/drivers/gpu/msm/kgsl_pwrscale.c

https://bitbucket.org/gideonx/bms-jb-3.4.y · C · 376 lines · 284 code · 72 blank · 20 comment · 36 complexity · 60a6753c0dd621edc09163c7f3c9d0e0 MD5 · raw file

  1. /* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  2. *
  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. #include <linux/export.h>
  14. #include <linux/kernel.h>
  15. #include <asm/page.h>
  16. #include "kgsl.h"
  17. #include "kgsl_pwrscale.h"
  18. #include "kgsl_device.h"
  19. struct kgsl_pwrscale_attribute {
  20. struct attribute attr;
  21. ssize_t (*show)(struct kgsl_device *device, char *buf);
  22. ssize_t (*store)(struct kgsl_device *device, const char *buf,
  23. size_t count);
  24. };
  25. #define to_pwrscale(k) container_of(k, struct kgsl_pwrscale, kobj)
  26. #define pwrscale_to_device(p) container_of(p, struct kgsl_device, pwrscale)
  27. #define to_device(k) container_of(k, struct kgsl_device, pwrscale_kobj)
  28. #define to_pwrscale_attr(a) \
  29. container_of(a, struct kgsl_pwrscale_attribute, attr)
  30. #define to_policy_attr(a) \
  31. container_of(a, struct kgsl_pwrscale_policy_attribute, attr)
  32. #define PWRSCALE_ATTR(_name, _mode, _show, _store) \
  33. struct kgsl_pwrscale_attribute pwrscale_attr_##_name = \
  34. __ATTR(_name, _mode, _show, _store)
  35. /* Master list of available policies */
  36. static struct kgsl_pwrscale_policy *kgsl_pwrscale_policies[] = {
  37. #ifdef CONFIG_MSM_SCM
  38. &kgsl_pwrscale_policy_tz,
  39. #endif
  40. #ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
  41. &kgsl_pwrscale_policy_idlestats,
  42. #endif
  43. #ifdef CONFIG_MSM_DCVS
  44. &kgsl_pwrscale_policy_msm,
  45. #endif
  46. NULL
  47. };
  48. static ssize_t pwrscale_policy_store(struct kgsl_device *device,
  49. const char *buf, size_t count)
  50. {
  51. int i;
  52. struct kgsl_pwrscale_policy *policy = NULL;
  53. /* The special keyword none allows the user to detach all
  54. policies */
  55. if (!strncmp("none", buf, 4)) {
  56. kgsl_pwrscale_detach_policy(device);
  57. return count;
  58. }
  59. for (i = 0; kgsl_pwrscale_policies[i]; i++) {
  60. if (!strncmp(kgsl_pwrscale_policies[i]->name, buf,
  61. strnlen(kgsl_pwrscale_policies[i]->name,
  62. PAGE_SIZE))) {
  63. policy = kgsl_pwrscale_policies[i];
  64. break;
  65. }
  66. }
  67. if (policy)
  68. if (kgsl_pwrscale_attach_policy(device, policy))
  69. return -EIO;
  70. return count;
  71. }
  72. static ssize_t pwrscale_policy_show(struct kgsl_device *device, char *buf)
  73. {
  74. int ret;
  75. if (device->pwrscale.policy) {
  76. ret = snprintf(buf, PAGE_SIZE, "%s",
  77. device->pwrscale.policy->name);
  78. if (device->pwrscale.enabled == 0)
  79. ret += snprintf(buf + ret, PAGE_SIZE - ret,
  80. " (disabled)");
  81. ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
  82. } else
  83. ret = snprintf(buf, PAGE_SIZE, "none\n");
  84. return ret;
  85. }
  86. PWRSCALE_ATTR(policy, 0664, pwrscale_policy_show, pwrscale_policy_store);
  87. static ssize_t pwrscale_avail_policies_show(struct kgsl_device *device,
  88. char *buf)
  89. {
  90. int i, ret = 0;
  91. for (i = 0; kgsl_pwrscale_policies[i]; i++) {
  92. ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s ",
  93. kgsl_pwrscale_policies[i]->name);
  94. }
  95. ret += snprintf(buf + ret, PAGE_SIZE - ret, "none\n");
  96. return ret;
  97. }
  98. PWRSCALE_ATTR(avail_policies, 0444, pwrscale_avail_policies_show, NULL);
  99. static struct attribute *pwrscale_attrs[] = {
  100. &pwrscale_attr_policy.attr,
  101. &pwrscale_attr_avail_policies.attr,
  102. NULL
  103. };
  104. static ssize_t policy_sysfs_show(struct kobject *kobj,
  105. struct attribute *attr, char *buf)
  106. {
  107. struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
  108. struct kgsl_device *device = pwrscale_to_device(pwrscale);
  109. struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
  110. ssize_t ret;
  111. if (pattr->show)
  112. ret = pattr->show(device, pwrscale, buf);
  113. else
  114. ret = -EIO;
  115. return ret;
  116. }
  117. static ssize_t policy_sysfs_store(struct kobject *kobj,
  118. struct attribute *attr,
  119. const char *buf, size_t count)
  120. {
  121. struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
  122. struct kgsl_device *device = pwrscale_to_device(pwrscale);
  123. struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
  124. ssize_t ret;
  125. if (pattr->store)
  126. ret = pattr->store(device, pwrscale, buf, count);
  127. else
  128. ret = -EIO;
  129. return ret;
  130. }
  131. static void policy_sysfs_release(struct kobject *kobj)
  132. {
  133. }
  134. static ssize_t pwrscale_sysfs_show(struct kobject *kobj,
  135. struct attribute *attr, char *buf)
  136. {
  137. struct kgsl_device *device = to_device(kobj);
  138. struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
  139. ssize_t ret;
  140. if (pattr->show)
  141. ret = pattr->show(device, buf);
  142. else
  143. ret = -EIO;
  144. return ret;
  145. }
  146. static ssize_t pwrscale_sysfs_store(struct kobject *kobj,
  147. struct attribute *attr,
  148. const char *buf, size_t count)
  149. {
  150. struct kgsl_device *device = to_device(kobj);
  151. struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
  152. ssize_t ret;
  153. if (pattr->store)
  154. ret = pattr->store(device, buf, count);
  155. else
  156. ret = -EIO;
  157. return ret;
  158. }
  159. static void pwrscale_sysfs_release(struct kobject *kobj)
  160. {
  161. }
  162. static const struct sysfs_ops policy_sysfs_ops = {
  163. .show = policy_sysfs_show,
  164. .store = policy_sysfs_store
  165. };
  166. static const struct sysfs_ops pwrscale_sysfs_ops = {
  167. .show = pwrscale_sysfs_show,
  168. .store = pwrscale_sysfs_store
  169. };
  170. static struct kobj_type ktype_pwrscale_policy = {
  171. .sysfs_ops = &policy_sysfs_ops,
  172. .default_attrs = NULL,
  173. .release = policy_sysfs_release
  174. };
  175. static struct kobj_type ktype_pwrscale = {
  176. .sysfs_ops = &pwrscale_sysfs_ops,
  177. .default_attrs = pwrscale_attrs,
  178. .release = pwrscale_sysfs_release
  179. };
  180. #define PWRSCALE_ACTIVE(_d) \
  181. ((_d)->pwrscale.policy && (_d)->pwrscale.enabled)
  182. void kgsl_pwrscale_sleep(struct kgsl_device *device)
  183. {
  184. if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->sleep)
  185. device->pwrscale.policy->sleep(device, &device->pwrscale);
  186. }
  187. EXPORT_SYMBOL(kgsl_pwrscale_sleep);
  188. void kgsl_pwrscale_wake(struct kgsl_device *device)
  189. {
  190. if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->wake)
  191. device->pwrscale.policy->wake(device, &device->pwrscale);
  192. }
  193. EXPORT_SYMBOL(kgsl_pwrscale_wake);
  194. void kgsl_pwrscale_busy(struct kgsl_device *device)
  195. {
  196. if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->busy)
  197. device->pwrscale.policy->busy(device,
  198. &device->pwrscale);
  199. }
  200. EXPORT_SYMBOL(kgsl_pwrscale_busy);
  201. void kgsl_pwrscale_idle(struct kgsl_device *device)
  202. {
  203. if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
  204. if (device->state == KGSL_STATE_ACTIVE)
  205. device->pwrscale.policy->idle(device,
  206. &device->pwrscale);
  207. }
  208. EXPORT_SYMBOL(kgsl_pwrscale_idle);
  209. void kgsl_pwrscale_disable(struct kgsl_device *device)
  210. {
  211. device->pwrscale.enabled = 0;
  212. }
  213. EXPORT_SYMBOL(kgsl_pwrscale_disable);
  214. void kgsl_pwrscale_enable(struct kgsl_device *device)
  215. {
  216. device->pwrscale.enabled = 1;
  217. }
  218. EXPORT_SYMBOL(kgsl_pwrscale_enable);
  219. int kgsl_pwrscale_policy_add_files(struct kgsl_device *device,
  220. struct kgsl_pwrscale *pwrscale,
  221. struct attribute_group *attr_group)
  222. {
  223. int ret;
  224. ret = kobject_add(&pwrscale->kobj, &device->pwrscale_kobj,
  225. "%s", pwrscale->policy->name);
  226. if (ret)
  227. return ret;
  228. ret = sysfs_create_group(&pwrscale->kobj, attr_group);
  229. if (ret) {
  230. kobject_del(&pwrscale->kobj);
  231. kobject_put(&pwrscale->kobj);
  232. }
  233. return ret;
  234. }
  235. void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device,
  236. struct kgsl_pwrscale *pwrscale,
  237. struct attribute_group *attr_group)
  238. {
  239. sysfs_remove_group(&pwrscale->kobj, attr_group);
  240. kobject_del(&pwrscale->kobj);
  241. kobject_put(&pwrscale->kobj);
  242. }
  243. static void _kgsl_pwrscale_detach_policy(struct kgsl_device *device)
  244. {
  245. if (device->pwrscale.policy != NULL) {
  246. device->pwrscale.policy->close(device, &device->pwrscale);
  247. /*
  248. * Try to set max pwrlevel which will be limited to thermal by
  249. * kgsl_pwrctrl_pwrlevel_change if thermal is indeed lower
  250. */
  251. kgsl_pwrctrl_pwrlevel_change(device,
  252. device->pwrctrl.max_pwrlevel);
  253. }
  254. device->pwrscale.policy = NULL;
  255. }
  256. void kgsl_pwrscale_detach_policy(struct kgsl_device *device)
  257. {
  258. mutex_lock(&device->mutex);
  259. _kgsl_pwrscale_detach_policy(device);
  260. mutex_unlock(&device->mutex);
  261. }
  262. EXPORT_SYMBOL(kgsl_pwrscale_detach_policy);
  263. int kgsl_pwrscale_attach_policy(struct kgsl_device *device,
  264. struct kgsl_pwrscale_policy *policy)
  265. {
  266. int ret = 0;
  267. mutex_lock(&device->mutex);
  268. if (device->pwrscale.policy == policy)
  269. goto done;
  270. if (device->pwrctrl.num_pwrlevels < 3) {
  271. ret = -EINVAL;
  272. goto done;
  273. }
  274. if (device->pwrscale.policy != NULL)
  275. _kgsl_pwrscale_detach_policy(device);
  276. device->pwrscale.policy = policy;
  277. /* Pwrscale is enabled by default at attach time */
  278. kgsl_pwrscale_enable(device);
  279. if (policy) {
  280. ret = device->pwrscale.policy->init(device, &device->pwrscale);
  281. if (ret)
  282. device->pwrscale.policy = NULL;
  283. }
  284. done:
  285. mutex_unlock(&device->mutex);
  286. return ret;
  287. }
  288. EXPORT_SYMBOL(kgsl_pwrscale_attach_policy);
  289. int kgsl_pwrscale_init(struct kgsl_device *device)
  290. {
  291. int ret;
  292. ret = kobject_init_and_add(&device->pwrscale_kobj, &ktype_pwrscale,
  293. &device->dev->kobj, "pwrscale");
  294. if (ret)
  295. return ret;
  296. kobject_init(&device->pwrscale.kobj, &ktype_pwrscale_policy);
  297. return ret;
  298. }
  299. EXPORT_SYMBOL(kgsl_pwrscale_init);
  300. void kgsl_pwrscale_close(struct kgsl_device *device)
  301. {
  302. kobject_put(&device->pwrscale_kobj);
  303. }
  304. EXPORT_SYMBOL(kgsl_pwrscale_close);