wil_platform_msm.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright (c) 2014 Qualcomm Atheros, Inc.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <linux/of.h>
  17. #include <linux/slab.h>
  18. #include <linux/msm-bus.h>
  19. #include "wil_platform.h"
  20. #include "wil_platform_msm.h"
  21. /**
  22. * struct wil_platform_msm - wil6210 msm platform module info
  23. *
  24. * @dev: device object
  25. * @msm_bus_handle: handle for using msm_bus API
  26. * @pdata: bus scale info retrieved from DT
  27. */
  28. struct wil_platform_msm {
  29. struct device *dev;
  30. uint32_t msm_bus_handle;
  31. struct msm_bus_scale_pdata *pdata;
  32. };
  33. #define KBTOB(a) (a * 1000ULL)
  34. /**
  35. * wil_platform_get_pdata() - Generate bus client data from device tree
  36. * provided by clients.
  37. *
  38. * dev: device object
  39. * of_node: Device tree node to extract information from
  40. *
  41. * The function returns a valid pointer to the allocated bus-scale-pdata
  42. * if the vectors were correctly read from the client's device node.
  43. * Any error in reading or parsing the device node will return NULL
  44. * to the caller.
  45. */
  46. static struct msm_bus_scale_pdata *wil_platform_get_pdata(
  47. struct device *dev,
  48. struct device_node *of_node)
  49. {
  50. struct msm_bus_scale_pdata *pdata;
  51. struct msm_bus_paths *usecase;
  52. int i, j, ret, len;
  53. unsigned int num_usecases, num_paths, mem_size;
  54. const uint32_t *vec_arr;
  55. struct msm_bus_vectors *vectors;
  56. /* first read num_usecases and num_paths so we can calculate
  57. * amount of memory to allocate
  58. */
  59. ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
  60. &num_usecases);
  61. if (ret) {
  62. dev_err(dev, "Error: num-usecases not found\n");
  63. return NULL;
  64. }
  65. ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
  66. &num_paths);
  67. if (ret) {
  68. dev_err(dev, "Error: num_paths not found\n");
  69. return NULL;
  70. }
  71. /* pdata memory layout:
  72. * msm_bus_scale_pdata
  73. * msm_bus_paths[num_usecases]
  74. * msm_bus_vectors[num_usecases][num_paths]
  75. */
  76. mem_size = sizeof(struct msm_bus_scale_pdata) +
  77. sizeof(struct msm_bus_paths) * num_usecases +
  78. sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
  79. pdata = kzalloc(mem_size, GFP_KERNEL);
  80. if (!pdata)
  81. return NULL;
  82. ret = of_property_read_string(of_node, "qcom,msm-bus,name",
  83. &pdata->name);
  84. if (ret) {
  85. dev_err(dev, "Error: Client name not found\n");
  86. goto err;
  87. }
  88. if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
  89. pdata->active_only = 1;
  90. } else {
  91. dev_info(dev, "active_only flag absent.\n");
  92. dev_info(dev, "Using dual context by default\n");
  93. }
  94. pdata->num_usecases = num_usecases;
  95. pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
  96. vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
  97. if (vec_arr == NULL) {
  98. dev_err(dev, "Error: Vector array not found\n");
  99. goto err;
  100. }
  101. if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
  102. dev_err(dev, "Error: Length-error on getting vectors\n");
  103. goto err;
  104. }
  105. vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
  106. for (i = 0; i < num_usecases; i++) {
  107. usecase = &pdata->usecase[i];
  108. usecase->num_paths = num_paths;
  109. usecase->vectors = &vectors[i];
  110. for (j = 0; j < num_paths; j++) {
  111. int index = ((i * num_paths) + j) * 4;
  112. usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
  113. usecase->vectors[j].dst =
  114. be32_to_cpu(vec_arr[index + 1]);
  115. usecase->vectors[j].ab = (uint64_t)
  116. KBTOB(be32_to_cpu(vec_arr[index + 2]));
  117. usecase->vectors[j].ib = (uint64_t)
  118. KBTOB(be32_to_cpu(vec_arr[index + 3]));
  119. }
  120. }
  121. return pdata;
  122. err:
  123. kfree(pdata);
  124. return NULL;
  125. }
  126. /* wil_platform API (callbacks) */
  127. static int wil_platform_bus_request(void *handle,
  128. uint32_t kbps /* KBytes/Sec */)
  129. {
  130. int rc, i;
  131. struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
  132. int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
  133. struct msm_bus_paths *usecase;
  134. uint32_t usecase_kbps;
  135. uint32_t min_kbps = ~0;
  136. /* find the lowest usecase that is bigger than requested kbps */
  137. for (i = 0; i < msm->pdata->num_usecases; i++) {
  138. usecase = &msm->pdata->usecase[i];
  139. /* assume we have single path (vectors[0]). If we ever
  140. * have multiple paths, need to define the behavior */
  141. usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
  142. if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
  143. min_kbps = usecase_kbps;
  144. vote = i;
  145. }
  146. }
  147. rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
  148. if (rc)
  149. dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
  150. kbps, vote, rc);
  151. else
  152. /* TOOD: remove */
  153. dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
  154. kbps, vote);
  155. return rc;
  156. }
  157. static void wil_platform_uninit(void *handle)
  158. {
  159. struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
  160. dev_info(msm->dev, "wil_platform_uninit\n");
  161. if (msm->msm_bus_handle)
  162. msm_bus_scale_unregister_client(msm->msm_bus_handle);
  163. kfree(msm->pdata);
  164. kfree(msm);
  165. }
  166. static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
  167. struct device_node *node)
  168. {
  169. msm->pdata = wil_platform_get_pdata(msm->dev, node);
  170. if (!msm->pdata) {
  171. dev_err(msm->dev, "Failed getting DT info\n");
  172. return -EINVAL;
  173. }
  174. msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
  175. if (!msm->msm_bus_handle) {
  176. dev_err(msm->dev, "Failed msm_bus registration\n");
  177. return -EINVAL;
  178. }
  179. dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
  180. msm->msm_bus_handle);
  181. return 0;
  182. }
  183. /**
  184. * wil_platform_msm_init() - wil6210 msm platform module init
  185. *
  186. * The function must be called before all other functions in this module.
  187. * It returns a handle which is used with the rest of the API
  188. *
  189. */
  190. void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
  191. {
  192. struct device_node *of_node;
  193. struct wil_platform_msm *msm;
  194. int rc;
  195. of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
  196. if (!of_node) {
  197. /* this could mean non-msm platform */
  198. dev_err(dev, "DT node not found\n");
  199. return NULL;
  200. }
  201. msm = kzalloc(sizeof(*msm), GFP_KERNEL);
  202. if (!msm)
  203. return NULL;
  204. msm->dev = dev;
  205. /* register with msm_bus module for scaling requests */
  206. rc = wil_platform_msm_bus_register(msm, of_node);
  207. if (rc)
  208. goto cleanup;
  209. memset(ops, 0, sizeof(*ops));
  210. ops->bus_request = wil_platform_bus_request;
  211. ops->uninit = wil_platform_uninit;
  212. return (void *)msm;
  213. cleanup:
  214. kfree(msm);
  215. return NULL;
  216. }