162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Xilinx Event Management Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2021 Xilinx, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Abhyuday Godhasara <abhyuday.godhasara@xilinx.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/cpuhotplug.h>
1162306a36Sopenharmony_ci#include <linux/firmware/xlnx-event-manager.h>
1262306a36Sopenharmony_ci#include <linux/firmware/xlnx-zynqmp.h>
1362306a36Sopenharmony_ci#include <linux/hashtable.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/irq.h>
1662306a36Sopenharmony_ci#include <linux/irqdomain.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/of_irq.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number1);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int virq_sgi;
2562306a36Sopenharmony_cistatic int event_manager_availability = -EACCES;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* SGI number used for Event management driver */
2862306a36Sopenharmony_ci#define XLNX_EVENT_SGI_NUM	(15)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Max number of driver can register for same event */
3162306a36Sopenharmony_ci#define MAX_DRIVER_PER_EVENT	(10U)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Max HashMap Order for PM API feature check (1<<7 = 128) */
3462306a36Sopenharmony_ci#define REGISTERED_DRIVER_MAX_ORDER	(7)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define MAX_BITS	(32U) /* Number of bits available for error mask */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define FIRMWARE_VERSION_MASK			(0xFFFFU)
3962306a36Sopenharmony_ci#define REGISTER_NOTIFIER_FIRMWARE_VERSION	(2U)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER);
4262306a36Sopenharmony_cistatic int sgi_num = XLNX_EVENT_SGI_NUM;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic bool is_need_to_unregister;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/**
4762306a36Sopenharmony_ci * struct agent_cb - Registered callback function and private data.
4862306a36Sopenharmony_ci * @agent_data:		Data passed back to handler function.
4962306a36Sopenharmony_ci * @eve_cb:		Function pointer to store the callback function.
5062306a36Sopenharmony_ci * @list:		member to create list.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistruct agent_cb {
5362306a36Sopenharmony_ci	void *agent_data;
5462306a36Sopenharmony_ci	event_cb_func_t eve_cb;
5562306a36Sopenharmony_ci	struct list_head list;
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * struct registered_event_data - Registered Event Data.
6062306a36Sopenharmony_ci * @key:		key is the combine id(Node-Id | Event-Id) of type u64
6162306a36Sopenharmony_ci *			where upper u32 for Node-Id and lower u32 for Event-Id,
6262306a36Sopenharmony_ci *			And this used as key to index into hashmap.
6362306a36Sopenharmony_ci * @cb_type:		Type of Api callback, like PM_NOTIFY_CB, etc.
6462306a36Sopenharmony_ci * @wake:		If this flag set, firmware will wake up processor if is
6562306a36Sopenharmony_ci *			in sleep or power down state.
6662306a36Sopenharmony_ci * @cb_list_head:	Head of call back data list which contain the information
6762306a36Sopenharmony_ci *			about registered handler and private data.
6862306a36Sopenharmony_ci * @hentry:		hlist_node that hooks this entry into hashtable.
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistruct registered_event_data {
7162306a36Sopenharmony_ci	u64 key;
7262306a36Sopenharmony_ci	enum pm_api_cb_id cb_type;
7362306a36Sopenharmony_ci	bool wake;
7462306a36Sopenharmony_ci	struct list_head cb_list_head;
7562306a36Sopenharmony_ci	struct hlist_node hentry;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic bool xlnx_is_error_event(const u32 node_id)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	if (node_id == EVENT_ERROR_PMC_ERR1 ||
8162306a36Sopenharmony_ci	    node_id == EVENT_ERROR_PMC_ERR2 ||
8262306a36Sopenharmony_ci	    node_id == EVENT_ERROR_PSM_ERR1 ||
8362306a36Sopenharmony_ci	    node_id == EVENT_ERROR_PSM_ERR2)
8462306a36Sopenharmony_ci		return true;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return false;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, const bool wake,
9062306a36Sopenharmony_ci					event_cb_func_t cb_fun,	void *data)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	u64 key = 0;
9362306a36Sopenharmony_ci	bool present_in_hash = false;
9462306a36Sopenharmony_ci	struct registered_event_data *eve_data;
9562306a36Sopenharmony_ci	struct agent_cb *cb_data;
9662306a36Sopenharmony_ci	struct agent_cb *cb_pos;
9762306a36Sopenharmony_ci	struct agent_cb *cb_next;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	key = ((u64)node_id << 32U) | (u64)event;
10062306a36Sopenharmony_ci	/* Check for existing entry in hash table for given key id */
10162306a36Sopenharmony_ci	hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
10262306a36Sopenharmony_ci		if (eve_data->key == key) {
10362306a36Sopenharmony_ci			present_in_hash = true;
10462306a36Sopenharmony_ci			break;
10562306a36Sopenharmony_ci		}
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (!present_in_hash) {
10962306a36Sopenharmony_ci		/* Add new entry if not present in HASH table */
11062306a36Sopenharmony_ci		eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL);
11162306a36Sopenharmony_ci		if (!eve_data)
11262306a36Sopenharmony_ci			return -ENOMEM;
11362306a36Sopenharmony_ci		eve_data->key = key;
11462306a36Sopenharmony_ci		eve_data->cb_type = PM_NOTIFY_CB;
11562306a36Sopenharmony_ci		eve_data->wake = wake;
11662306a36Sopenharmony_ci		INIT_LIST_HEAD(&eve_data->cb_list_head);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
11962306a36Sopenharmony_ci		if (!cb_data) {
12062306a36Sopenharmony_ci			kfree(eve_data);
12162306a36Sopenharmony_ci			return -ENOMEM;
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci		cb_data->eve_cb = cb_fun;
12462306a36Sopenharmony_ci		cb_data->agent_data = data;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		/* Add into callback list */
12762306a36Sopenharmony_ci		list_add(&cb_data->list, &eve_data->cb_list_head);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		/* Add into HASH table */
13062306a36Sopenharmony_ci		hash_add(reg_driver_map, &eve_data->hentry, key);
13162306a36Sopenharmony_ci	} else {
13262306a36Sopenharmony_ci		/* Search for callback function and private data in list */
13362306a36Sopenharmony_ci		list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
13462306a36Sopenharmony_ci			if (cb_pos->eve_cb == cb_fun &&
13562306a36Sopenharmony_ci			    cb_pos->agent_data == data) {
13662306a36Sopenharmony_ci				return 0;
13762306a36Sopenharmony_ci			}
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		/* Add multiple handler and private data in list */
14162306a36Sopenharmony_ci		cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
14262306a36Sopenharmony_ci		if (!cb_data)
14362306a36Sopenharmony_ci			return -ENOMEM;
14462306a36Sopenharmony_ci		cb_data->eve_cb = cb_fun;
14562306a36Sopenharmony_ci		cb_data->agent_data = data;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		list_add(&cb_data->list, &eve_data->cb_list_head);
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return 0;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int xlnx_add_cb_for_suspend(event_cb_func_t cb_fun, void *data)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct registered_event_data *eve_data;
15662306a36Sopenharmony_ci	struct agent_cb *cb_data;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Check for existing entry in hash table for given cb_type */
15962306a36Sopenharmony_ci	hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
16062306a36Sopenharmony_ci		if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
16162306a36Sopenharmony_ci			pr_err("Found as already registered\n");
16262306a36Sopenharmony_ci			return -EINVAL;
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Add new entry if not present */
16762306a36Sopenharmony_ci	eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL);
16862306a36Sopenharmony_ci	if (!eve_data)
16962306a36Sopenharmony_ci		return -ENOMEM;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	eve_data->key = 0;
17262306a36Sopenharmony_ci	eve_data->cb_type = PM_INIT_SUSPEND_CB;
17362306a36Sopenharmony_ci	INIT_LIST_HEAD(&eve_data->cb_list_head);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
17662306a36Sopenharmony_ci	if (!cb_data)
17762306a36Sopenharmony_ci		return -ENOMEM;
17862306a36Sopenharmony_ci	cb_data->eve_cb = cb_fun;
17962306a36Sopenharmony_ci	cb_data->agent_data = data;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Add into callback list */
18262306a36Sopenharmony_ci	list_add(&cb_data->list, &eve_data->cb_list_head);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	hash_add(reg_driver_map, &eve_data->hentry, PM_INIT_SUSPEND_CB);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	bool is_callback_found = false;
19262306a36Sopenharmony_ci	struct registered_event_data *eve_data;
19362306a36Sopenharmony_ci	struct agent_cb *cb_pos;
19462306a36Sopenharmony_ci	struct agent_cb *cb_next;
19562306a36Sopenharmony_ci	struct hlist_node *tmp;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	is_need_to_unregister = false;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Check for existing entry in hash table for given cb_type */
20062306a36Sopenharmony_ci	hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, PM_INIT_SUSPEND_CB) {
20162306a36Sopenharmony_ci		if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
20262306a36Sopenharmony_ci			/* Delete the list of callback */
20362306a36Sopenharmony_ci			list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
20462306a36Sopenharmony_ci				if (cb_pos->eve_cb == cb_fun) {
20562306a36Sopenharmony_ci					is_callback_found = true;
20662306a36Sopenharmony_ci					list_del_init(&cb_pos->list);
20762306a36Sopenharmony_ci					kfree(cb_pos);
20862306a36Sopenharmony_ci				}
20962306a36Sopenharmony_ci			}
21062306a36Sopenharmony_ci			/* remove an object from a hashtable */
21162306a36Sopenharmony_ci			hash_del(&eve_data->hentry);
21262306a36Sopenharmony_ci			kfree(eve_data);
21362306a36Sopenharmony_ci			is_need_to_unregister = true;
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci	if (!is_callback_found) {
21762306a36Sopenharmony_ci		pr_warn("Didn't find any registered callback for suspend event\n");
21862306a36Sopenharmony_ci		return -EINVAL;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return 0;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
22562306a36Sopenharmony_ci					   event_cb_func_t cb_fun, void *data)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	bool is_callback_found = false;
22862306a36Sopenharmony_ci	struct registered_event_data *eve_data;
22962306a36Sopenharmony_ci	u64 key = ((u64)node_id << 32U) | (u64)event;
23062306a36Sopenharmony_ci	struct agent_cb *cb_pos;
23162306a36Sopenharmony_ci	struct agent_cb *cb_next;
23262306a36Sopenharmony_ci	struct hlist_node *tmp;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	is_need_to_unregister = false;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* Check for existing entry in hash table for given key id */
23762306a36Sopenharmony_ci	hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, key) {
23862306a36Sopenharmony_ci		if (eve_data->key == key) {
23962306a36Sopenharmony_ci			/* Delete the list of callback */
24062306a36Sopenharmony_ci			list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
24162306a36Sopenharmony_ci				if (cb_pos->eve_cb == cb_fun &&
24262306a36Sopenharmony_ci				    cb_pos->agent_data == data) {
24362306a36Sopenharmony_ci					is_callback_found = true;
24462306a36Sopenharmony_ci					list_del_init(&cb_pos->list);
24562306a36Sopenharmony_ci					kfree(cb_pos);
24662306a36Sopenharmony_ci				}
24762306a36Sopenharmony_ci			}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci			/* Remove HASH table if callback list is empty */
25062306a36Sopenharmony_ci			if (list_empty(&eve_data->cb_list_head)) {
25162306a36Sopenharmony_ci				/* remove an object from a HASH table */
25262306a36Sopenharmony_ci				hash_del(&eve_data->hentry);
25362306a36Sopenharmony_ci				kfree(eve_data);
25462306a36Sopenharmony_ci				is_need_to_unregister = true;
25562306a36Sopenharmony_ci			}
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci	if (!is_callback_found) {
25962306a36Sopenharmony_ci		pr_warn("Didn't find any registered callback for 0x%x 0x%x\n",
26062306a36Sopenharmony_ci			node_id, event);
26162306a36Sopenharmony_ci		return -EINVAL;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/**
26862306a36Sopenharmony_ci * xlnx_register_event() - Register for the event.
26962306a36Sopenharmony_ci * @cb_type:	Type of callback from pm_api_cb_id,
27062306a36Sopenharmony_ci *			PM_NOTIFY_CB - for Error Events,
27162306a36Sopenharmony_ci *			PM_INIT_SUSPEND_CB - for suspend callback.
27262306a36Sopenharmony_ci * @node_id:	Node-Id related to event.
27362306a36Sopenharmony_ci * @event:	Event Mask for the Error Event.
27462306a36Sopenharmony_ci * @wake:	Flag specifying whether the subsystem should be woken upon
27562306a36Sopenharmony_ci *		event notification.
27662306a36Sopenharmony_ci * @cb_fun:	Function pointer to store the callback function.
27762306a36Sopenharmony_ci * @data:	Pointer for the driver instance.
27862306a36Sopenharmony_ci *
27962306a36Sopenharmony_ci * Return:	Returns 0 on successful registration else error code.
28062306a36Sopenharmony_ci */
28162306a36Sopenharmony_ciint xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
28262306a36Sopenharmony_ci			const bool wake, event_cb_func_t cb_fun, void *data)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	int ret = 0;
28562306a36Sopenharmony_ci	u32 eve;
28662306a36Sopenharmony_ci	int pos;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (event_manager_availability)
28962306a36Sopenharmony_ci		return event_manager_availability;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (cb_type != PM_NOTIFY_CB && cb_type != PM_INIT_SUSPEND_CB) {
29262306a36Sopenharmony_ci		pr_err("%s() Unsupported Callback 0x%x\n", __func__, cb_type);
29362306a36Sopenharmony_ci		return -EINVAL;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (!cb_fun)
29762306a36Sopenharmony_ci		return -EFAULT;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (cb_type == PM_INIT_SUSPEND_CB) {
30062306a36Sopenharmony_ci		ret = xlnx_add_cb_for_suspend(cb_fun, data);
30162306a36Sopenharmony_ci	} else {
30262306a36Sopenharmony_ci		if (!xlnx_is_error_event(node_id)) {
30362306a36Sopenharmony_ci			/* Add entry for Node-Id/Event in hash table */
30462306a36Sopenharmony_ci			ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data);
30562306a36Sopenharmony_ci		} else {
30662306a36Sopenharmony_ci			/* Add into Hash table */
30762306a36Sopenharmony_ci			for (pos = 0; pos < MAX_BITS; pos++) {
30862306a36Sopenharmony_ci				eve = event & (1 << pos);
30962306a36Sopenharmony_ci				if (!eve)
31062306a36Sopenharmony_ci					continue;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci				/* Add entry for Node-Id/Eve in hash table */
31362306a36Sopenharmony_ci				ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun,
31462306a36Sopenharmony_ci								   data);
31562306a36Sopenharmony_ci				/* Break the loop if got error */
31662306a36Sopenharmony_ci				if (ret)
31762306a36Sopenharmony_ci					break;
31862306a36Sopenharmony_ci			}
31962306a36Sopenharmony_ci			if (ret) {
32062306a36Sopenharmony_ci				/* Skip the Event for which got the error */
32162306a36Sopenharmony_ci				pos--;
32262306a36Sopenharmony_ci				/* Remove registered(during this call) event from hash table */
32362306a36Sopenharmony_ci				for ( ; pos >= 0; pos--) {
32462306a36Sopenharmony_ci					eve = event & (1 << pos);
32562306a36Sopenharmony_ci					if (!eve)
32662306a36Sopenharmony_ci						continue;
32762306a36Sopenharmony_ci					xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
32862306a36Sopenharmony_ci				}
32962306a36Sopenharmony_ci			}
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		if (ret) {
33362306a36Sopenharmony_ci			pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
33462306a36Sopenharmony_ci			       event, ret);
33562306a36Sopenharmony_ci			return ret;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		/* Register for Node-Id/Event combination in firmware */
33962306a36Sopenharmony_ci		ret = zynqmp_pm_register_notifier(node_id, event, wake, true);
34062306a36Sopenharmony_ci		if (ret) {
34162306a36Sopenharmony_ci			pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
34262306a36Sopenharmony_ci			       event, ret);
34362306a36Sopenharmony_ci			/* Remove already registered event from hash table */
34462306a36Sopenharmony_ci			if (xlnx_is_error_event(node_id)) {
34562306a36Sopenharmony_ci				for (pos = 0; pos < MAX_BITS; pos++) {
34662306a36Sopenharmony_ci					eve = event & (1 << pos);
34762306a36Sopenharmony_ci					if (!eve)
34862306a36Sopenharmony_ci						continue;
34962306a36Sopenharmony_ci					xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
35062306a36Sopenharmony_ci				}
35162306a36Sopenharmony_ci			} else {
35262306a36Sopenharmony_ci				xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
35362306a36Sopenharmony_ci			}
35462306a36Sopenharmony_ci			return ret;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return ret;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xlnx_register_event);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/**
36362306a36Sopenharmony_ci * xlnx_unregister_event() - Unregister for the event.
36462306a36Sopenharmony_ci * @cb_type:	Type of callback from pm_api_cb_id,
36562306a36Sopenharmony_ci *			PM_NOTIFY_CB - for Error Events,
36662306a36Sopenharmony_ci *			PM_INIT_SUSPEND_CB - for suspend callback.
36762306a36Sopenharmony_ci * @node_id:	Node-Id related to event.
36862306a36Sopenharmony_ci * @event:	Event Mask for the Error Event.
36962306a36Sopenharmony_ci * @cb_fun:	Function pointer of callback function.
37062306a36Sopenharmony_ci * @data:	Pointer of agent's private data.
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Return:	Returns 0 on successful unregistration else error code.
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_ciint xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
37562306a36Sopenharmony_ci			  event_cb_func_t cb_fun, void *data)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	int ret = 0;
37862306a36Sopenharmony_ci	u32 eve, pos;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	is_need_to_unregister = false;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (event_manager_availability)
38362306a36Sopenharmony_ci		return event_manager_availability;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (cb_type != PM_NOTIFY_CB && cb_type != PM_INIT_SUSPEND_CB) {
38662306a36Sopenharmony_ci		pr_err("%s() Unsupported Callback 0x%x\n", __func__, cb_type);
38762306a36Sopenharmony_ci		return -EINVAL;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (!cb_fun)
39162306a36Sopenharmony_ci		return -EFAULT;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (cb_type == PM_INIT_SUSPEND_CB) {
39462306a36Sopenharmony_ci		ret = xlnx_remove_cb_for_suspend(cb_fun);
39562306a36Sopenharmony_ci	} else {
39662306a36Sopenharmony_ci		/* Remove Node-Id/Event from hash table */
39762306a36Sopenharmony_ci		if (!xlnx_is_error_event(node_id)) {
39862306a36Sopenharmony_ci			xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
39962306a36Sopenharmony_ci		} else {
40062306a36Sopenharmony_ci			for (pos = 0; pos < MAX_BITS; pos++) {
40162306a36Sopenharmony_ci				eve = event & (1 << pos);
40262306a36Sopenharmony_ci				if (!eve)
40362306a36Sopenharmony_ci					continue;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci				xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
40662306a36Sopenharmony_ci			}
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		/* Un-register if list is empty */
41062306a36Sopenharmony_ci		if (is_need_to_unregister) {
41162306a36Sopenharmony_ci			/* Un-register for Node-Id/Event combination */
41262306a36Sopenharmony_ci			ret = zynqmp_pm_register_notifier(node_id, event, false, false);
41362306a36Sopenharmony_ci			if (ret) {
41462306a36Sopenharmony_ci				pr_err("%s() failed for 0x%x and 0x%x: %d\n",
41562306a36Sopenharmony_ci				       __func__, node_id, event, ret);
41662306a36Sopenharmony_ci				return ret;
41762306a36Sopenharmony_ci			}
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return ret;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xlnx_unregister_event);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void xlnx_call_suspend_cb_handler(const u32 *payload)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	bool is_callback_found = false;
42862306a36Sopenharmony_ci	struct registered_event_data *eve_data;
42962306a36Sopenharmony_ci	u32 cb_type = payload[0];
43062306a36Sopenharmony_ci	struct agent_cb *cb_pos;
43162306a36Sopenharmony_ci	struct agent_cb *cb_next;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* Check for existing entry in hash table for given cb_type */
43462306a36Sopenharmony_ci	hash_for_each_possible(reg_driver_map, eve_data, hentry, cb_type) {
43562306a36Sopenharmony_ci		if (eve_data->cb_type == cb_type) {
43662306a36Sopenharmony_ci			list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
43762306a36Sopenharmony_ci				cb_pos->eve_cb(&payload[0], cb_pos->agent_data);
43862306a36Sopenharmony_ci				is_callback_found = true;
43962306a36Sopenharmony_ci			}
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	if (!is_callback_found)
44362306a36Sopenharmony_ci		pr_warn("Didn't find any registered callback for suspend event\n");
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic void xlnx_call_notify_cb_handler(const u32 *payload)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	bool is_callback_found = false;
44962306a36Sopenharmony_ci	struct registered_event_data *eve_data;
45062306a36Sopenharmony_ci	u64 key = ((u64)payload[1] << 32U) | (u64)payload[2];
45162306a36Sopenharmony_ci	int ret;
45262306a36Sopenharmony_ci	struct agent_cb *cb_pos;
45362306a36Sopenharmony_ci	struct agent_cb *cb_next;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* Check for existing entry in hash table for given key id */
45662306a36Sopenharmony_ci	hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
45762306a36Sopenharmony_ci		if (eve_data->key == key) {
45862306a36Sopenharmony_ci			list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
45962306a36Sopenharmony_ci				cb_pos->eve_cb(&payload[0], cb_pos->agent_data);
46062306a36Sopenharmony_ci				is_callback_found = true;
46162306a36Sopenharmony_ci			}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci			/* re register with firmware to get future events */
46462306a36Sopenharmony_ci			ret = zynqmp_pm_register_notifier(payload[1], payload[2],
46562306a36Sopenharmony_ci							  eve_data->wake, true);
46662306a36Sopenharmony_ci			if (ret) {
46762306a36Sopenharmony_ci				pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__,
46862306a36Sopenharmony_ci				       payload[1], payload[2], ret);
46962306a36Sopenharmony_ci				list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head,
47062306a36Sopenharmony_ci							 list) {
47162306a36Sopenharmony_ci					/* Remove already registered event from hash table */
47262306a36Sopenharmony_ci					xlnx_remove_cb_for_notify_event(payload[1], payload[2],
47362306a36Sopenharmony_ci									cb_pos->eve_cb,
47462306a36Sopenharmony_ci									cb_pos->agent_data);
47562306a36Sopenharmony_ci				}
47662306a36Sopenharmony_ci			}
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	if (!is_callback_found)
48062306a36Sopenharmony_ci		pr_warn("Unhandled SGI node 0x%x event 0x%x. Expected with Xen hypervisor\n",
48162306a36Sopenharmony_ci			payload[1], payload[2]);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic void xlnx_get_event_callback_data(u32 *buf)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic irqreturn_t xlnx_event_handler(int irq, void *dev_id)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	u32 cb_type, node_id, event, pos;
49262306a36Sopenharmony_ci	u32 payload[CB_MAX_PAYLOAD_SIZE] = {0};
49362306a36Sopenharmony_ci	u32 event_data[CB_MAX_PAYLOAD_SIZE] = {0};
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Get event data */
49662306a36Sopenharmony_ci	xlnx_get_event_callback_data(payload);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* First element is callback type, others are callback arguments */
49962306a36Sopenharmony_ci	cb_type = payload[0];
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (cb_type == PM_NOTIFY_CB) {
50262306a36Sopenharmony_ci		node_id = payload[1];
50362306a36Sopenharmony_ci		event = payload[2];
50462306a36Sopenharmony_ci		if (!xlnx_is_error_event(node_id)) {
50562306a36Sopenharmony_ci			xlnx_call_notify_cb_handler(payload);
50662306a36Sopenharmony_ci		} else {
50762306a36Sopenharmony_ci			/*
50862306a36Sopenharmony_ci			 * Each call back function expecting payload as an input arguments.
50962306a36Sopenharmony_ci			 * We can get multiple error events as in one call back through error
51062306a36Sopenharmony_ci			 * mask. So payload[2] may can contain multiple error events.
51162306a36Sopenharmony_ci			 * In reg_driver_map database we store data in the combination of single
51262306a36Sopenharmony_ci			 * node_id-error combination.
51362306a36Sopenharmony_ci			 * So coping the payload message into event_data and update the
51462306a36Sopenharmony_ci			 * event_data[2] with Error Mask for single error event and use
51562306a36Sopenharmony_ci			 * event_data as input argument for registered call back function.
51662306a36Sopenharmony_ci			 *
51762306a36Sopenharmony_ci			 */
51862306a36Sopenharmony_ci			memcpy(event_data, payload, (4 * CB_MAX_PAYLOAD_SIZE));
51962306a36Sopenharmony_ci			/* Support Multiple Error Event */
52062306a36Sopenharmony_ci			for (pos = 0; pos < MAX_BITS; pos++) {
52162306a36Sopenharmony_ci				if ((0 == (event & (1 << pos))))
52262306a36Sopenharmony_ci					continue;
52362306a36Sopenharmony_ci				event_data[2] = (event & (1 << pos));
52462306a36Sopenharmony_ci				xlnx_call_notify_cb_handler(event_data);
52562306a36Sopenharmony_ci			}
52662306a36Sopenharmony_ci		}
52762306a36Sopenharmony_ci	} else if (cb_type == PM_INIT_SUSPEND_CB) {
52862306a36Sopenharmony_ci		xlnx_call_suspend_cb_handler(payload);
52962306a36Sopenharmony_ci	} else {
53062306a36Sopenharmony_ci		pr_err("%s() Unsupported Callback %d\n", __func__, cb_type);
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return IRQ_HANDLED;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic int xlnx_event_cpuhp_start(unsigned int cpu)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	enable_percpu_irq(virq_sgi, IRQ_TYPE_NONE);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return 0;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int xlnx_event_cpuhp_down(unsigned int cpu)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	disable_percpu_irq(virq_sgi);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return 0;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic void xlnx_disable_percpu_irq(void *data)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	disable_percpu_irq(virq_sgi);
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic int xlnx_event_init_sgi(struct platform_device *pdev)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	int ret = 0;
55862306a36Sopenharmony_ci	int cpu;
55962306a36Sopenharmony_ci	/*
56062306a36Sopenharmony_ci	 * IRQ related structures are used for the following:
56162306a36Sopenharmony_ci	 * for each SGI interrupt ensure its mapped by GIC IRQ domain
56262306a36Sopenharmony_ci	 * and that each corresponding linux IRQ for the HW IRQ has
56362306a36Sopenharmony_ci	 * a handler for when receiving an interrupt from the remote
56462306a36Sopenharmony_ci	 * processor.
56562306a36Sopenharmony_ci	 */
56662306a36Sopenharmony_ci	struct irq_domain *domain;
56762306a36Sopenharmony_ci	struct irq_fwspec sgi_fwspec;
56862306a36Sopenharmony_ci	struct device_node *interrupt_parent = NULL;
56962306a36Sopenharmony_ci	struct device *parent = pdev->dev.parent;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* Find GIC controller to map SGIs. */
57262306a36Sopenharmony_ci	interrupt_parent = of_irq_find_parent(parent->of_node);
57362306a36Sopenharmony_ci	if (!interrupt_parent) {
57462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to find property for Interrupt parent\n");
57562306a36Sopenharmony_ci		return -EINVAL;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* Each SGI needs to be associated with GIC's IRQ domain. */
57962306a36Sopenharmony_ci	domain = irq_find_host(interrupt_parent);
58062306a36Sopenharmony_ci	of_node_put(interrupt_parent);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* Each mapping needs GIC domain when finding IRQ mapping. */
58362306a36Sopenharmony_ci	sgi_fwspec.fwnode = domain->fwnode;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/*
58662306a36Sopenharmony_ci	 * When irq domain looks at mapping each arg is as follows:
58762306a36Sopenharmony_ci	 * 3 args for: interrupt type (SGI), interrupt # (set later), type
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	sgi_fwspec.param_count = 1;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* Set SGI's hwirq */
59262306a36Sopenharmony_ci	sgi_fwspec.param[0] = sgi_num;
59362306a36Sopenharmony_ci	virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	cpu = get_cpu();
59662306a36Sopenharmony_ci	per_cpu(cpu_number1, cpu) = cpu;
59762306a36Sopenharmony_ci	ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt",
59862306a36Sopenharmony_ci				 &cpu_number1);
59962306a36Sopenharmony_ci	put_cpu();
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	WARN_ON(ret);
60262306a36Sopenharmony_ci	if (ret) {
60362306a36Sopenharmony_ci		irq_dispose_mapping(virq_sgi);
60462306a36Sopenharmony_ci		return ret;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	irq_to_desc(virq_sgi);
60862306a36Sopenharmony_ci	irq_set_status_flags(virq_sgi, IRQ_PER_CPU);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	return ret;
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic void xlnx_event_cleanup_sgi(struct platform_device *pdev)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	int cpu = smp_processor_id();
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	per_cpu(cpu_number1, cpu) = cpu;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	cpuhp_remove_state(CPUHP_AP_ONLINE_DYN);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	on_each_cpu(xlnx_disable_percpu_irq, NULL, 1);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	irq_clear_status_flags(virq_sgi, IRQ_PER_CPU);
62462306a36Sopenharmony_ci	free_percpu_irq(virq_sgi, &cpu_number1);
62562306a36Sopenharmony_ci	irq_dispose_mapping(virq_sgi);
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic int xlnx_event_manager_probe(struct platform_device *pdev)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	int ret;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	ret = zynqmp_pm_feature(PM_REGISTER_NOTIFIER);
63362306a36Sopenharmony_ci	if (ret < 0) {
63462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Feature check failed with %d\n", ret);
63562306a36Sopenharmony_ci		return ret;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if ((ret & FIRMWARE_VERSION_MASK) <
63962306a36Sopenharmony_ci	    REGISTER_NOTIFIER_FIRMWARE_VERSION) {
64062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n",
64162306a36Sopenharmony_ci			REGISTER_NOTIFIER_FIRMWARE_VERSION,
64262306a36Sopenharmony_ci			ret & FIRMWARE_VERSION_MASK);
64362306a36Sopenharmony_ci		return -EOPNOTSUPP;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* Initialize the SGI */
64762306a36Sopenharmony_ci	ret = xlnx_event_init_sgi(pdev);
64862306a36Sopenharmony_ci	if (ret) {
64962306a36Sopenharmony_ci		dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret);
65062306a36Sopenharmony_ci		return ret;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* Setup function for the CPU hot-plug cases */
65462306a36Sopenharmony_ci	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/event:starting",
65562306a36Sopenharmony_ci			  xlnx_event_cpuhp_start, xlnx_event_cpuhp_down);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	ret = zynqmp_pm_register_sgi(sgi_num, 0);
65862306a36Sopenharmony_ci	if (ret) {
65962306a36Sopenharmony_ci		dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret);
66062306a36Sopenharmony_ci		xlnx_event_cleanup_sgi(pdev);
66162306a36Sopenharmony_ci		return ret;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	event_manager_availability = 0;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	dev_info(&pdev->dev, "SGI %d Registered over TF-A\n", sgi_num);
66762306a36Sopenharmony_ci	dev_info(&pdev->dev, "Xilinx Event Management driver probed\n");
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	return ret;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic void xlnx_event_manager_remove(struct platform_device *pdev)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	int i;
67562306a36Sopenharmony_ci	struct registered_event_data *eve_data;
67662306a36Sopenharmony_ci	struct hlist_node *tmp;
67762306a36Sopenharmony_ci	int ret;
67862306a36Sopenharmony_ci	struct agent_cb *cb_pos;
67962306a36Sopenharmony_ci	struct agent_cb *cb_next;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	hash_for_each_safe(reg_driver_map, i, tmp, eve_data, hentry) {
68262306a36Sopenharmony_ci		list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
68362306a36Sopenharmony_ci			list_del_init(&cb_pos->list);
68462306a36Sopenharmony_ci			kfree(cb_pos);
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci		hash_del(&eve_data->hentry);
68762306a36Sopenharmony_ci		kfree(eve_data);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	ret = zynqmp_pm_register_sgi(0, 1);
69162306a36Sopenharmony_ci	if (ret)
69262306a36Sopenharmony_ci		dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	xlnx_event_cleanup_sgi(pdev);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	event_manager_availability = -EACCES;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic struct platform_driver xlnx_event_manager_driver = {
70062306a36Sopenharmony_ci	.probe = xlnx_event_manager_probe,
70162306a36Sopenharmony_ci	.remove_new = xlnx_event_manager_remove,
70262306a36Sopenharmony_ci	.driver = {
70362306a36Sopenharmony_ci		.name = "xlnx_event_manager",
70462306a36Sopenharmony_ci	},
70562306a36Sopenharmony_ci};
70662306a36Sopenharmony_cimodule_param(sgi_num, uint, 0);
70762306a36Sopenharmony_cimodule_platform_driver(xlnx_event_manager_driver);
708