Loading drivers/gpu/drm/msm/sde_power_handle.c +105 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,17 @@ #include "sde_power_handle.h" #include "sde_trace.h" static void sde_power_event_trigger_locked(struct sde_power_handle *phandle, u32 event_type) { struct sde_power_event *event; list_for_each_entry(event, &phandle->event_list, list) { if (event->event_type & event_type) event->cb_fnc(event_type, event->usr); } } struct sde_power_client *sde_power_client_create( struct sde_power_handle *phandle, char *client_name) { Loading @@ -48,6 +59,7 @@ struct sde_power_client *sde_power_client_create( strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); client->usecase_ndx = VOTE_INDEX_DISABLE; client->id = id; client->active = true; pr_debug("client %s created:%pK id :%d\n", client_name, client, id); id++; Loading @@ -62,6 +74,9 @@ void sde_power_client_destroy(struct sde_power_handle *phandle, { if (!client || !phandle) { pr_err("reg bus vote: invalid client handle\n"); } else if (!client->active) { pr_err("sde power deinit already done\n"); kfree(client); } else { pr_debug("bus vote client %s destroyed:%pK id:%u\n", client->name, client, client->id); Loading Loading @@ -661,6 +676,8 @@ int sde_power_resource_init(struct platform_device *pdev, } INIT_LIST_HEAD(&phandle->power_client_clist); INIT_LIST_HEAD(&phandle->event_list); mutex_init(&phandle->phandle_lock); return rc; Loading @@ -672,9 +689,11 @@ int sde_power_resource_init(struct platform_device *pdev, clk_err: msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0); vreg_err: if (mp->vreg_config) devm_kfree(&pdev->dev, mp->vreg_config); mp->num_vreg = 0; parse_vreg_err: if (mp->clk_config) devm_kfree(&pdev->dev, mp->clk_config); mp->num_clk = 0; end: Loading @@ -685,6 +704,8 @@ void sde_power_resource_deinit(struct platform_device *pdev, struct sde_power_handle *phandle) { struct dss_module_power *mp; struct sde_power_client *curr_client, *next_client; struct sde_power_event *curr_event, *next_event; if (!phandle || !pdev) { pr_err("invalid input param\n"); Loading @@ -692,6 +713,26 @@ void sde_power_resource_deinit(struct platform_device *pdev, } mp = &phandle->mp; mutex_lock(&phandle->phandle_lock); list_for_each_entry_safe(curr_client, next_client, &phandle->power_client_clist, list) { pr_err("cliend:%s-%d still registered with refcount:%d\n", curr_client->name, curr_client->id, curr_client->refcount); curr_client->active = false; list_del(&curr_client->list); } list_for_each_entry_safe(curr_event, next_event, &phandle->event_list, list) { pr_err("event:%d, client:%s still registered\n", curr_event->event_type, curr_event->client_name); curr_event->active = false; list_del(&curr_event->list); } mutex_unlock(&phandle->phandle_lock); sde_power_data_bus_unregister(&phandle->data_bus_handle); sde_power_reg_bus_unregister(phandle->reg_bus_hdl); Loading Loading @@ -757,6 +798,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, goto end; if (enable) { sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_PRE_ENABLE); rc = sde_power_data_bus_update(&phandle->data_bus_handle, enable); if (rc) { Loading @@ -782,7 +826,14 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, pr_err("clock enable failed rc:%d\n", rc); goto clk_err; } sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_POST_ENABLE); } else { sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_PRE_DISABLE); msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); sde_power_reg_bus_update(phandle->reg_bus_hdl, Loading @@ -791,6 +842,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); sde_power_data_bus_update(&phandle->data_bus_handle, enable); sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_POST_DISABLE); } end: Loading Loading @@ -903,3 +957,52 @@ struct clk *sde_power_clk_get_clk(struct sde_power_handle *phandle, return clk; } struct sde_power_event *sde_power_handle_register_event( struct sde_power_handle *phandle, u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), void *usr, char *client_name) { struct sde_power_event *event; if (!phandle) { pr_err("invalid power handle\n"); return ERR_PTR(-EINVAL); } else if (!cb_fnc || !event_type) { pr_err("no callback fnc or event type\n"); return ERR_PTR(-EINVAL); } event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL); if (!event) return ERR_PTR(-ENOMEM); event->event_type = event_type; event->cb_fnc = cb_fnc; event->usr = usr; strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); event->active = true; mutex_lock(&phandle->phandle_lock); list_add(&event->list, &phandle->event_list); mutex_unlock(&phandle->phandle_lock); return event; } void sde_power_handle_unregister_event( struct sde_power_handle *phandle, struct sde_power_event *event) { if (!phandle || !event) { pr_err("invalid phandle or event\n"); } else if (!event->active) { pr_err("power handle deinit already done\n"); kfree(event); } else { mutex_lock(&phandle->phandle_lock); list_del_init(&event->list); mutex_unlock(&phandle->phandle_lock); kfree(event); } } drivers/gpu/drm/msm/sde_power_handle.h +58 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,18 @@ #include <linux/sde_io_util.h> /* event will be triggered before power handler disable */ #define SDE_POWER_EVENT_PRE_DISABLE 0x1 /* event will be triggered after power handler disable */ #define SDE_POWER_EVENT_POST_DISABLE 0x2 /* event will be triggered before power handler enable */ #define SDE_POWER_EVENT_PRE_ENABLE 0x4 /* event will be triggered after power handler enable */ #define SDE_POWER_EVENT_POST_ENABLE 0x8 /** * mdss_bus_vote_type: register bus vote type * VOTE_INDEX_DISABLE: removes the client vote Loading Loading @@ -59,6 +71,7 @@ enum sde_power_handle_data_bus_client { * @list: list to attach power handle master list * @ab: arbitrated bandwidth for each bus client * @ib: instantaneous bandwidth for each bus client * @active: inidcates the state of sde power handle */ struct sde_power_client { char name[MAX_CLIENT_NAME_LEN]; Loading @@ -68,6 +81,7 @@ struct sde_power_client { struct list_head list; u64 ab[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; u64 ib[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; bool active; }; /** Loading @@ -90,6 +104,24 @@ struct sde_power_data_bus_handle { u32 ao_bw_uc_idx; }; /* * struct sde_power_event - local event registration structure * @client_name: name of the client registering * @cb_fnc: pointer to desired callback function * @usr: user pointer to pass to callback event trigger * @event: refer to SDE_POWER_HANDLE_EVENT_* * @list: list to attach event master list * @active: indicates the state of sde power handle */ struct sde_power_event { char client_name[MAX_CLIENT_NAME_LEN]; void (*cb_fnc)(u32 event_type, void *usr); void *usr; u32 event_type; struct list_head list; bool active; }; /** * struct sde_power_handle: power handle main struct * @mp: module power for clock and regulator Loading @@ -99,6 +131,7 @@ struct sde_power_data_bus_handle { * @usecase_ndx: current usecase index * @reg_bus_hdl: current register bus handle * @data_bus_handle: context structure for data bus control * @event_list: current power handle event list */ struct sde_power_handle { struct dss_module_power mp; Loading @@ -108,6 +141,7 @@ struct sde_power_handle { u32 current_usecase_ndx; u32 reg_bus_hdl; struct sde_power_data_bus_handle data_bus_handle; struct list_head event_list; }; /** Loading Loading @@ -226,4 +260,28 @@ int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, void sde_power_data_bus_bandwidth_ctrl(struct sde_power_handle *phandle, struct sde_power_client *pclient, int enable); /** * sde_power_handle_register_event - register a callback function for an event. * Clients can register for multiple events with a single register. * Any block with access to phandle can register for the event * notification. * @phandle: power handle containing the resources * @event_type: event type to register; refer SDE_POWER_HANDLE_EVENT_* * @cb_fnc: pointer to desired callback function * @usr: user pointer to pass to callback on event trigger * * Return: event pointer if success, or error code otherwise */ struct sde_power_event *sde_power_handle_register_event( struct sde_power_handle *phandle, u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), void *usr, char *client_name); /** * sde_power_handle_unregister_event - unregister callback for event(s) * @phandle: power handle containing the resources * @event: event pointer returned after power handle register */ void sde_power_handle_unregister_event(struct sde_power_handle *phandle, struct sde_power_event *event); #endif /* _SDE_POWER_HANDLE_H_ */ Loading
drivers/gpu/drm/msm/sde_power_handle.c +105 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,17 @@ #include "sde_power_handle.h" #include "sde_trace.h" static void sde_power_event_trigger_locked(struct sde_power_handle *phandle, u32 event_type) { struct sde_power_event *event; list_for_each_entry(event, &phandle->event_list, list) { if (event->event_type & event_type) event->cb_fnc(event_type, event->usr); } } struct sde_power_client *sde_power_client_create( struct sde_power_handle *phandle, char *client_name) { Loading @@ -48,6 +59,7 @@ struct sde_power_client *sde_power_client_create( strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); client->usecase_ndx = VOTE_INDEX_DISABLE; client->id = id; client->active = true; pr_debug("client %s created:%pK id :%d\n", client_name, client, id); id++; Loading @@ -62,6 +74,9 @@ void sde_power_client_destroy(struct sde_power_handle *phandle, { if (!client || !phandle) { pr_err("reg bus vote: invalid client handle\n"); } else if (!client->active) { pr_err("sde power deinit already done\n"); kfree(client); } else { pr_debug("bus vote client %s destroyed:%pK id:%u\n", client->name, client, client->id); Loading Loading @@ -661,6 +676,8 @@ int sde_power_resource_init(struct platform_device *pdev, } INIT_LIST_HEAD(&phandle->power_client_clist); INIT_LIST_HEAD(&phandle->event_list); mutex_init(&phandle->phandle_lock); return rc; Loading @@ -672,9 +689,11 @@ int sde_power_resource_init(struct platform_device *pdev, clk_err: msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0); vreg_err: if (mp->vreg_config) devm_kfree(&pdev->dev, mp->vreg_config); mp->num_vreg = 0; parse_vreg_err: if (mp->clk_config) devm_kfree(&pdev->dev, mp->clk_config); mp->num_clk = 0; end: Loading @@ -685,6 +704,8 @@ void sde_power_resource_deinit(struct platform_device *pdev, struct sde_power_handle *phandle) { struct dss_module_power *mp; struct sde_power_client *curr_client, *next_client; struct sde_power_event *curr_event, *next_event; if (!phandle || !pdev) { pr_err("invalid input param\n"); Loading @@ -692,6 +713,26 @@ void sde_power_resource_deinit(struct platform_device *pdev, } mp = &phandle->mp; mutex_lock(&phandle->phandle_lock); list_for_each_entry_safe(curr_client, next_client, &phandle->power_client_clist, list) { pr_err("cliend:%s-%d still registered with refcount:%d\n", curr_client->name, curr_client->id, curr_client->refcount); curr_client->active = false; list_del(&curr_client->list); } list_for_each_entry_safe(curr_event, next_event, &phandle->event_list, list) { pr_err("event:%d, client:%s still registered\n", curr_event->event_type, curr_event->client_name); curr_event->active = false; list_del(&curr_event->list); } mutex_unlock(&phandle->phandle_lock); sde_power_data_bus_unregister(&phandle->data_bus_handle); sde_power_reg_bus_unregister(phandle->reg_bus_hdl); Loading Loading @@ -757,6 +798,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, goto end; if (enable) { sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_PRE_ENABLE); rc = sde_power_data_bus_update(&phandle->data_bus_handle, enable); if (rc) { Loading @@ -782,7 +826,14 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, pr_err("clock enable failed rc:%d\n", rc); goto clk_err; } sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_POST_ENABLE); } else { sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_PRE_DISABLE); msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); sde_power_reg_bus_update(phandle->reg_bus_hdl, Loading @@ -791,6 +842,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); sde_power_data_bus_update(&phandle->data_bus_handle, enable); sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_POST_DISABLE); } end: Loading Loading @@ -903,3 +957,52 @@ struct clk *sde_power_clk_get_clk(struct sde_power_handle *phandle, return clk; } struct sde_power_event *sde_power_handle_register_event( struct sde_power_handle *phandle, u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), void *usr, char *client_name) { struct sde_power_event *event; if (!phandle) { pr_err("invalid power handle\n"); return ERR_PTR(-EINVAL); } else if (!cb_fnc || !event_type) { pr_err("no callback fnc or event type\n"); return ERR_PTR(-EINVAL); } event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL); if (!event) return ERR_PTR(-ENOMEM); event->event_type = event_type; event->cb_fnc = cb_fnc; event->usr = usr; strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); event->active = true; mutex_lock(&phandle->phandle_lock); list_add(&event->list, &phandle->event_list); mutex_unlock(&phandle->phandle_lock); return event; } void sde_power_handle_unregister_event( struct sde_power_handle *phandle, struct sde_power_event *event) { if (!phandle || !event) { pr_err("invalid phandle or event\n"); } else if (!event->active) { pr_err("power handle deinit already done\n"); kfree(event); } else { mutex_lock(&phandle->phandle_lock); list_del_init(&event->list); mutex_unlock(&phandle->phandle_lock); kfree(event); } }
drivers/gpu/drm/msm/sde_power_handle.h +58 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,18 @@ #include <linux/sde_io_util.h> /* event will be triggered before power handler disable */ #define SDE_POWER_EVENT_PRE_DISABLE 0x1 /* event will be triggered after power handler disable */ #define SDE_POWER_EVENT_POST_DISABLE 0x2 /* event will be triggered before power handler enable */ #define SDE_POWER_EVENT_PRE_ENABLE 0x4 /* event will be triggered after power handler enable */ #define SDE_POWER_EVENT_POST_ENABLE 0x8 /** * mdss_bus_vote_type: register bus vote type * VOTE_INDEX_DISABLE: removes the client vote Loading Loading @@ -59,6 +71,7 @@ enum sde_power_handle_data_bus_client { * @list: list to attach power handle master list * @ab: arbitrated bandwidth for each bus client * @ib: instantaneous bandwidth for each bus client * @active: inidcates the state of sde power handle */ struct sde_power_client { char name[MAX_CLIENT_NAME_LEN]; Loading @@ -68,6 +81,7 @@ struct sde_power_client { struct list_head list; u64 ab[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; u64 ib[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; bool active; }; /** Loading @@ -90,6 +104,24 @@ struct sde_power_data_bus_handle { u32 ao_bw_uc_idx; }; /* * struct sde_power_event - local event registration structure * @client_name: name of the client registering * @cb_fnc: pointer to desired callback function * @usr: user pointer to pass to callback event trigger * @event: refer to SDE_POWER_HANDLE_EVENT_* * @list: list to attach event master list * @active: indicates the state of sde power handle */ struct sde_power_event { char client_name[MAX_CLIENT_NAME_LEN]; void (*cb_fnc)(u32 event_type, void *usr); void *usr; u32 event_type; struct list_head list; bool active; }; /** * struct sde_power_handle: power handle main struct * @mp: module power for clock and regulator Loading @@ -99,6 +131,7 @@ struct sde_power_data_bus_handle { * @usecase_ndx: current usecase index * @reg_bus_hdl: current register bus handle * @data_bus_handle: context structure for data bus control * @event_list: current power handle event list */ struct sde_power_handle { struct dss_module_power mp; Loading @@ -108,6 +141,7 @@ struct sde_power_handle { u32 current_usecase_ndx; u32 reg_bus_hdl; struct sde_power_data_bus_handle data_bus_handle; struct list_head event_list; }; /** Loading Loading @@ -226,4 +260,28 @@ int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, void sde_power_data_bus_bandwidth_ctrl(struct sde_power_handle *phandle, struct sde_power_client *pclient, int enable); /** * sde_power_handle_register_event - register a callback function for an event. * Clients can register for multiple events with a single register. * Any block with access to phandle can register for the event * notification. * @phandle: power handle containing the resources * @event_type: event type to register; refer SDE_POWER_HANDLE_EVENT_* * @cb_fnc: pointer to desired callback function * @usr: user pointer to pass to callback on event trigger * * Return: event pointer if success, or error code otherwise */ struct sde_power_event *sde_power_handle_register_event( struct sde_power_handle *phandle, u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), void *usr, char *client_name); /** * sde_power_handle_unregister_event - unregister callback for event(s) * @phandle: power handle containing the resources * @event: event pointer returned after power handle register */ void sde_power_handle_unregister_event(struct sde_power_handle *phandle, struct sde_power_event *event); #endif /* _SDE_POWER_HANDLE_H_ */