cam_cpas_hw.c 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/device.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/of.h>
  8. #include <linux/pm_opp.h>
  9. #include <linux/slab.h>
  10. #include <linux/module.h>
  11. #include "cam_cpas_hw.h"
  12. #include "cam_cpas_hw_intf.h"
  13. #include "cam_cpas_soc.h"
  14. static uint cam_min_camnoc_ib_bw;
  15. module_param(cam_min_camnoc_ib_bw, uint, 0644);
  16. int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw,
  17. enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info)
  18. {
  19. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  20. struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
  21. uint32_t value;
  22. int reg_base_index;
  23. if (reg_info->enable == false)
  24. return 0;
  25. reg_base_index = cpas_core->regbase_index[reg_base];
  26. if (reg_base_index == -1)
  27. return -EINVAL;
  28. if (reg_info->masked_value) {
  29. value = cam_io_r_mb(
  30. soc_info->reg_map[reg_base_index].mem_base +
  31. reg_info->offset);
  32. value = value & (~reg_info->mask);
  33. value = value | (reg_info->value << reg_info->shift);
  34. } else {
  35. value = reg_info->value;
  36. }
  37. CAM_DBG(CAM_CPAS, "Base[%d] Offset[0x%08x] Value[0x%08x]",
  38. reg_base, reg_info->offset, value);
  39. cam_io_w_mb(value, soc_info->reg_map[reg_base_index].mem_base +
  40. reg_info->offset);
  41. return 0;
  42. }
  43. static int cam_cpas_util_vote_bus_client_level(
  44. struct cam_cpas_bus_client *bus_client, unsigned int level)
  45. {
  46. int rc = 0;
  47. if (!bus_client->valid) {
  48. CAM_ERR(CAM_CPAS, "bus client not valid");
  49. rc = -EINVAL;
  50. goto end;
  51. }
  52. if (level == bus_client->curr_vote_level)
  53. goto end;
  54. rc = cam_soc_bus_client_update_request(bus_client->soc_bus_client,
  55. level);
  56. if (rc) {
  57. CAM_ERR(CAM_CPAS, "Client: %s update request failed rc: %d",
  58. bus_client->common_data.name, rc);
  59. goto end;
  60. }
  61. bus_client->curr_vote_level = level;
  62. end:
  63. return rc;
  64. }
  65. static int cam_cpas_util_vote_bus_client_bw(
  66. struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib,
  67. bool camnoc_bw)
  68. {
  69. int rc = 0;
  70. uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
  71. if (!bus_client->valid) {
  72. CAM_ERR(CAM_CPAS, "bus client: %s not valid",
  73. bus_client->common_data.name);
  74. rc = -EINVAL;
  75. goto end;
  76. }
  77. if (cam_min_camnoc_ib_bw > 0)
  78. min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L;
  79. CAM_DBG(CAM_CPAS,
  80. "Bus_client: %s, cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu",
  81. bus_client->common_data.name, cam_min_camnoc_ib_bw,
  82. min_camnoc_ib_bw);
  83. mutex_lock(&bus_client->lock);
  84. if (camnoc_bw) {
  85. if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW))
  86. ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW;
  87. if ((ib > 0) && (ib < min_camnoc_ib_bw))
  88. ib = min_camnoc_ib_bw;
  89. } else {
  90. if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW))
  91. ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW;
  92. if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW))
  93. ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
  94. }
  95. rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib);
  96. if (rc) {
  97. CAM_ERR(CAM_CPAS,
  98. "Update bw failed, ab[%llu] ib[%llu]",
  99. ab, ib);
  100. goto unlock_client;
  101. }
  102. unlock_client:
  103. mutex_unlock(&bus_client->lock);
  104. end:
  105. return rc;
  106. }
  107. static int cam_cpas_util_register_bus_client(
  108. struct cam_hw_soc_info *soc_info, struct device_node *dev_node,
  109. struct cam_cpas_bus_client *bus_client)
  110. {
  111. int rc = 0;
  112. rc = cam_soc_bus_client_register(soc_info->pdev, dev_node,
  113. &bus_client->soc_bus_client, &bus_client->common_data);
  114. if (rc) {
  115. CAM_ERR(CAM_CPAS, "Bus client: %s registertion failed ,rc: %d",
  116. bus_client->common_data.name, rc);
  117. return rc;
  118. }
  119. bus_client->curr_vote_level = 0;
  120. bus_client->valid = true;
  121. mutex_init(&bus_client->lock);
  122. return 0;
  123. }
  124. static int cam_cpas_util_unregister_bus_client(
  125. struct cam_cpas_bus_client *bus_client)
  126. {
  127. if (!bus_client->valid) {
  128. CAM_ERR(CAM_CPAS, "bus client not valid");
  129. return -EINVAL;
  130. }
  131. cam_soc_bus_client_unregister(&bus_client->soc_bus_client);
  132. bus_client->curr_vote_level = 0;
  133. bus_client->valid = false;
  134. mutex_destroy(&bus_client->lock);
  135. return 0;
  136. }
  137. static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core,
  138. struct cam_hw_soc_info *soc_info)
  139. {
  140. int i = 0;
  141. if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) {
  142. CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d",
  143. cpas_core->num_axi_ports);
  144. return -EINVAL;
  145. }
  146. for (i = 0; i < cpas_core->num_axi_ports; i++) {
  147. cam_cpas_util_unregister_bus_client(
  148. &cpas_core->axi_port[i].bus_client);
  149. of_node_put(cpas_core->axi_port[i].axi_port_node);
  150. cpas_core->axi_port[i].axi_port_node = NULL;
  151. }
  152. return 0;
  153. }
  154. static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core,
  155. struct cam_hw_soc_info *soc_info)
  156. {
  157. int i = 0, rc = 0;
  158. struct device_node *axi_port_mnoc_node = NULL;
  159. if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) {
  160. CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d",
  161. cpas_core->num_axi_ports);
  162. return -EINVAL;
  163. }
  164. for (i = 0; i < cpas_core->num_axi_ports; i++) {
  165. axi_port_mnoc_node = cpas_core->axi_port[i].axi_port_node;
  166. rc = cam_cpas_util_register_bus_client(soc_info,
  167. axi_port_mnoc_node, &cpas_core->axi_port[i].bus_client);
  168. if (rc)
  169. goto bus_register_fail;
  170. }
  171. return 0;
  172. bus_register_fail:
  173. of_node_put(cpas_core->axi_port[i].axi_port_node);
  174. return rc;
  175. }
  176. static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw,
  177. int enable)
  178. {
  179. int rc, i = 0;
  180. struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info;
  181. uint64_t ab_bw, ib_bw;
  182. rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client,
  183. (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE);
  184. if (rc) {
  185. CAM_ERR(CAM_CPAS, "Failed in AHB vote, enable=%d, rc=%d",
  186. enable, rc);
  187. return rc;
  188. }
  189. if (enable) {
  190. ab_bw = CAM_CPAS_DEFAULT_AXI_BW;
  191. ib_bw = CAM_CPAS_DEFAULT_AXI_BW;
  192. } else {
  193. ab_bw = 0;
  194. ib_bw = 0;
  195. }
  196. for (i = 0; i < cpas_core->num_axi_ports; i++) {
  197. rc = cam_cpas_util_vote_bus_client_bw(
  198. &cpas_core->axi_port[i].bus_client,
  199. ab_bw, ib_bw, false);
  200. if (rc) {
  201. CAM_ERR(CAM_CPAS,
  202. "Failed in mnoc vote, enable=%d, rc=%d",
  203. enable, rc);
  204. goto remove_ahb_vote;
  205. }
  206. }
  207. return 0;
  208. remove_ahb_vote:
  209. cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client,
  210. CAM_SUSPEND_VOTE);
  211. return rc;
  212. }
  213. static int cam_cpas_hw_reg_write(struct cam_hw_info *cpas_hw,
  214. uint32_t client_handle, enum cam_cpas_reg_base reg_base,
  215. uint32_t offset, bool mb, uint32_t value)
  216. {
  217. struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
  218. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  219. struct cam_cpas_client *cpas_client = NULL;
  220. int reg_base_index = cpas_core->regbase_index[reg_base];
  221. uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle);
  222. int rc = 0;
  223. if (reg_base_index < 0 || reg_base_index >= soc_info->num_reg_map) {
  224. CAM_ERR(CAM_CPAS,
  225. "Invalid reg_base=%d, reg_base_index=%d, num_map=%d",
  226. reg_base, reg_base_index, soc_info->num_reg_map);
  227. return -EINVAL;
  228. }
  229. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  230. return -EINVAL;
  231. mutex_lock(&cpas_core->client_mutex[client_indx]);
  232. cpas_client = cpas_core->cpas_client[client_indx];
  233. if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  234. CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started",
  235. client_indx, cpas_client->data.identifier,
  236. cpas_client->data.cell_index);
  237. rc = -EPERM;
  238. goto unlock_client;
  239. }
  240. if (mb)
  241. cam_io_w_mb(value,
  242. soc_info->reg_map[reg_base_index].mem_base + offset);
  243. else
  244. cam_io_w(value,
  245. soc_info->reg_map[reg_base_index].mem_base + offset);
  246. unlock_client:
  247. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  248. return rc;
  249. }
  250. static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw,
  251. uint32_t client_handle, enum cam_cpas_reg_base reg_base,
  252. uint32_t offset, bool mb, uint32_t *value)
  253. {
  254. struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
  255. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  256. struct cam_cpas_client *cpas_client = NULL;
  257. int reg_base_index = cpas_core->regbase_index[reg_base];
  258. uint32_t reg_value;
  259. uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle);
  260. int rc = 0;
  261. if (!value)
  262. return -EINVAL;
  263. if (reg_base_index < 0 || reg_base_index >= soc_info->num_reg_map) {
  264. CAM_ERR(CAM_CPAS,
  265. "Invalid reg_base=%d, reg_base_index=%d, num_map=%d",
  266. reg_base, reg_base_index, soc_info->num_reg_map);
  267. return -EINVAL;
  268. }
  269. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  270. return -EINVAL;
  271. cpas_client = cpas_core->cpas_client[client_indx];
  272. if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  273. CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started",
  274. client_indx, cpas_client->data.identifier,
  275. cpas_client->data.cell_index);
  276. return -EPERM;
  277. }
  278. if (mb)
  279. reg_value = cam_io_r_mb(
  280. soc_info->reg_map[reg_base_index].mem_base + offset);
  281. else
  282. reg_value = cam_io_r(
  283. soc_info->reg_map[reg_base_index].mem_base + offset);
  284. *value = reg_value;
  285. return rc;
  286. }
  287. static int cam_cpas_util_set_camnoc_axi_clk_rate(
  288. struct cam_hw_info *cpas_hw)
  289. {
  290. struct cam_cpas_private_soc *soc_private =
  291. (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
  292. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  293. struct cam_cpas_tree_node *tree_node = NULL;
  294. int rc = 0, i = 0;
  295. CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d",
  296. soc_private->control_camnoc_axi_clk);
  297. if (soc_private->control_camnoc_axi_clk) {
  298. struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
  299. uint64_t required_camnoc_bw = 0, intermediate_result = 0;
  300. int32_t clk_rate = 0;
  301. for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) {
  302. tree_node = soc_private->tree_node[i];
  303. if (!tree_node ||
  304. !tree_node->camnoc_max_needed)
  305. continue;
  306. if (required_camnoc_bw < (tree_node->camnoc_bw *
  307. tree_node->bus_width_factor)) {
  308. required_camnoc_bw = tree_node->camnoc_bw *
  309. tree_node->bus_width_factor;
  310. }
  311. }
  312. intermediate_result = required_camnoc_bw *
  313. soc_private->camnoc_axi_clk_bw_margin;
  314. do_div(intermediate_result, 100);
  315. required_camnoc_bw += intermediate_result;
  316. if ((required_camnoc_bw > 0) &&
  317. (required_camnoc_bw <
  318. soc_private->camnoc_axi_min_ib_bw))
  319. required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw;
  320. intermediate_result = required_camnoc_bw;
  321. do_div(intermediate_result, soc_private->camnoc_bus_width);
  322. clk_rate = intermediate_result;
  323. CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d",
  324. required_camnoc_bw, clk_rate);
  325. /*
  326. * CPAS hw is not powered on for the first client.
  327. * Also, clk_rate will be overwritten with default
  328. * value while power on. So, skipping this for first
  329. * client.
  330. */
  331. if (cpas_core->streamon_clients) {
  332. rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate);
  333. if (rc)
  334. CAM_ERR(CAM_CPAS,
  335. "Failed in setting camnoc axi clk %llu %d %d",
  336. required_camnoc_bw, clk_rate, rc);
  337. }
  338. }
  339. return rc;
  340. }
  341. static int cam_cpas_util_translate_client_paths(
  342. struct cam_axi_vote *axi_vote)
  343. {
  344. int i;
  345. uint32_t *path_data_type = NULL;
  346. if (!axi_vote)
  347. return -EINVAL;
  348. for (i = 0; i < axi_vote->num_paths; i++) {
  349. path_data_type = &axi_vote->axi_path[i].path_data_type;
  350. /* Update path_data_type from UAPI value to internal value */
  351. if (*path_data_type >= CAM_CPAS_PATH_DATA_CONSO_OFFSET)
  352. *path_data_type = CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT +
  353. (*path_data_type %
  354. CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT);
  355. else
  356. *path_data_type %= CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT;
  357. if (*path_data_type >= CAM_CPAS_PATH_DATA_MAX) {
  358. CAM_ERR(CAM_CPAS, "index Invalid: %d", path_data_type);
  359. return -EINVAL;
  360. }
  361. }
  362. return 0;
  363. }
  364. static int cam_cpas_axi_consolidate_path_votes(
  365. struct cam_cpas_client *cpas_client,
  366. struct cam_axi_vote *axi_vote)
  367. {
  368. int rc = 0, i, k, l;
  369. struct cam_axi_vote *con_axi_vote = &cpas_client->axi_vote;
  370. bool path_found = false, cons_entry_found;
  371. struct cam_cpas_tree_node *curr_tree_node = NULL;
  372. struct cam_cpas_tree_node *sum_tree_node = NULL;
  373. uint32_t transac_type;
  374. uint32_t path_data_type;
  375. struct cam_axi_per_path_bw_vote *axi_path;
  376. con_axi_vote->num_paths = 0;
  377. for (i = 0; i < axi_vote->num_paths; i++) {
  378. path_found = false;
  379. path_data_type = axi_vote->axi_path[i].path_data_type;
  380. transac_type = axi_vote->axi_path[i].transac_type;
  381. if ((path_data_type >= CAM_CPAS_PATH_DATA_MAX) ||
  382. (transac_type >= CAM_CPAS_TRANSACTION_MAX)) {
  383. CAM_ERR(CAM_CPAS, "Invalid path or transac type: %d %d",
  384. path_data_type, transac_type);
  385. return -EINVAL;
  386. }
  387. axi_path = &con_axi_vote->axi_path[con_axi_vote->num_paths];
  388. curr_tree_node =
  389. cpas_client->tree_node[path_data_type][transac_type];
  390. if (curr_tree_node) {
  391. path_found = true;
  392. memcpy(axi_path, &axi_vote->axi_path[i],
  393. sizeof(struct cam_axi_per_path_bw_vote));
  394. con_axi_vote->num_paths++;
  395. continue;
  396. }
  397. for (k = 0; k < CAM_CPAS_PATH_DATA_MAX; k++) {
  398. sum_tree_node = cpas_client->tree_node[k][transac_type];
  399. if (!sum_tree_node)
  400. continue;
  401. if (sum_tree_node->constituent_paths[path_data_type]) {
  402. path_found = true;
  403. /*
  404. * Check if corresponding consolidated path
  405. * entry is already added into consolidated list
  406. */
  407. cons_entry_found = false;
  408. for (l = 0; l < con_axi_vote->num_paths; l++) {
  409. if ((con_axi_vote->axi_path[l]
  410. .path_data_type == k) &&
  411. (con_axi_vote->axi_path[l]
  412. .transac_type == transac_type)) {
  413. cons_entry_found = true;
  414. con_axi_vote->axi_path[l]
  415. .camnoc_bw +=
  416. axi_vote->axi_path[i]
  417. .camnoc_bw;
  418. con_axi_vote->axi_path[l]
  419. .mnoc_ab_bw +=
  420. axi_vote->axi_path[i]
  421. .mnoc_ab_bw;
  422. con_axi_vote->axi_path[l]
  423. .mnoc_ib_bw +=
  424. axi_vote->axi_path[i]
  425. .mnoc_ib_bw;
  426. break;
  427. }
  428. }
  429. /* If not found, add a new entry */
  430. if (!cons_entry_found) {
  431. axi_path->path_data_type = k;
  432. axi_path->transac_type = transac_type;
  433. axi_path->camnoc_bw =
  434. axi_vote->axi_path[i].camnoc_bw;
  435. axi_path->mnoc_ab_bw =
  436. axi_vote->axi_path[i].mnoc_ab_bw;
  437. axi_path->mnoc_ib_bw =
  438. axi_vote->axi_path[i].mnoc_ib_bw;
  439. con_axi_vote->num_paths++;
  440. }
  441. break;
  442. }
  443. }
  444. if (!path_found) {
  445. CAM_ERR(CAM_CPAS,
  446. "Client [%s][%d] Consolidated path not found for path=%d, transac=%d",
  447. cpas_client->data.identifier,
  448. cpas_client->data.cell_index,
  449. path_data_type, transac_type);
  450. return -EINVAL;
  451. }
  452. }
  453. return rc;
  454. }
  455. static int cam_cpas_util_apply_client_axi_vote(
  456. struct cam_hw_info *cpas_hw,
  457. struct cam_cpas_client *cpas_client,
  458. struct cam_axi_vote *axi_vote)
  459. {
  460. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  461. struct cam_axi_vote *con_axi_vote = NULL;
  462. struct cam_cpas_axi_port *axi_port = NULL;
  463. struct cam_cpas_tree_node *curr_tree_node = NULL;
  464. struct cam_cpas_tree_node *par_tree_node = NULL;
  465. uint32_t transac_type;
  466. uint32_t path_data_type;
  467. bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false};
  468. uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0,
  469. curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0,
  470. par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0;
  471. int rc = 0, i = 0;
  472. mutex_lock(&cpas_core->tree_lock);
  473. if (!cpas_client->tree_node_valid) {
  474. /*
  475. * This is by assuming apply_client_axi_vote is called
  476. * for these clients from only cpas_start, cpas_stop.
  477. * not called from hw_update_axi_vote
  478. */
  479. for (i = 0; i < cpas_core->num_axi_ports; i++) {
  480. if (axi_vote->axi_path[0].mnoc_ab_bw) {
  481. /* start case */
  482. cpas_core->axi_port[i].additional_bw +=
  483. CAM_CPAS_DEFAULT_AXI_BW;
  484. } else {
  485. /* stop case */
  486. cpas_core->axi_port[i].additional_bw -=
  487. CAM_CPAS_DEFAULT_AXI_BW;
  488. }
  489. axi_port_updated[i] = true;
  490. }
  491. goto vote_start_clients;
  492. }
  493. rc = cam_cpas_axi_consolidate_path_votes(cpas_client, axi_vote);
  494. if (rc) {
  495. CAM_ERR(CAM_PERF, "Failed in bw consolidation, Client [%s][%d]",
  496. cpas_client->data.identifier,
  497. cpas_client->data.cell_index);
  498. goto unlock_tree;
  499. }
  500. con_axi_vote = &cpas_client->axi_vote;
  501. cam_cpas_dump_axi_vote_info(cpas_client, "Consolidated Vote",
  502. con_axi_vote);
  503. /* Traverse through node tree and update bw vote values */
  504. for (i = 0; i < con_axi_vote->num_paths; i++) {
  505. path_data_type =
  506. con_axi_vote->axi_path[i].path_data_type;
  507. transac_type =
  508. con_axi_vote->axi_path[i].transac_type;
  509. curr_tree_node = cpas_client->tree_node[path_data_type]
  510. [transac_type];
  511. if (con_axi_vote->axi_path[i].mnoc_ab_bw == 0)
  512. con_axi_vote->axi_path[i].mnoc_ab_bw =
  513. con_axi_vote->axi_path[i].camnoc_bw;
  514. if (con_axi_vote->axi_path[i].camnoc_bw == 0)
  515. con_axi_vote->axi_path[i].camnoc_bw =
  516. con_axi_vote->axi_path[i].mnoc_ab_bw;
  517. if ((curr_tree_node->camnoc_bw ==
  518. con_axi_vote->axi_path[i].camnoc_bw) &&
  519. (curr_tree_node->mnoc_ab_bw ==
  520. con_axi_vote->axi_path[i].mnoc_ab_bw) &&
  521. (curr_tree_node->mnoc_ib_bw ==
  522. con_axi_vote->axi_path[i].mnoc_ib_bw))
  523. continue;
  524. curr_camnoc_old = curr_tree_node->camnoc_bw;
  525. curr_mnoc_ab_old = curr_tree_node->mnoc_ab_bw;
  526. curr_mnoc_ib_old = curr_tree_node->mnoc_ib_bw;
  527. curr_tree_node->camnoc_bw =
  528. con_axi_vote->axi_path[i].camnoc_bw;
  529. curr_tree_node->mnoc_ab_bw =
  530. con_axi_vote->axi_path[i].mnoc_ab_bw;
  531. curr_tree_node->mnoc_ib_bw =
  532. con_axi_vote->axi_path[i].mnoc_ib_bw;
  533. while (curr_tree_node->parent_node) {
  534. par_tree_node = curr_tree_node->parent_node;
  535. par_camnoc_old = par_tree_node->camnoc_bw;
  536. par_mnoc_ab_old = par_tree_node->mnoc_ab_bw;
  537. par_mnoc_ib_old = par_tree_node->mnoc_ib_bw;
  538. par_tree_node->mnoc_ab_bw -= curr_mnoc_ab_old;
  539. par_tree_node->mnoc_ab_bw += curr_tree_node->mnoc_ab_bw;
  540. par_tree_node->mnoc_ib_bw -= curr_mnoc_ib_old;
  541. par_tree_node->mnoc_ib_bw += curr_tree_node->mnoc_ib_bw;
  542. if (par_tree_node->merge_type ==
  543. CAM_CPAS_TRAFFIC_MERGE_SUM) {
  544. par_tree_node->camnoc_bw -=
  545. curr_camnoc_old;
  546. par_tree_node->camnoc_bw +=
  547. curr_tree_node->camnoc_bw;
  548. } else if (par_tree_node->merge_type ==
  549. CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE) {
  550. par_tree_node->camnoc_bw -=
  551. (curr_camnoc_old / 2);
  552. par_tree_node->camnoc_bw +=
  553. (curr_tree_node->camnoc_bw / 2);
  554. } else {
  555. CAM_ERR(CAM_CPAS, "Invalid Merge type");
  556. rc = -EINVAL;
  557. goto unlock_tree;
  558. }
  559. if (!par_tree_node->parent_node) {
  560. if ((par_tree_node->axi_port_idx < 0) ||
  561. (par_tree_node->axi_port_idx >=
  562. CAM_CPAS_MAX_AXI_PORTS)) {
  563. CAM_ERR(CAM_CPAS,
  564. "AXI port index invalid");
  565. rc = -EINVAL;
  566. goto unlock_tree;
  567. }
  568. cpas_core->axi_port
  569. [par_tree_node->axi_port_idx].ab_bw =
  570. par_tree_node->mnoc_ab_bw;
  571. cpas_core->axi_port
  572. [par_tree_node->axi_port_idx].ib_bw =
  573. par_tree_node->mnoc_ib_bw;
  574. axi_port_updated[par_tree_node->axi_port_idx] =
  575. true;
  576. }
  577. curr_tree_node = par_tree_node;
  578. curr_camnoc_old = par_camnoc_old;
  579. curr_mnoc_ab_old = par_mnoc_ab_old;
  580. curr_mnoc_ib_old = par_mnoc_ib_old;
  581. }
  582. }
  583. if (!par_tree_node) {
  584. CAM_DBG(CAM_CPAS, "No change in BW for all paths");
  585. rc = 0;
  586. goto unlock_tree;
  587. }
  588. vote_start_clients:
  589. for (i = 0; i < cpas_core->num_axi_ports; i++) {
  590. if (axi_port_updated[i])
  591. axi_port = &cpas_core->axi_port[i];
  592. else
  593. continue;
  594. CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld",
  595. axi_port->bus_client.common_data.name, axi_port->ab_bw,
  596. axi_port->ib_bw, axi_port->additional_bw);
  597. if (axi_port->ab_bw)
  598. mnoc_ab_bw = axi_port->ab_bw;
  599. else
  600. mnoc_ab_bw = axi_port->additional_bw;
  601. if (cpas_core->axi_port[i].ib_bw_voting_needed)
  602. mnoc_ib_bw = axi_port->ib_bw;
  603. else
  604. mnoc_ib_bw = 0;
  605. rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client,
  606. mnoc_ab_bw, mnoc_ib_bw, false);
  607. if (rc) {
  608. CAM_ERR(CAM_CPAS,
  609. "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
  610. mnoc_ab_bw, mnoc_ib_bw, rc);
  611. goto unlock_tree;
  612. }
  613. }
  614. rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw);
  615. if (rc)
  616. CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc);
  617. unlock_tree:
  618. mutex_unlock(&cpas_core->tree_lock);
  619. return rc;
  620. }
  621. static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw,
  622. uint32_t client_handle, struct cam_axi_vote *client_axi_vote)
  623. {
  624. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  625. struct cam_cpas_client *cpas_client = NULL;
  626. struct cam_axi_vote axi_vote = {0};
  627. uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle);
  628. int rc = 0;
  629. if (!client_axi_vote) {
  630. CAM_ERR(CAM_CPAS, "Invalid arg, client_handle=%d",
  631. client_handle);
  632. return -EINVAL;
  633. }
  634. memcpy(&axi_vote, client_axi_vote, sizeof(struct cam_axi_vote));
  635. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  636. return -EINVAL;
  637. cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx],
  638. "Incoming Vote", &axi_vote);
  639. mutex_lock(&cpas_hw->hw_mutex);
  640. mutex_lock(&cpas_core->client_mutex[client_indx]);
  641. cpas_client = cpas_core->cpas_client[client_indx];
  642. if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  643. CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started",
  644. client_indx, cpas_client->data.identifier,
  645. cpas_client->data.cell_index);
  646. rc = -EPERM;
  647. goto unlock_client;
  648. }
  649. rc = cam_cpas_util_translate_client_paths(&axi_vote);
  650. if (rc) {
  651. CAM_ERR(CAM_CPAS,
  652. "Unable to translate per path votes rc: %d", rc);
  653. goto unlock_client;
  654. }
  655. cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx],
  656. "Translated Vote", &axi_vote);
  657. rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
  658. cpas_core->cpas_client[client_indx], &axi_vote);
  659. unlock_client:
  660. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  661. mutex_unlock(&cpas_hw->hw_mutex);
  662. return rc;
  663. }
  664. static int cam_cpas_util_get_ahb_level(struct cam_hw_info *cpas_hw,
  665. struct device *dev, unsigned long freq, enum cam_vote_level *req_level)
  666. {
  667. struct cam_cpas_private_soc *soc_private =
  668. (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
  669. struct dev_pm_opp *opp;
  670. unsigned int corner;
  671. enum cam_vote_level level = CAM_SVS_VOTE;
  672. unsigned long corner_freq = freq;
  673. int i;
  674. if (!dev || !req_level) {
  675. CAM_ERR(CAM_CPAS, "Invalid params %pK, %pK", dev, req_level);
  676. return -EINVAL;
  677. }
  678. opp = dev_pm_opp_find_freq_ceil(dev, &corner_freq);
  679. if (IS_ERR(opp)) {
  680. CAM_DBG(CAM_CPAS, "OPP Ceil not available for freq :%ld, %pK",
  681. corner_freq, opp);
  682. *req_level = CAM_TURBO_VOTE;
  683. return 0;
  684. }
  685. corner = dev_pm_opp_get_voltage(opp);
  686. for (i = 0; i < soc_private->num_vdd_ahb_mapping; i++)
  687. if (corner == soc_private->vdd_ahb[i].vdd_corner)
  688. level = soc_private->vdd_ahb[i].ahb_level;
  689. CAM_DBG(CAM_CPAS,
  690. "From OPP table : freq=[%ld][%ld], corner=%d, level=%d",
  691. freq, corner_freq, corner, level);
  692. *req_level = level;
  693. return 0;
  694. }
  695. static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw,
  696. struct cam_cpas_client *cpas_client, struct cam_ahb_vote *ahb_vote,
  697. enum cam_vote_level *applied_level)
  698. {
  699. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  700. struct cam_cpas_bus_client *ahb_bus_client = &cpas_core->ahb_bus_client;
  701. enum cam_vote_level required_level;
  702. enum cam_vote_level highest_level;
  703. int i, rc = 0;
  704. if (!ahb_bus_client->valid) {
  705. CAM_ERR(CAM_CPAS, "AHB Bus client not valid");
  706. return -EINVAL;
  707. }
  708. if (ahb_vote->type == CAM_VOTE_DYNAMIC) {
  709. rc = cam_cpas_util_get_ahb_level(cpas_hw, cpas_client->data.dev,
  710. ahb_vote->vote.freq, &required_level);
  711. if (rc)
  712. return rc;
  713. } else {
  714. required_level = ahb_vote->vote.level;
  715. }
  716. if (cpas_client->ahb_level == required_level)
  717. return 0;
  718. mutex_lock(&ahb_bus_client->lock);
  719. cpas_client->ahb_level = required_level;
  720. CAM_DBG(CAM_CPAS, "Client[%s] required level[%d], curr_level[%d]",
  721. ahb_bus_client->common_data.name, required_level,
  722. ahb_bus_client->curr_vote_level);
  723. if (required_level == ahb_bus_client->curr_vote_level)
  724. goto unlock_bus_client;
  725. highest_level = required_level;
  726. for (i = 0; i < cpas_core->num_clients; i++) {
  727. if (cpas_core->cpas_client[i] && (highest_level <
  728. cpas_core->cpas_client[i]->ahb_level))
  729. highest_level = cpas_core->cpas_client[i]->ahb_level;
  730. }
  731. CAM_DBG(CAM_CPAS, "Required highest_level[%d]", highest_level);
  732. if (!cpas_core->ahb_bus_scaling_disable) {
  733. rc = cam_cpas_util_vote_bus_client_level(ahb_bus_client,
  734. highest_level);
  735. if (rc) {
  736. CAM_ERR(CAM_CPAS, "Failed in ahb vote, level=%d, rc=%d",
  737. highest_level, rc);
  738. goto unlock_bus_client;
  739. }
  740. }
  741. rc = cam_soc_util_set_clk_rate_level(&cpas_hw->soc_info, highest_level);
  742. if (rc) {
  743. CAM_ERR(CAM_CPAS,
  744. "Failed in scaling clock rate level %d for AHB",
  745. highest_level);
  746. goto unlock_bus_client;
  747. }
  748. if (applied_level)
  749. *applied_level = highest_level;
  750. unlock_bus_client:
  751. mutex_unlock(&ahb_bus_client->lock);
  752. return rc;
  753. }
  754. static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw,
  755. uint32_t client_handle, struct cam_ahb_vote *client_ahb_vote)
  756. {
  757. struct cam_ahb_vote ahb_vote;
  758. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  759. struct cam_cpas_client *cpas_client = NULL;
  760. uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle);
  761. int rc = 0;
  762. if (!client_ahb_vote) {
  763. CAM_ERR(CAM_CPAS, "Invalid input arg");
  764. return -EINVAL;
  765. }
  766. ahb_vote = *client_ahb_vote;
  767. if (ahb_vote.vote.level == 0) {
  768. CAM_DBG(CAM_CPAS, "0 ahb vote from client %d",
  769. client_handle);
  770. ahb_vote.type = CAM_VOTE_ABSOLUTE;
  771. ahb_vote.vote.level = CAM_SVS_VOTE;
  772. }
  773. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  774. return -EINVAL;
  775. mutex_lock(&cpas_hw->hw_mutex);
  776. mutex_lock(&cpas_core->client_mutex[client_indx]);
  777. cpas_client = cpas_core->cpas_client[client_indx];
  778. if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  779. CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started",
  780. client_indx, cpas_client->data.identifier,
  781. cpas_client->data.cell_index);
  782. rc = -EPERM;
  783. goto unlock_client;
  784. }
  785. CAM_DBG(CAM_PERF,
  786. "client=[%d][%s][%d] : type[%d], level[%d], freq[%ld], applied[%d]",
  787. client_indx, cpas_client->data.identifier,
  788. cpas_client->data.cell_index, ahb_vote.type,
  789. ahb_vote.vote.level, ahb_vote.vote.freq,
  790. cpas_core->cpas_client[client_indx]->ahb_level);
  791. rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw,
  792. cpas_core->cpas_client[client_indx], &ahb_vote, NULL);
  793. unlock_client:
  794. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  795. mutex_unlock(&cpas_hw->hw_mutex);
  796. return rc;
  797. }
  798. static int cam_cpas_util_create_vote_all_paths(
  799. struct cam_cpas_client *cpas_client,
  800. struct cam_axi_vote *axi_vote)
  801. {
  802. int i, j;
  803. uint64_t camnoc_bw, mnoc_ab_bw, mnoc_ib_bw;
  804. struct cam_axi_per_path_bw_vote *axi_path;
  805. if (!cpas_client || !axi_vote)
  806. return -EINVAL;
  807. camnoc_bw = axi_vote->axi_path[0].camnoc_bw;
  808. mnoc_ab_bw = axi_vote->axi_path[0].mnoc_ab_bw;
  809. mnoc_ib_bw = axi_vote->axi_path[0].mnoc_ib_bw;
  810. axi_vote->num_paths = 0;
  811. for (i = 0; i < CAM_CPAS_TRANSACTION_MAX; i++) {
  812. for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) {
  813. if (cpas_client->tree_node[j][i]) {
  814. axi_path =
  815. &axi_vote->axi_path[axi_vote->num_paths];
  816. axi_path->path_data_type = j;
  817. axi_path->transac_type = i;
  818. axi_path->camnoc_bw = camnoc_bw;
  819. axi_path->mnoc_ab_bw = mnoc_ab_bw;
  820. axi_path->mnoc_ib_bw = mnoc_ib_bw;
  821. axi_vote->num_paths++;
  822. }
  823. }
  824. }
  825. return 0;
  826. }
  827. static int cam_cpas_hw_start(void *hw_priv, void *start_args,
  828. uint32_t arg_size)
  829. {
  830. struct cam_hw_info *cpas_hw;
  831. struct cam_cpas *cpas_core;
  832. uint32_t client_indx;
  833. struct cam_cpas_hw_cmd_start *cmd_hw_start;
  834. struct cam_cpas_client *cpas_client;
  835. struct cam_ahb_vote *ahb_vote;
  836. struct cam_axi_vote axi_vote = {0};
  837. enum cam_vote_level applied_level = CAM_SVS_VOTE;
  838. int rc, i = 0;
  839. struct cam_cpas_private_soc *soc_private = NULL;
  840. bool invalid_start = true;
  841. if (!hw_priv || !start_args) {
  842. CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
  843. hw_priv, start_args);
  844. return -EINVAL;
  845. }
  846. if (sizeof(struct cam_cpas_hw_cmd_start) != arg_size) {
  847. CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d",
  848. sizeof(struct cam_cpas_hw_cmd_start), arg_size);
  849. return -EINVAL;
  850. }
  851. cpas_hw = (struct cam_hw_info *)hw_priv;
  852. cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  853. soc_private = (struct cam_cpas_private_soc *)
  854. cpas_hw->soc_info.soc_private;
  855. cmd_hw_start = (struct cam_cpas_hw_cmd_start *)start_args;
  856. client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_start->client_handle);
  857. ahb_vote = cmd_hw_start->ahb_vote;
  858. if (!ahb_vote || !cmd_hw_start->axi_vote)
  859. return -EINVAL;
  860. if (!ahb_vote->vote.level) {
  861. CAM_ERR(CAM_CPAS, "Invalid vote ahb[%d]",
  862. ahb_vote->vote.level);
  863. return -EINVAL;
  864. }
  865. memcpy(&axi_vote, cmd_hw_start->axi_vote, sizeof(struct cam_axi_vote));
  866. for (i = 0; i < axi_vote.num_paths; i++) {
  867. if ((axi_vote.axi_path[i].camnoc_bw != 0) ||
  868. (axi_vote.axi_path[i].mnoc_ab_bw != 0) ||
  869. (axi_vote.axi_path[i].mnoc_ib_bw != 0)) {
  870. invalid_start = false;
  871. break;
  872. }
  873. }
  874. if (invalid_start) {
  875. CAM_ERR(CAM_CPAS, "Zero start vote");
  876. return -EINVAL;
  877. }
  878. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  879. return -EINVAL;
  880. mutex_lock(&cpas_hw->hw_mutex);
  881. mutex_lock(&cpas_core->client_mutex[client_indx]);
  882. cpas_client = cpas_core->cpas_client[client_indx];
  883. if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) {
  884. CAM_ERR(CAM_CPAS, "client=[%d] is not registered",
  885. client_indx);
  886. rc = -EPERM;
  887. goto done;
  888. }
  889. if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  890. CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] is in start state",
  891. client_indx, cpas_client->data.identifier,
  892. cpas_client->data.cell_index);
  893. rc = -EPERM;
  894. goto done;
  895. }
  896. CAM_DBG(CAM_CPAS,
  897. "AHB :client=[%d][%s][%d] type[%d], level[%d], applied[%d]",
  898. client_indx, cpas_client->data.identifier,
  899. cpas_client->data.cell_index,
  900. ahb_vote->type, ahb_vote->vote.level, cpas_client->ahb_level);
  901. rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client,
  902. ahb_vote, &applied_level);
  903. if (rc)
  904. goto done;
  905. cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Vote",
  906. &axi_vote);
  907. /*
  908. * If client has indicated start bw to be applied on all paths
  909. * of client, apply that otherwise apply whatever the client supplies
  910. * for specific paths
  911. */
  912. if (axi_vote.axi_path[0].path_data_type ==
  913. CAM_CPAS_API_PATH_DATA_STD_START) {
  914. rc = cam_cpas_util_create_vote_all_paths(cpas_client,
  915. &axi_vote);
  916. } else {
  917. rc = cam_cpas_util_translate_client_paths(&axi_vote);
  918. }
  919. if (rc) {
  920. CAM_ERR(CAM_CPAS, "Unable to create or translate paths rc: %d",
  921. rc);
  922. goto done;
  923. }
  924. cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote",
  925. &axi_vote);
  926. rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
  927. cpas_client, &axi_vote);
  928. if (rc)
  929. goto done;
  930. if (cpas_core->streamon_clients == 0) {
  931. atomic_set(&cpas_core->irq_count, 1);
  932. rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info,
  933. applied_level);
  934. if (rc) {
  935. atomic_set(&cpas_core->irq_count, 0);
  936. CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc);
  937. goto done;
  938. }
  939. if (cpas_core->internal_ops.power_on) {
  940. rc = cpas_core->internal_ops.power_on(cpas_hw);
  941. if (rc) {
  942. atomic_set(&cpas_core->irq_count, 0);
  943. cam_cpas_soc_disable_resources(
  944. &cpas_hw->soc_info, true, true);
  945. CAM_ERR(CAM_CPAS,
  946. "failed in power_on settings rc=%d",
  947. rc);
  948. goto done;
  949. }
  950. }
  951. CAM_DBG(CAM_CPAS, "irq_count=%d\n",
  952. atomic_read(&cpas_core->irq_count));
  953. cpas_hw->hw_state = CAM_HW_STATE_POWER_UP;
  954. }
  955. cpas_client->started = true;
  956. cpas_core->streamon_clients++;
  957. CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d",
  958. client_indx, cpas_client->data.identifier,
  959. cpas_client->data.cell_index, cpas_core->streamon_clients);
  960. done:
  961. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  962. mutex_unlock(&cpas_hw->hw_mutex);
  963. return rc;
  964. }
  965. static int _check_irq_count(struct cam_cpas *cpas_core)
  966. {
  967. return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1;
  968. }
  969. static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
  970. uint32_t arg_size)
  971. {
  972. struct cam_hw_info *cpas_hw;
  973. struct cam_cpas *cpas_core;
  974. uint32_t client_indx;
  975. struct cam_cpas_hw_cmd_stop *cmd_hw_stop;
  976. struct cam_cpas_client *cpas_client;
  977. struct cam_ahb_vote ahb_vote;
  978. struct cam_axi_vote axi_vote = {0};
  979. struct cam_cpas_private_soc *soc_private = NULL;
  980. int rc = 0;
  981. long result;
  982. if (!hw_priv || !stop_args) {
  983. CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
  984. hw_priv, stop_args);
  985. return -EINVAL;
  986. }
  987. if (sizeof(struct cam_cpas_hw_cmd_stop) != arg_size) {
  988. CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d",
  989. sizeof(struct cam_cpas_hw_cmd_stop), arg_size);
  990. return -EINVAL;
  991. }
  992. cpas_hw = (struct cam_hw_info *)hw_priv;
  993. cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  994. soc_private = (struct cam_cpas_private_soc *)
  995. cpas_hw->soc_info.soc_private;
  996. cmd_hw_stop = (struct cam_cpas_hw_cmd_stop *)stop_args;
  997. client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_stop->client_handle);
  998. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  999. return -EINVAL;
  1000. mutex_lock(&cpas_hw->hw_mutex);
  1001. mutex_lock(&cpas_core->client_mutex[client_indx]);
  1002. cpas_client = cpas_core->cpas_client[client_indx];
  1003. CAM_DBG(CAM_CPAS, "Client=[%d][%s][%d] streamon_clients=%d",
  1004. client_indx, cpas_client->data.identifier,
  1005. cpas_client->data.cell_index, cpas_core->streamon_clients);
  1006. if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  1007. CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not started",
  1008. client_indx, cpas_client->data.identifier,
  1009. cpas_client->data.cell_index);
  1010. rc = -EPERM;
  1011. goto done;
  1012. }
  1013. cpas_client->started = false;
  1014. cpas_core->streamon_clients--;
  1015. if (cpas_core->streamon_clients == 0) {
  1016. if (cpas_core->internal_ops.power_off) {
  1017. rc = cpas_core->internal_ops.power_off(cpas_hw);
  1018. if (rc) {
  1019. CAM_ERR(CAM_CPAS,
  1020. "failed in power_off settings rc=%d",
  1021. rc);
  1022. /* Do not return error, passthrough */
  1023. }
  1024. }
  1025. rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
  1026. if (rc) {
  1027. CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
  1028. goto done;
  1029. }
  1030. /* Wait for any IRQs still being handled */
  1031. atomic_dec(&cpas_core->irq_count);
  1032. result = wait_event_timeout(cpas_core->irq_count_wq,
  1033. _check_irq_count(cpas_core), HZ);
  1034. if (result == 0) {
  1035. CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d",
  1036. atomic_read(&cpas_core->irq_count));
  1037. }
  1038. rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
  1039. true, false);
  1040. if (rc) {
  1041. CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc);
  1042. goto done;
  1043. }
  1044. CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n",
  1045. atomic_read(&cpas_core->irq_count));
  1046. cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
  1047. }
  1048. ahb_vote.type = CAM_VOTE_ABSOLUTE;
  1049. ahb_vote.vote.level = CAM_SUSPEND_VOTE;
  1050. rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client,
  1051. &ahb_vote, NULL);
  1052. if (rc)
  1053. goto done;
  1054. rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote);
  1055. if (rc) {
  1056. CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc);
  1057. goto done;
  1058. }
  1059. cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Stop Vote", &axi_vote);
  1060. rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
  1061. cpas_client, &axi_vote);
  1062. done:
  1063. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  1064. mutex_unlock(&cpas_hw->hw_mutex);
  1065. return rc;
  1066. }
  1067. static int cam_cpas_hw_init(void *hw_priv, void *init_hw_args,
  1068. uint32_t arg_size)
  1069. {
  1070. struct cam_hw_info *cpas_hw;
  1071. struct cam_cpas *cpas_core;
  1072. int rc = 0;
  1073. if (!hw_priv || !init_hw_args) {
  1074. CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
  1075. hw_priv, init_hw_args);
  1076. return -EINVAL;
  1077. }
  1078. if (sizeof(struct cam_cpas_hw_caps) != arg_size) {
  1079. CAM_ERR(CAM_CPAS, "INIT HW size mismatch %zd %d",
  1080. sizeof(struct cam_cpas_hw_caps), arg_size);
  1081. return -EINVAL;
  1082. }
  1083. cpas_hw = (struct cam_hw_info *)hw_priv;
  1084. cpas_core = (struct cam_cpas *)cpas_hw->core_info;
  1085. if (cpas_core->internal_ops.init_hw_version) {
  1086. rc = cpas_core->internal_ops.init_hw_version(cpas_hw,
  1087. (struct cam_cpas_hw_caps *)init_hw_args);
  1088. }
  1089. return rc;
  1090. }
  1091. static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw,
  1092. struct cam_cpas_register_params *register_params)
  1093. {
  1094. int rc;
  1095. char client_name[CAM_HW_IDENTIFIER_LENGTH + 3];
  1096. int32_t client_indx = -1;
  1097. struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info;
  1098. struct cam_cpas_private_soc *soc_private =
  1099. (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
  1100. if ((!register_params) ||
  1101. (strlen(register_params->identifier) < 1)) {
  1102. CAM_ERR(CAM_CPAS, "Invalid cpas client identifier");
  1103. return -EINVAL;
  1104. }
  1105. CAM_DBG(CAM_CPAS, "Register params : identifier=%s, cell_index=%d",
  1106. register_params->identifier, register_params->cell_index);
  1107. if (soc_private->client_id_based)
  1108. snprintf(client_name, sizeof(client_name), "%s%d",
  1109. register_params->identifier,
  1110. register_params->cell_index);
  1111. else
  1112. snprintf(client_name, sizeof(client_name), "%s",
  1113. register_params->identifier);
  1114. mutex_lock(&cpas_hw->hw_mutex);
  1115. rc = cam_common_util_get_string_index(soc_private->client_name,
  1116. soc_private->num_clients, client_name, &client_indx);
  1117. mutex_lock(&cpas_core->client_mutex[client_indx]);
  1118. if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) ||
  1119. CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) {
  1120. CAM_ERR(CAM_CPAS,
  1121. "Inval client %s %d : %d %d %pK %d",
  1122. register_params->identifier,
  1123. register_params->cell_index,
  1124. CAM_CPAS_CLIENT_VALID(client_indx),
  1125. CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx),
  1126. cpas_core->cpas_client[client_indx], rc);
  1127. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  1128. mutex_unlock(&cpas_hw->hw_mutex);
  1129. return -EPERM;
  1130. }
  1131. register_params->client_handle =
  1132. CAM_CPAS_GET_CLIENT_HANDLE(client_indx);
  1133. memcpy(&cpas_core->cpas_client[client_indx]->data, register_params,
  1134. sizeof(struct cam_cpas_register_params));
  1135. cpas_core->registered_clients++;
  1136. cpas_core->cpas_client[client_indx]->registered = true;
  1137. CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d",
  1138. client_indx,
  1139. cpas_core->cpas_client[client_indx]->data.identifier,
  1140. cpas_core->cpas_client[client_indx]->data.cell_index,
  1141. cpas_core->registered_clients);
  1142. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  1143. mutex_unlock(&cpas_hw->hw_mutex);
  1144. return 0;
  1145. }
  1146. static int cam_cpas_hw_unregister_client(struct cam_hw_info *cpas_hw,
  1147. uint32_t client_handle)
  1148. {
  1149. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  1150. uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle);
  1151. int rc = 0;
  1152. if (!CAM_CPAS_CLIENT_VALID(client_indx))
  1153. return -EINVAL;
  1154. mutex_lock(&cpas_hw->hw_mutex);
  1155. mutex_lock(&cpas_core->client_mutex[client_indx]);
  1156. if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) {
  1157. CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] not registered",
  1158. client_indx,
  1159. cpas_core->cpas_client[client_indx]->data.identifier,
  1160. cpas_core->cpas_client[client_indx]->data.cell_index);
  1161. rc = -EPERM;
  1162. goto done;
  1163. }
  1164. if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
  1165. CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not stopped",
  1166. client_indx,
  1167. cpas_core->cpas_client[client_indx]->data.identifier,
  1168. cpas_core->cpas_client[client_indx]->data.cell_index);
  1169. rc = -EPERM;
  1170. goto done;
  1171. }
  1172. CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d",
  1173. client_indx,
  1174. cpas_core->cpas_client[client_indx]->data.identifier,
  1175. cpas_core->cpas_client[client_indx]->data.cell_index,
  1176. cpas_core->registered_clients);
  1177. cpas_core->cpas_client[client_indx]->registered = false;
  1178. cpas_core->registered_clients--;
  1179. done:
  1180. mutex_unlock(&cpas_core->client_mutex[client_indx]);
  1181. mutex_unlock(&cpas_hw->hw_mutex);
  1182. return rc;
  1183. }
  1184. static int cam_cpas_hw_get_hw_info(void *hw_priv,
  1185. void *get_hw_cap_args, uint32_t arg_size)
  1186. {
  1187. struct cam_hw_info *cpas_hw;
  1188. struct cam_cpas *cpas_core;
  1189. struct cam_cpas_hw_caps *hw_caps;
  1190. if (!hw_priv || !get_hw_cap_args) {
  1191. CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
  1192. hw_priv, get_hw_cap_args);
  1193. return -EINVAL;
  1194. }
  1195. if (sizeof(struct cam_cpas_hw_caps) != arg_size) {
  1196. CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d",
  1197. sizeof(struct cam_cpas_hw_caps), arg_size);
  1198. return -EINVAL;
  1199. }
  1200. cpas_hw = (struct cam_hw_info *)hw_priv;
  1201. cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  1202. hw_caps = (struct cam_cpas_hw_caps *)get_hw_cap_args;
  1203. *hw_caps = cpas_core->hw_caps;
  1204. return 0;
  1205. }
  1206. static int cam_cpas_hw_process_cmd(void *hw_priv,
  1207. uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
  1208. {
  1209. int rc = -EINVAL;
  1210. if (!hw_priv || !cmd_args ||
  1211. (cmd_type >= CAM_CPAS_HW_CMD_INVALID)) {
  1212. CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK %d",
  1213. hw_priv, cmd_args, cmd_type);
  1214. return -EINVAL;
  1215. }
  1216. switch (cmd_type) {
  1217. case CAM_CPAS_HW_CMD_REGISTER_CLIENT: {
  1218. struct cam_cpas_register_params *register_params;
  1219. if (sizeof(struct cam_cpas_register_params) != arg_size) {
  1220. CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
  1221. cmd_type, arg_size);
  1222. break;
  1223. }
  1224. register_params = (struct cam_cpas_register_params *)cmd_args;
  1225. rc = cam_cpas_hw_register_client(hw_priv, register_params);
  1226. break;
  1227. }
  1228. case CAM_CPAS_HW_CMD_UNREGISTER_CLIENT: {
  1229. uint32_t *client_handle;
  1230. if (sizeof(uint32_t) != arg_size) {
  1231. CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
  1232. cmd_type, arg_size);
  1233. break;
  1234. }
  1235. client_handle = (uint32_t *)cmd_args;
  1236. rc = cam_cpas_hw_unregister_client(hw_priv, *client_handle);
  1237. break;
  1238. }
  1239. case CAM_CPAS_HW_CMD_REG_WRITE: {
  1240. struct cam_cpas_hw_cmd_reg_read_write *reg_write;
  1241. if (sizeof(struct cam_cpas_hw_cmd_reg_read_write) !=
  1242. arg_size) {
  1243. CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
  1244. cmd_type, arg_size);
  1245. break;
  1246. }
  1247. reg_write =
  1248. (struct cam_cpas_hw_cmd_reg_read_write *)cmd_args;
  1249. rc = cam_cpas_hw_reg_write(hw_priv, reg_write->client_handle,
  1250. reg_write->reg_base, reg_write->offset, reg_write->mb,
  1251. reg_write->value);
  1252. break;
  1253. }
  1254. case CAM_CPAS_HW_CMD_REG_READ: {
  1255. struct cam_cpas_hw_cmd_reg_read_write *reg_read;
  1256. if (sizeof(struct cam_cpas_hw_cmd_reg_read_write) !=
  1257. arg_size) {
  1258. CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
  1259. cmd_type, arg_size);
  1260. break;
  1261. }
  1262. reg_read =
  1263. (struct cam_cpas_hw_cmd_reg_read_write *)cmd_args;
  1264. rc = cam_cpas_hw_reg_read(hw_priv,
  1265. reg_read->client_handle, reg_read->reg_base,
  1266. reg_read->offset, reg_read->mb, &reg_read->value);
  1267. break;
  1268. }
  1269. case CAM_CPAS_HW_CMD_AHB_VOTE: {
  1270. struct cam_cpas_hw_cmd_ahb_vote *cmd_ahb_vote;
  1271. if (sizeof(struct cam_cpas_hw_cmd_ahb_vote) != arg_size) {
  1272. CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
  1273. cmd_type, arg_size);
  1274. break;
  1275. }
  1276. cmd_ahb_vote = (struct cam_cpas_hw_cmd_ahb_vote *)cmd_args;
  1277. rc = cam_cpas_hw_update_ahb_vote(hw_priv,
  1278. cmd_ahb_vote->client_handle, cmd_ahb_vote->ahb_vote);
  1279. break;
  1280. }
  1281. case CAM_CPAS_HW_CMD_AXI_VOTE: {
  1282. struct cam_cpas_hw_cmd_axi_vote *cmd_axi_vote;
  1283. if (sizeof(struct cam_cpas_hw_cmd_axi_vote) != arg_size) {
  1284. CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
  1285. cmd_type, arg_size);
  1286. break;
  1287. }
  1288. cmd_axi_vote = (struct cam_cpas_hw_cmd_axi_vote *)cmd_args;
  1289. rc = cam_cpas_hw_update_axi_vote(hw_priv,
  1290. cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote);
  1291. break;
  1292. }
  1293. default:
  1294. CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type);
  1295. break;
  1296. }
  1297. return rc;
  1298. }
  1299. static int cam_cpas_util_client_setup(struct cam_hw_info *cpas_hw)
  1300. {
  1301. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  1302. int i;
  1303. for (i = 0; i < CAM_CPAS_MAX_CLIENTS; i++) {
  1304. mutex_init(&cpas_core->client_mutex[i]);
  1305. }
  1306. return 0;
  1307. }
  1308. int cam_cpas_util_client_cleanup(struct cam_hw_info *cpas_hw)
  1309. {
  1310. struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
  1311. int i;
  1312. for (i = 0; i < CAM_CPAS_MAX_CLIENTS; i++) {
  1313. if (cpas_core->cpas_client[i] &&
  1314. cpas_core->cpas_client[i]->registered) {
  1315. cam_cpas_hw_unregister_client(cpas_hw, i);
  1316. }
  1317. kfree(cpas_core->cpas_client[i]);
  1318. cpas_core->cpas_client[i] = NULL;
  1319. mutex_destroy(&cpas_core->client_mutex[i]);
  1320. }
  1321. return 0;
  1322. }
  1323. static int cam_cpas_util_get_internal_ops(struct platform_device *pdev,
  1324. struct cam_hw_intf *hw_intf, struct cam_cpas_internal_ops *internal_ops)
  1325. {
  1326. struct device_node *of_node = pdev->dev.of_node;
  1327. int rc;
  1328. const char *compat_str = NULL;
  1329. rc = of_property_read_string_index(of_node, "arch-compat", 0,
  1330. (const char **)&compat_str);
  1331. if (rc) {
  1332. CAM_ERR(CAM_CPAS, "failed to get arch-compat rc=%d", rc);
  1333. return -EINVAL;
  1334. }
  1335. if (strnstr(compat_str, "camss_top", strlen(compat_str))) {
  1336. hw_intf->hw_type = CAM_HW_CAMSSTOP;
  1337. rc = cam_camsstop_get_internal_ops(internal_ops);
  1338. } else if (strnstr(compat_str, "cpas_top", strlen(compat_str))) {
  1339. hw_intf->hw_type = CAM_HW_CPASTOP;
  1340. rc = cam_cpastop_get_internal_ops(internal_ops);
  1341. } else {
  1342. CAM_ERR(CAM_CPAS, "arch-compat %s not supported", compat_str);
  1343. rc = -EINVAL;
  1344. }
  1345. return rc;
  1346. }
  1347. static int cam_cpas_util_create_debugfs(
  1348. struct cam_cpas *cpas_core)
  1349. {
  1350. int rc = 0;
  1351. cpas_core->dentry = debugfs_create_dir("camera_cpas", NULL);
  1352. if (!cpas_core->dentry)
  1353. return -ENOMEM;
  1354. if (!debugfs_create_bool("ahb_bus_scaling_disable",
  1355. 0644,
  1356. cpas_core->dentry,
  1357. &cpas_core->ahb_bus_scaling_disable)) {
  1358. CAM_ERR(CAM_CPAS,
  1359. "failed to create ahb_bus_scaling_disable entry");
  1360. rc = -ENOMEM;
  1361. goto err;
  1362. }
  1363. return 0;
  1364. err:
  1365. debugfs_remove_recursive(cpas_core->dentry);
  1366. cpas_core->dentry = NULL;
  1367. return rc;
  1368. }
  1369. int cam_cpas_hw_probe(struct platform_device *pdev,
  1370. struct cam_hw_intf **hw_intf)
  1371. {
  1372. int rc = 0;
  1373. int i;
  1374. struct cam_hw_info *cpas_hw = NULL;
  1375. struct cam_hw_intf *cpas_hw_intf = NULL;
  1376. struct cam_cpas *cpas_core = NULL;
  1377. struct cam_cpas_private_soc *soc_private;
  1378. struct cam_cpas_internal_ops *internal_ops;
  1379. cpas_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
  1380. if (!cpas_hw_intf)
  1381. return -ENOMEM;
  1382. cpas_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
  1383. if (!cpas_hw) {
  1384. kfree(cpas_hw_intf);
  1385. return -ENOMEM;
  1386. }
  1387. cpas_core = kzalloc(sizeof(struct cam_cpas), GFP_KERNEL);
  1388. if (!cpas_core) {
  1389. kfree(cpas_hw);
  1390. kfree(cpas_hw_intf);
  1391. return -ENOMEM;
  1392. }
  1393. for (i = 0; i < CAM_CPAS_REG_MAX; i++)
  1394. cpas_core->regbase_index[i] = -1;
  1395. cpas_hw_intf->hw_priv = cpas_hw;
  1396. cpas_hw->core_info = cpas_core;
  1397. cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
  1398. cpas_hw->soc_info.pdev = pdev;
  1399. cpas_hw->soc_info.dev = &pdev->dev;
  1400. cpas_hw->soc_info.dev_name = pdev->name;
  1401. cpas_hw->open_count = 0;
  1402. cpas_core->ahb_bus_scaling_disable = false;
  1403. mutex_init(&cpas_hw->hw_mutex);
  1404. spin_lock_init(&cpas_hw->hw_lock);
  1405. init_completion(&cpas_hw->hw_complete);
  1406. cpas_hw_intf->hw_ops.get_hw_caps = cam_cpas_hw_get_hw_info;
  1407. cpas_hw_intf->hw_ops.init = cam_cpas_hw_init;
  1408. cpas_hw_intf->hw_ops.deinit = NULL;
  1409. cpas_hw_intf->hw_ops.reset = NULL;
  1410. cpas_hw_intf->hw_ops.reserve = NULL;
  1411. cpas_hw_intf->hw_ops.release = NULL;
  1412. cpas_hw_intf->hw_ops.start = cam_cpas_hw_start;
  1413. cpas_hw_intf->hw_ops.stop = cam_cpas_hw_stop;
  1414. cpas_hw_intf->hw_ops.read = NULL;
  1415. cpas_hw_intf->hw_ops.write = NULL;
  1416. cpas_hw_intf->hw_ops.process_cmd = cam_cpas_hw_process_cmd;
  1417. cpas_core->work_queue = alloc_workqueue("cam-cpas",
  1418. WQ_UNBOUND | WQ_MEM_RECLAIM, CAM_CPAS_INFLIGHT_WORKS);
  1419. if (!cpas_core->work_queue) {
  1420. rc = -ENOMEM;
  1421. goto release_mem;
  1422. }
  1423. internal_ops = &cpas_core->internal_ops;
  1424. rc = cam_cpas_util_get_internal_ops(pdev, cpas_hw_intf, internal_ops);
  1425. if (rc)
  1426. goto release_workq;
  1427. rc = cam_cpas_soc_init_resources(&cpas_hw->soc_info,
  1428. internal_ops->handle_irq, cpas_hw);
  1429. if (rc)
  1430. goto release_workq;
  1431. soc_private = (struct cam_cpas_private_soc *)
  1432. cpas_hw->soc_info.soc_private;
  1433. cpas_core->num_clients = soc_private->num_clients;
  1434. atomic_set(&cpas_core->irq_count, 0);
  1435. init_waitqueue_head(&cpas_core->irq_count_wq);
  1436. if (internal_ops->setup_regbase) {
  1437. rc = internal_ops->setup_regbase(&cpas_hw->soc_info,
  1438. cpas_core->regbase_index, CAM_CPAS_REG_MAX);
  1439. if (rc)
  1440. goto deinit_platform_res;
  1441. }
  1442. rc = cam_cpas_util_client_setup(cpas_hw);
  1443. if (rc) {
  1444. CAM_ERR(CAM_CPAS, "failed in client setup, rc=%d", rc);
  1445. goto deinit_platform_res;
  1446. }
  1447. rc = cam_cpas_util_register_bus_client(&cpas_hw->soc_info,
  1448. cpas_hw->soc_info.pdev->dev.of_node,
  1449. &cpas_core->ahb_bus_client);
  1450. if (rc) {
  1451. CAM_ERR(CAM_CPAS, "failed in ahb setup, rc=%d", rc);
  1452. goto client_cleanup;
  1453. }
  1454. rc = cam_cpas_util_axi_setup(cpas_core, &cpas_hw->soc_info);
  1455. if (rc) {
  1456. CAM_ERR(CAM_CPAS, "failed in axi setup, rc=%d", rc);
  1457. goto ahb_cleanup;
  1458. }
  1459. /* Need to vote first before enabling clocks */
  1460. rc = cam_cpas_util_vote_default_ahb_axi(cpas_hw, true);
  1461. if (rc)
  1462. goto axi_cleanup;
  1463. rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, CAM_SVS_VOTE);
  1464. if (rc) {
  1465. CAM_ERR(CAM_CPAS, "failed in soc_enable_resources, rc=%d", rc);
  1466. goto remove_default_vote;
  1467. }
  1468. if (internal_ops->get_hw_info) {
  1469. rc = internal_ops->get_hw_info(cpas_hw, &cpas_core->hw_caps);
  1470. if (rc) {
  1471. CAM_ERR(CAM_CPAS, "failed in get_hw_info, rc=%d", rc);
  1472. goto disable_soc_res;
  1473. }
  1474. } else {
  1475. CAM_ERR(CAM_CPAS, "Invalid get_hw_info");
  1476. goto disable_soc_res;
  1477. }
  1478. rc = cam_cpas_hw_init(cpas_hw_intf->hw_priv,
  1479. &cpas_core->hw_caps, sizeof(struct cam_cpas_hw_caps));
  1480. if (rc)
  1481. goto disable_soc_res;
  1482. rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
  1483. if (rc) {
  1484. CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc);
  1485. goto remove_default_vote;
  1486. }
  1487. rc = cam_cpas_util_vote_default_ahb_axi(cpas_hw, false);
  1488. if (rc)
  1489. goto axi_cleanup;
  1490. rc = cam_cpas_util_create_debugfs(cpas_core);
  1491. if (rc)
  1492. CAM_WARN(CAM_CPAS, "Failed to create dentry");
  1493. *hw_intf = cpas_hw_intf;
  1494. return 0;
  1495. disable_soc_res:
  1496. cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
  1497. remove_default_vote:
  1498. cam_cpas_util_vote_default_ahb_axi(cpas_hw, false);
  1499. axi_cleanup:
  1500. cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info);
  1501. ahb_cleanup:
  1502. cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client);
  1503. client_cleanup:
  1504. cam_cpas_util_client_cleanup(cpas_hw);
  1505. cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private);
  1506. deinit_platform_res:
  1507. cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
  1508. release_workq:
  1509. flush_workqueue(cpas_core->work_queue);
  1510. destroy_workqueue(cpas_core->work_queue);
  1511. release_mem:
  1512. mutex_destroy(&cpas_hw->hw_mutex);
  1513. kfree(cpas_core);
  1514. kfree(cpas_hw);
  1515. kfree(cpas_hw_intf);
  1516. CAM_ERR(CAM_CPAS, "failed in hw probe");
  1517. return rc;
  1518. }
  1519. int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf)
  1520. {
  1521. struct cam_hw_info *cpas_hw;
  1522. struct cam_cpas *cpas_core;
  1523. if (!cpas_hw_intf) {
  1524. CAM_ERR(CAM_CPAS, "cpas interface not initialized");
  1525. return -EINVAL;
  1526. }
  1527. cpas_hw = (struct cam_hw_info *)cpas_hw_intf->hw_priv;
  1528. cpas_core = (struct cam_cpas *)cpas_hw->core_info;
  1529. if (cpas_hw->hw_state == CAM_HW_STATE_POWER_UP) {
  1530. CAM_ERR(CAM_CPAS, "cpas hw is in power up state");
  1531. return -EINVAL;
  1532. }
  1533. cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info);
  1534. cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private);
  1535. cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client);
  1536. cam_cpas_util_client_cleanup(cpas_hw);
  1537. cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
  1538. debugfs_remove_recursive(cpas_core->dentry);
  1539. cpas_core->dentry = NULL;
  1540. flush_workqueue(cpas_core->work_queue);
  1541. destroy_workqueue(cpas_core->work_queue);
  1542. mutex_destroy(&cpas_hw->hw_mutex);
  1543. kfree(cpas_core);
  1544. kfree(cpas_hw);
  1545. kfree(cpas_hw_intf);
  1546. return 0;
  1547. }