1 /* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
14 #define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__
16 #include <linux/kernel.h>
18 #include <linux/string.h>
19 #include <linux/of_address.h>
20 #include <linux/slab.h>
21 #include <linux/mutex.h>
22 #include <linux/of_platform.h>
24 #include "dpu_power_handle.h"
25 #include "dpu_trace.h"
27 static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = {
28 [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus",
29 [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus",
30 [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus",
33 const char *dpu_power_handle_get_dbus_name(u32 bus_id)
35 if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX)
36 return data_bus_name[bus_id];
41 static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle,
44 struct dpu_power_event *event;
46 list_for_each_entry(event, &phandle->event_list, list) {
47 if (event->event_type & event_type)
48 event->cb_fnc(event_type, event->usr);
52 struct dpu_power_client *dpu_power_client_create(
53 struct dpu_power_handle *phandle, char *client_name)
55 struct dpu_power_client *client;
58 if (!client_name || !phandle) {
59 pr_err("client name is null or invalid power data\n");
60 return ERR_PTR(-EINVAL);
63 client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL);
65 return ERR_PTR(-ENOMEM);
67 mutex_lock(&phandle->phandle_lock);
68 strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
69 client->usecase_ndx = VOTE_INDEX_DISABLE;
71 client->active = true;
72 pr_debug("client %s created:%pK id :%d\n", client_name,
75 list_add(&client->list, &phandle->power_client_clist);
76 mutex_unlock(&phandle->phandle_lock);
81 void dpu_power_client_destroy(struct dpu_power_handle *phandle,
82 struct dpu_power_client *client)
84 if (!client || !phandle) {
85 pr_err("reg bus vote: invalid client handle\n");
86 } else if (!client->active) {
87 pr_err("dpu power deinit already done\n");
90 pr_debug("bus vote client %s destroyed:%pK id:%u\n",
91 client->name, client, client->id);
92 mutex_lock(&phandle->phandle_lock);
93 list_del_init(&client->list);
94 mutex_unlock(&phandle->phandle_lock);
99 void dpu_power_resource_init(struct platform_device *pdev,
100 struct dpu_power_handle *phandle)
102 phandle->dev = &pdev->dev;
104 INIT_LIST_HEAD(&phandle->power_client_clist);
105 INIT_LIST_HEAD(&phandle->event_list);
107 mutex_init(&phandle->phandle_lock);
110 void dpu_power_resource_deinit(struct platform_device *pdev,
111 struct dpu_power_handle *phandle)
113 struct dpu_power_client *curr_client, *next_client;
114 struct dpu_power_event *curr_event, *next_event;
116 if (!phandle || !pdev) {
117 pr_err("invalid input param\n");
121 mutex_lock(&phandle->phandle_lock);
122 list_for_each_entry_safe(curr_client, next_client,
123 &phandle->power_client_clist, list) {
124 pr_err("client:%s-%d still registered with refcount:%d\n",
125 curr_client->name, curr_client->id,
126 curr_client->refcount);
127 curr_client->active = false;
128 list_del(&curr_client->list);
131 list_for_each_entry_safe(curr_event, next_event,
132 &phandle->event_list, list) {
133 pr_err("event:%d, client:%s still registered\n",
134 curr_event->event_type,
135 curr_event->client_name);
136 curr_event->active = false;
137 list_del(&curr_event->list);
139 mutex_unlock(&phandle->phandle_lock);
142 int dpu_power_resource_enable(struct dpu_power_handle *phandle,
143 struct dpu_power_client *pclient, bool enable)
145 bool changed = false;
146 u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx;
147 struct dpu_power_client *client;
149 if (!phandle || !pclient) {
150 pr_err("invalid input argument\n");
154 mutex_lock(&phandle->phandle_lock);
157 else if (pclient->refcount)
160 if (pclient->refcount)
161 pclient->usecase_ndx = VOTE_INDEX_LOW;
163 pclient->usecase_ndx = VOTE_INDEX_DISABLE;
165 list_for_each_entry(client, &phandle->power_client_clist, list) {
166 if (client->usecase_ndx < VOTE_INDEX_MAX &&
167 client->usecase_ndx > max_usecase_ndx)
168 max_usecase_ndx = client->usecase_ndx;
171 if (phandle->current_usecase_ndx != max_usecase_ndx) {
173 prev_usecase_ndx = phandle->current_usecase_ndx;
174 phandle->current_usecase_ndx = max_usecase_ndx;
177 pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n",
178 __builtin_return_address(0), changed, max_usecase_ndx,
179 pclient->name, pclient->id, enable, pclient->refcount);
185 dpu_power_event_trigger_locked(phandle,
186 DPU_POWER_EVENT_PRE_ENABLE);
187 dpu_power_event_trigger_locked(phandle,
188 DPU_POWER_EVENT_POST_ENABLE);
191 dpu_power_event_trigger_locked(phandle,
192 DPU_POWER_EVENT_PRE_DISABLE);
193 dpu_power_event_trigger_locked(phandle,
194 DPU_POWER_EVENT_POST_DISABLE);
198 mutex_unlock(&phandle->phandle_lock);
202 struct dpu_power_event *dpu_power_handle_register_event(
203 struct dpu_power_handle *phandle,
204 u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
205 void *usr, char *client_name)
207 struct dpu_power_event *event;
210 pr_err("invalid power handle\n");
211 return ERR_PTR(-EINVAL);
212 } else if (!cb_fnc || !event_type) {
213 pr_err("no callback fnc or event type\n");
214 return ERR_PTR(-EINVAL);
217 event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL);
219 return ERR_PTR(-ENOMEM);
221 event->event_type = event_type;
222 event->cb_fnc = cb_fnc;
224 strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN);
225 event->active = true;
227 mutex_lock(&phandle->phandle_lock);
228 list_add(&event->list, &phandle->event_list);
229 mutex_unlock(&phandle->phandle_lock);
234 void dpu_power_handle_unregister_event(
235 struct dpu_power_handle *phandle,
236 struct dpu_power_event *event)
238 if (!phandle || !event) {
239 pr_err("invalid phandle or event\n");
240 } else if (!event->active) {
241 pr_err("power handle deinit already done\n");
244 mutex_lock(&phandle->phandle_lock);
245 list_del_init(&event->list);
246 mutex_unlock(&phandle->phandle_lock);