blob: ddc641d229e3b2fc3b1f77dff71373ed30f4532c [file] [log] [blame]
Lynus Vazdde09ee2012-01-05 13:28:22 +05301/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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.
6 *
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.
11 *
12 */
13
14#include <linux/kernel.h>
15
16#include "kgsl.h"
17#include "kgsl_pwrscale.h"
18#include "kgsl_device.h"
19
20struct kgsl_pwrscale_attribute {
21 struct attribute attr;
22 ssize_t (*show)(struct kgsl_device *device, char *buf);
23 ssize_t (*store)(struct kgsl_device *device, const char *buf,
24 size_t count);
25};
26
27#define to_pwrscale(k) container_of(k, struct kgsl_pwrscale, kobj)
28#define pwrscale_to_device(p) container_of(p, struct kgsl_device, pwrscale)
29#define to_device(k) container_of(k, struct kgsl_device, pwrscale_kobj)
30#define to_pwrscale_attr(a) \
31container_of(a, struct kgsl_pwrscale_attribute, attr)
32#define to_policy_attr(a) \
33container_of(a, struct kgsl_pwrscale_policy_attribute, attr)
34
35#define PWRSCALE_ATTR(_name, _mode, _show, _store) \
36struct kgsl_pwrscale_attribute pwrscale_attr_##_name = \
37__ATTR(_name, _mode, _show, _store)
38
39/* Master list of available policies */
40
41static struct kgsl_pwrscale_policy *kgsl_pwrscale_policies[] = {
42#ifdef CONFIG_MSM_SCM
43 &kgsl_pwrscale_policy_tz,
44#endif
Lynus Vazdde09ee2012-01-05 13:28:22 +053045#ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
Lucille Sylvester591ea032011-07-21 16:08:37 -060046 &kgsl_pwrscale_policy_idlestats,
47#endif
Lucille Sylvester6e362412011-12-09 16:21:42 -070048#ifdef CONFIG_MSM_DCVS
49 &kgsl_pwrscale_policy_msm,
50#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051 NULL
52};
53
54static ssize_t pwrscale_policy_store(struct kgsl_device *device,
55 const char *buf, size_t count)
56{
57 int i;
58 struct kgsl_pwrscale_policy *policy = NULL;
59
60 /* The special keyword none allows the user to detach all
61 policies */
62 if (!strncmp("none", buf, 4)) {
63 kgsl_pwrscale_detach_policy(device);
64 return count;
65 }
66
67 for (i = 0; kgsl_pwrscale_policies[i]; i++) {
68 if (!strncmp(kgsl_pwrscale_policies[i]->name, buf,
69 strnlen(kgsl_pwrscale_policies[i]->name,
70 PAGE_SIZE))) {
71 policy = kgsl_pwrscale_policies[i];
72 break;
73 }
74 }
75
76 if (policy)
77 if (kgsl_pwrscale_attach_policy(device, policy))
78 return -EIO;
79
80 return count;
81}
82
83static ssize_t pwrscale_policy_show(struct kgsl_device *device, char *buf)
84{
85 int ret;
86
87 if (device->pwrscale.policy)
88 ret = snprintf(buf, PAGE_SIZE, "%s\n",
89 device->pwrscale.policy->name);
90 else
91 ret = snprintf(buf, PAGE_SIZE, "none\n");
92
93 return ret;
94}
95
Praveena Pachipulusu263467d2011-12-22 18:07:16 +053096PWRSCALE_ATTR(policy, 0664, pwrscale_policy_show, pwrscale_policy_store);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097
98static ssize_t pwrscale_avail_policies_show(struct kgsl_device *device,
99 char *buf)
100{
101 int i, ret = 0;
102
103 for (i = 0; kgsl_pwrscale_policies[i]; i++) {
104 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s ",
105 kgsl_pwrscale_policies[i]->name);
106 }
107
108 ret += snprintf(buf + ret, PAGE_SIZE - ret, "none\n");
109 return ret;
110}
111PWRSCALE_ATTR(avail_policies, 0444, pwrscale_avail_policies_show, NULL);
112
113static struct attribute *pwrscale_attrs[] = {
114 &pwrscale_attr_policy.attr,
115 &pwrscale_attr_avail_policies.attr,
116 NULL
117};
118
119static ssize_t policy_sysfs_show(struct kobject *kobj,
120 struct attribute *attr, char *buf)
121{
122 struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
123 struct kgsl_device *device = pwrscale_to_device(pwrscale);
124 struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
125 ssize_t ret;
126
127 if (pattr->show)
128 ret = pattr->show(device, pwrscale, buf);
129 else
130 ret = -EIO;
131
132 return ret;
133}
134
135static ssize_t policy_sysfs_store(struct kobject *kobj,
136 struct attribute *attr,
137 const char *buf, size_t count)
138{
139 struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
140 struct kgsl_device *device = pwrscale_to_device(pwrscale);
141 struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
142 ssize_t ret;
143
144 if (pattr->store)
145 ret = pattr->store(device, pwrscale, buf, count);
146 else
147 ret = -EIO;
148
149 return ret;
150}
151
152static void policy_sysfs_release(struct kobject *kobj)
153{
154}
155
156static ssize_t pwrscale_sysfs_show(struct kobject *kobj,
157 struct attribute *attr, char *buf)
158{
159 struct kgsl_device *device = to_device(kobj);
160 struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
161 ssize_t ret;
162
163 if (pattr->show)
164 ret = pattr->show(device, buf);
165 else
166 ret = -EIO;
167
168 return ret;
169}
170
171static ssize_t pwrscale_sysfs_store(struct kobject *kobj,
172 struct attribute *attr,
173 const char *buf, size_t count)
174{
175 struct kgsl_device *device = to_device(kobj);
176 struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
177 ssize_t ret;
178
179 if (pattr->store)
180 ret = pattr->store(device, buf, count);
181 else
182 ret = -EIO;
183
184 return ret;
185}
186
187static void pwrscale_sysfs_release(struct kobject *kobj)
188{
189}
190
191static const struct sysfs_ops policy_sysfs_ops = {
192 .show = policy_sysfs_show,
193 .store = policy_sysfs_store
194};
195
196static const struct sysfs_ops pwrscale_sysfs_ops = {
197 .show = pwrscale_sysfs_show,
198 .store = pwrscale_sysfs_store
199};
200
201static struct kobj_type ktype_pwrscale_policy = {
202 .sysfs_ops = &policy_sysfs_ops,
203 .default_attrs = NULL,
204 .release = policy_sysfs_release
205};
206
207static struct kobj_type ktype_pwrscale = {
208 .sysfs_ops = &pwrscale_sysfs_ops,
209 .default_attrs = pwrscale_attrs,
210 .release = pwrscale_sysfs_release
211};
212
213void kgsl_pwrscale_sleep(struct kgsl_device *device)
214{
215 if (device->pwrscale.policy && device->pwrscale.policy->sleep)
216 device->pwrscale.policy->sleep(device, &device->pwrscale);
217}
218EXPORT_SYMBOL(kgsl_pwrscale_sleep);
219
220void kgsl_pwrscale_wake(struct kgsl_device *device)
221{
222 if (device->pwrscale.policy && device->pwrscale.policy->wake)
223 device->pwrscale.policy->wake(device, &device->pwrscale);
224}
225EXPORT_SYMBOL(kgsl_pwrscale_wake);
226
227void kgsl_pwrscale_busy(struct kgsl_device *device)
228{
229 if (device->pwrscale.policy && device->pwrscale.policy->busy)
Lucille Sylvesterb2679c02012-03-13 17:09:27 -0600230 if ((!device->pwrscale.gpu_busy) &&
231 (device->requested_state != KGSL_STATE_SLUMBER))
Lucille Sylvester28e99c82011-08-18 17:23:10 -0600232 device->pwrscale.policy->busy(device,
233 &device->pwrscale);
Lucille Sylvester1e99fcb2011-08-26 16:58:56 -0600234 device->pwrscale.gpu_busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235}
236
237void kgsl_pwrscale_idle(struct kgsl_device *device)
238{
239 if (device->pwrscale.policy && device->pwrscale.policy->idle)
Lucille Sylvesterb2679c02012-03-13 17:09:27 -0600240 if (device->requested_state !=
241 (KGSL_STATE_SLUMBER | KGSL_STATE_SLEEP))
242 device->pwrscale.policy->idle(device,
243 &device->pwrscale);
Lucille Sylvester1e99fcb2011-08-26 16:58:56 -0600244 device->pwrscale.gpu_busy = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245}
246EXPORT_SYMBOL(kgsl_pwrscale_idle);
247
248int kgsl_pwrscale_policy_add_files(struct kgsl_device *device,
249 struct kgsl_pwrscale *pwrscale,
250 struct attribute_group *attr_group)
251{
252 int ret;
253
254 ret = kobject_add(&pwrscale->kobj, &device->pwrscale_kobj,
255 "%s", pwrscale->policy->name);
256
257 if (ret)
258 return ret;
259
260 ret = sysfs_create_group(&pwrscale->kobj, attr_group);
261
262 if (ret) {
263 kobject_del(&pwrscale->kobj);
264 kobject_put(&pwrscale->kobj);
265 }
266
267 return ret;
268}
269
270void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device,
271 struct kgsl_pwrscale *pwrscale,
272 struct attribute_group *attr_group)
273{
274 sysfs_remove_group(&pwrscale->kobj, attr_group);
275 kobject_del(&pwrscale->kobj);
276 kobject_put(&pwrscale->kobj);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277}
278
279static void _kgsl_pwrscale_detach_policy(struct kgsl_device *device)
280{
Lucille Sylvesterb0568f42011-10-19 13:40:54 -0600281 if (device->pwrscale.policy != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 device->pwrscale.policy->close(device, &device->pwrscale);
Lucille Sylvesterb0568f42011-10-19 13:40:54 -0600283 kgsl_pwrctrl_pwrlevel_change(device,
284 device->pwrctrl.thermal_pwrlevel);
285 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 device->pwrscale.policy = NULL;
287}
288
289void kgsl_pwrscale_detach_policy(struct kgsl_device *device)
290{
291 mutex_lock(&device->mutex);
292 _kgsl_pwrscale_detach_policy(device);
293 mutex_unlock(&device->mutex);
294}
295EXPORT_SYMBOL(kgsl_pwrscale_detach_policy);
296
297int kgsl_pwrscale_attach_policy(struct kgsl_device *device,
298 struct kgsl_pwrscale_policy *policy)
299{
300 int ret = 0;
301
302 mutex_lock(&device->mutex);
303
304 if (device->pwrscale.policy == policy)
305 goto done;
306
Lynus Vaz3f050222012-01-10 11:49:31 +0530307 if (device->pwrctrl.num_pwrlevels < 3) {
308 ret = -EINVAL;
309 goto done;
310 }
311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 if (device->pwrscale.policy != NULL)
313 _kgsl_pwrscale_detach_policy(device);
314
315 device->pwrscale.policy = policy;
316
317 if (policy) {
318 ret = device->pwrscale.policy->init(device, &device->pwrscale);
319 if (ret)
320 device->pwrscale.policy = NULL;
321 }
322
323done:
324 mutex_unlock(&device->mutex);
325
326 return ret;
327}
328EXPORT_SYMBOL(kgsl_pwrscale_attach_policy);
329
330int kgsl_pwrscale_init(struct kgsl_device *device)
331{
332 int ret;
333
334 ret = kobject_init_and_add(&device->pwrscale_kobj, &ktype_pwrscale,
335 &device->dev->kobj, "pwrscale");
336
337 if (ret)
338 return ret;
339
340 kobject_init(&device->pwrscale.kobj, &ktype_pwrscale_policy);
341 return ret;
342}
343EXPORT_SYMBOL(kgsl_pwrscale_init);
344
345void kgsl_pwrscale_close(struct kgsl_device *device)
346{
347 kobject_put(&device->pwrscale_kobj);
348}
349EXPORT_SYMBOL(kgsl_pwrscale_close);