cam_cpas_intf.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/of.h>
  6. #include <linux/module.h>
  7. #include <linux/kernel.h>
  8. #include <linux/platform_device.h>
  9. #include <media/v4l2-event.h>
  10. #include <media/v4l2-ioctl.h>
  11. #include <media/v4l2-subdev.h>
  12. #include <media/cam_cpas.h>
  13. #include <media/cam_req_mgr.h>
  14. #include <dt-bindings/msm-camera.h>
  15. #include "cam_subdev.h"
  16. #include "cam_cpas_hw_intf.h"
  17. #include "cam_cpas_soc.h"
  18. #include "camera_main.h"
  19. #define CAM_CPAS_DEV_NAME "cam-cpas"
  20. #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done)
  21. /**
  22. * struct cam_cpas_intf : CPAS interface
  23. *
  24. * @pdev: Platform device
  25. * @subdev: Subdev info
  26. * @hw_intf: CPAS HW interface
  27. * @hw_caps: CPAS HW capabilities
  28. * @intf_lock: CPAS interface mutex
  29. * @open_cnt: CPAS subdev open count
  30. * @probe_done: Whether CPAS prove completed
  31. *
  32. */
  33. struct cam_cpas_intf {
  34. struct platform_device *pdev;
  35. struct cam_subdev subdev;
  36. struct cam_hw_intf *hw_intf;
  37. struct cam_cpas_hw_caps hw_caps;
  38. struct mutex intf_lock;
  39. uint32_t open_cnt;
  40. bool probe_done;
  41. };
  42. static struct cam_cpas_intf *g_cpas_intf;
  43. const char *cam_cpas_axi_util_path_type_to_string(
  44. uint32_t path_data_type)
  45. {
  46. switch (path_data_type) {
  47. /* IFE Paths */
  48. case CAM_AXI_PATH_DATA_IFE_LINEAR:
  49. return "IFE_LINEAR";
  50. case CAM_AXI_PATH_DATA_IFE_VID:
  51. return "IFE_VID";
  52. case CAM_AXI_PATH_DATA_IFE_DISP:
  53. return "IFE_DISP";
  54. case CAM_AXI_PATH_DATA_IFE_STATS:
  55. return "IFE_STATS";
  56. case CAM_AXI_PATH_DATA_IFE_RDI0:
  57. return "IFE_RDI0";
  58. case CAM_AXI_PATH_DATA_IFE_RDI1:
  59. return "IFE_RDI1";
  60. case CAM_AXI_PATH_DATA_IFE_RDI2:
  61. return "IFE_RDI2";
  62. case CAM_AXI_PATH_DATA_IFE_RDI3:
  63. return "IFE_RDI3";
  64. case CAM_AXI_PATH_DATA_IFE_PDAF:
  65. return "IFE_PDAF";
  66. case CAM_AXI_PATH_DATA_IFE_PIXEL_RAW:
  67. return "IFE_PIXEL_RAW";
  68. /* IPE Paths */
  69. case CAM_AXI_PATH_DATA_IPE_RD_IN:
  70. return "IPE_RD_IN";
  71. case CAM_AXI_PATH_DATA_IPE_RD_REF:
  72. return "IPE_RD_REF";
  73. case CAM_AXI_PATH_DATA_IPE_WR_VID:
  74. return "IPE_WR_VID";
  75. case CAM_AXI_PATH_DATA_IPE_WR_DISP:
  76. return "IPE_WR_DISP";
  77. case CAM_AXI_PATH_DATA_IPE_WR_REF:
  78. return "IPE_WR_REF";
  79. /* OPE Paths */
  80. case CAM_AXI_PATH_DATA_OPE_RD_IN:
  81. return "OPE_RD_IN";
  82. case CAM_AXI_PATH_DATA_OPE_RD_REF:
  83. return "OPE_RD_REF";
  84. case CAM_AXI_PATH_DATA_OPE_WR_VID:
  85. return "OPE_WR_VID";
  86. case CAM_AXI_PATH_DATA_OPE_WR_DISP:
  87. return "OPE_WR_DISP";
  88. case CAM_AXI_PATH_DATA_OPE_WR_REF:
  89. return "OPE_WR_REF";
  90. /* SFE Paths */
  91. case CAM_AXI_PATH_DATA_SFE_NRDI:
  92. return "SFE_NRDI";
  93. case CAM_AXI_PATH_DATA_SFE_RDI0:
  94. return "SFE_RDI0";
  95. case CAM_AXI_PATH_DATA_SFE_RDI1:
  96. return "SFE_RDI1";
  97. case CAM_AXI_PATH_DATA_SFE_RDI2:
  98. return "SFE_RDI2";
  99. case CAM_AXI_PATH_DATA_SFE_RDI3:
  100. return "SFE_RDI3";
  101. case CAM_AXI_PATH_DATA_SFE_RDI4:
  102. return "SFE_RDI4";
  103. case CAM_AXI_PATH_DATA_SFE_STATS:
  104. return "SFE_STATS";
  105. /* Common Paths */
  106. case CAM_AXI_PATH_DATA_ALL:
  107. return "DATA_ALL";
  108. default:
  109. return "IFE_PATH_INVALID";
  110. }
  111. }
  112. EXPORT_SYMBOL(cam_cpas_axi_util_path_type_to_string);
  113. const char *cam_cpas_axi_util_trans_type_to_string(
  114. uint32_t transac_type)
  115. {
  116. switch (transac_type) {
  117. case CAM_AXI_TRANSACTION_READ:
  118. return "TRANSAC_READ";
  119. case CAM_AXI_TRANSACTION_WRITE:
  120. return "TRANSAC_WRITE";
  121. default:
  122. return "TRANSAC_INVALID";
  123. }
  124. }
  125. EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
  126. bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
  127. uint32_t *fuse_val)
  128. {
  129. struct cam_hw_info *cpas_hw = NULL;
  130. struct cam_cpas_private_soc *soc_private = NULL;
  131. bool supported = true;
  132. int32_t i;
  133. if (!CAM_CPAS_INTF_INITIALIZED()) {
  134. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  135. return false;
  136. }
  137. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  138. soc_private =
  139. (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
  140. if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) {
  141. CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag);
  142. return false;
  143. }
  144. for (i = 0; i < soc_private->num_feature_info; i++)
  145. if (soc_private->feature_info[i].feature == flag)
  146. break;
  147. if (i == soc_private->num_feature_info) {
  148. CAM_INFO(CAM_CPAS, "Feature not found, no of featues: %d",
  149. soc_private->num_feature_info);
  150. goto end;
  151. }
  152. if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE
  153. || (soc_private->feature_info[i].type ==
  154. CAM_CPAS_FEATURE_TYPE_ENABLE)) {
  155. if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map)
  156. supported = soc_private->feature_info[i].enable;
  157. else
  158. supported = !soc_private->feature_info[i].enable;
  159. } else {
  160. if (!fuse_val) {
  161. CAM_ERR(CAM_CPAS,
  162. "Invalid arg fuse_val");
  163. } else {
  164. *fuse_val = soc_private->feature_info[i].value;
  165. }
  166. }
  167. end:
  168. return supported;
  169. }
  170. EXPORT_SYMBOL(cam_cpas_is_feature_supported);
  171. int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
  172. {
  173. struct cam_hw_info *cpas_hw = NULL;
  174. if (!CAM_CPAS_INTF_INITIALIZED()) {
  175. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  176. return -ENODEV;
  177. }
  178. if (!hw_version) {
  179. CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version);
  180. return -EINVAL;
  181. }
  182. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  183. *hw_version = cpas_hw->soc_info.hw_version;
  184. if (*hw_version == CAM_CPAS_TITAN_NONE) {
  185. CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d",
  186. *hw_version);
  187. }
  188. return 0;
  189. }
  190. int cam_cpas_get_hw_info(uint32_t *camera_family,
  191. struct cam_hw_version *camera_version,
  192. struct cam_hw_version *cpas_version,
  193. uint32_t *cam_caps,
  194. struct cam_cpas_fuse_info *cam_fuse_info)
  195. {
  196. if (!CAM_CPAS_INTF_INITIALIZED()) {
  197. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  198. return -ENODEV;
  199. }
  200. if (!camera_family || !camera_version || !cpas_version || !cam_caps) {
  201. CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK",
  202. camera_family, camera_version, cpas_version, cam_caps);
  203. return -EINVAL;
  204. }
  205. *camera_family = g_cpas_intf->hw_caps.camera_family;
  206. *camera_version = g_cpas_intf->hw_caps.camera_version;
  207. *cpas_version = g_cpas_intf->hw_caps.cpas_version;
  208. *cam_caps = g_cpas_intf->hw_caps.camera_capability;
  209. if (cam_fuse_info)
  210. *cam_fuse_info = g_cpas_intf->hw_caps.fuse_info;
  211. CAM_DBG(CAM_CPAS, "Family %d, version %d.%d cam_caps %d",
  212. *camera_family, camera_version->major,
  213. camera_version->minor, *cam_caps);
  214. return 0;
  215. }
  216. EXPORT_SYMBOL(cam_cpas_get_hw_info);
  217. int cam_cpas_reg_write(uint32_t client_handle,
  218. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  219. uint32_t value)
  220. {
  221. int rc;
  222. if (!CAM_CPAS_INTF_INITIALIZED()) {
  223. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  224. return -ENODEV;
  225. }
  226. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  227. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write;
  228. cmd_reg_write.client_handle = client_handle;
  229. cmd_reg_write.reg_base = reg_base;
  230. cmd_reg_write.offset = offset;
  231. cmd_reg_write.value = value;
  232. cmd_reg_write.mb = mb;
  233. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  234. g_cpas_intf->hw_intf->hw_priv,
  235. CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write,
  236. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  237. if (rc)
  238. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  239. } else {
  240. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  241. rc = -EINVAL;
  242. }
  243. return rc;
  244. }
  245. EXPORT_SYMBOL(cam_cpas_reg_write);
  246. int cam_cpas_reg_read(uint32_t client_handle,
  247. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  248. uint32_t *value)
  249. {
  250. int rc;
  251. if (!CAM_CPAS_INTF_INITIALIZED()) {
  252. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  253. return -ENODEV;
  254. }
  255. if (!value) {
  256. CAM_ERR(CAM_CPAS, "Invalid arg value");
  257. return -EINVAL;
  258. }
  259. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  260. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read;
  261. cmd_reg_read.client_handle = client_handle;
  262. cmd_reg_read.reg_base = reg_base;
  263. cmd_reg_read.offset = offset;
  264. cmd_reg_read.mb = mb;
  265. cmd_reg_read.value = 0;
  266. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  267. g_cpas_intf->hw_intf->hw_priv,
  268. CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read,
  269. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  270. if (rc) {
  271. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  272. return rc;
  273. }
  274. *value = cmd_reg_read.value;
  275. } else {
  276. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  277. rc = -EINVAL;
  278. }
  279. return rc;
  280. }
  281. EXPORT_SYMBOL(cam_cpas_reg_read);
  282. int cam_cpas_update_axi_vote(uint32_t client_handle,
  283. struct cam_axi_vote *axi_vote)
  284. {
  285. int rc;
  286. if (!CAM_CPAS_INTF_INITIALIZED()) {
  287. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  288. return -ENODEV;
  289. }
  290. if (!axi_vote) {
  291. CAM_ERR(CAM_CPAS, "NULL axi vote");
  292. return -EINVAL;
  293. }
  294. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  295. struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote;
  296. cmd_axi_vote.client_handle = client_handle;
  297. cmd_axi_vote.axi_vote = axi_vote;
  298. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  299. g_cpas_intf->hw_intf->hw_priv,
  300. CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote,
  301. sizeof(struct cam_cpas_hw_cmd_axi_vote));
  302. if (rc)
  303. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  304. } else {
  305. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  306. rc = -EINVAL;
  307. }
  308. return rc;
  309. }
  310. EXPORT_SYMBOL(cam_cpas_update_axi_vote);
  311. int cam_cpas_update_ahb_vote(uint32_t client_handle,
  312. struct cam_ahb_vote *ahb_vote)
  313. {
  314. int rc;
  315. if (!CAM_CPAS_INTF_INITIALIZED()) {
  316. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  317. return -ENODEV;
  318. }
  319. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  320. struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote;
  321. cmd_ahb_vote.client_handle = client_handle;
  322. cmd_ahb_vote.ahb_vote = ahb_vote;
  323. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  324. g_cpas_intf->hw_intf->hw_priv,
  325. CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote,
  326. sizeof(struct cam_cpas_hw_cmd_ahb_vote));
  327. if (rc)
  328. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  329. } else {
  330. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  331. rc = -EINVAL;
  332. }
  333. return rc;
  334. }
  335. EXPORT_SYMBOL(cam_cpas_update_ahb_vote);
  336. int cam_cpas_stop(uint32_t client_handle)
  337. {
  338. int rc;
  339. if (!CAM_CPAS_INTF_INITIALIZED()) {
  340. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  341. return -ENODEV;
  342. }
  343. if (g_cpas_intf->hw_intf->hw_ops.stop) {
  344. struct cam_cpas_hw_cmd_stop cmd_hw_stop;
  345. cmd_hw_stop.client_handle = client_handle;
  346. rc = g_cpas_intf->hw_intf->hw_ops.stop(
  347. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop,
  348. sizeof(struct cam_cpas_hw_cmd_stop));
  349. if (rc)
  350. CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc);
  351. } else {
  352. CAM_ERR(CAM_CPAS, "Invalid stop ops");
  353. rc = -EINVAL;
  354. }
  355. return rc;
  356. }
  357. EXPORT_SYMBOL(cam_cpas_stop);
  358. int cam_cpas_start(uint32_t client_handle,
  359. struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote)
  360. {
  361. int rc;
  362. if (!CAM_CPAS_INTF_INITIALIZED()) {
  363. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  364. return -ENODEV;
  365. }
  366. if (!axi_vote) {
  367. CAM_ERR(CAM_CPAS, "NULL axi vote");
  368. return -EINVAL;
  369. }
  370. if (g_cpas_intf->hw_intf->hw_ops.start) {
  371. struct cam_cpas_hw_cmd_start cmd_hw_start;
  372. cmd_hw_start.client_handle = client_handle;
  373. cmd_hw_start.ahb_vote = ahb_vote;
  374. cmd_hw_start.axi_vote = axi_vote;
  375. rc = g_cpas_intf->hw_intf->hw_ops.start(
  376. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start,
  377. sizeof(struct cam_cpas_hw_cmd_start));
  378. if (rc)
  379. CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc);
  380. } else {
  381. CAM_ERR(CAM_CPAS, "Invalid start ops");
  382. rc = -EINVAL;
  383. }
  384. return rc;
  385. }
  386. EXPORT_SYMBOL(cam_cpas_start);
  387. void cam_cpas_log_votes(void)
  388. {
  389. uint32_t dummy_args;
  390. int rc;
  391. if (!CAM_CPAS_INTF_INITIALIZED()) {
  392. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  393. return;
  394. }
  395. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  396. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  397. g_cpas_intf->hw_intf->hw_priv,
  398. CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args,
  399. sizeof(dummy_args));
  400. if (rc)
  401. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  402. } else {
  403. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  404. }
  405. }
  406. EXPORT_SYMBOL(cam_cpas_log_votes);
  407. int cam_cpas_select_qos_settings(uint32_t selection_mask)
  408. {
  409. int rc = 0;
  410. if (!CAM_CPAS_INTF_INITIALIZED()) {
  411. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  412. return -EBADR;
  413. }
  414. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  415. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  416. g_cpas_intf->hw_intf->hw_priv,
  417. CAM_CPAS_HW_CMD_SELECT_QOS, &selection_mask,
  418. sizeof(selection_mask));
  419. if (rc)
  420. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  421. } else {
  422. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  423. rc = -EBADR;
  424. }
  425. return rc;
  426. }
  427. EXPORT_SYMBOL(cam_cpas_select_qos_settings);
  428. int cam_cpas_notify_event(const char *identifier_string,
  429. int32_t identifier_value)
  430. {
  431. int rc = 0;
  432. if (!CAM_CPAS_INTF_INITIALIZED()) {
  433. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  434. return -EBADR;
  435. }
  436. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  437. struct cam_cpas_hw_cmd_notify_event event = { 0 };
  438. event.identifier_string = identifier_string;
  439. event.identifier_value = identifier_value;
  440. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  441. g_cpas_intf->hw_intf->hw_priv,
  442. CAM_CPAS_HW_CMD_LOG_EVENT, &event,
  443. sizeof(event));
  444. if (rc)
  445. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  446. } else {
  447. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  448. rc = -EBADR;
  449. }
  450. return rc;
  451. }
  452. EXPORT_SYMBOL(cam_cpas_notify_event);
  453. int cam_cpas_unregister_client(uint32_t client_handle)
  454. {
  455. int rc;
  456. if (!CAM_CPAS_INTF_INITIALIZED()) {
  457. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  458. return -ENODEV;
  459. }
  460. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  461. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  462. g_cpas_intf->hw_intf->hw_priv,
  463. CAM_CPAS_HW_CMD_UNREGISTER_CLIENT,
  464. &client_handle, sizeof(uint32_t));
  465. if (rc)
  466. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  467. } else {
  468. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  469. rc = -EINVAL;
  470. }
  471. return rc;
  472. }
  473. EXPORT_SYMBOL(cam_cpas_unregister_client);
  474. int cam_cpas_register_client(
  475. struct cam_cpas_register_params *register_params)
  476. {
  477. int rc;
  478. if (!CAM_CPAS_INTF_INITIALIZED()) {
  479. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  480. return -ENODEV;
  481. }
  482. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  483. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  484. g_cpas_intf->hw_intf->hw_priv,
  485. CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params,
  486. sizeof(struct cam_cpas_register_params));
  487. if (rc)
  488. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  489. } else {
  490. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  491. rc = -EINVAL;
  492. }
  493. return rc;
  494. }
  495. EXPORT_SYMBOL(cam_cpas_register_client);
  496. int cam_cpas_get_scid(
  497. enum cam_sys_cache_config_types type)
  498. {
  499. int rc;
  500. if (!CAM_CPAS_INTF_INITIALIZED()) {
  501. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  502. return -ENODEV;
  503. }
  504. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  505. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  506. g_cpas_intf->hw_intf->hw_priv,
  507. CAM_CPAS_HW_CMD_GET_SCID, &type,
  508. sizeof(type));
  509. } else {
  510. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  511. rc = -EINVAL;
  512. }
  513. return rc;
  514. }
  515. EXPORT_SYMBOL(cam_cpas_get_scid);
  516. int cam_cpas_activate_llcc(
  517. enum cam_sys_cache_config_types type)
  518. {
  519. int rc;
  520. if (!CAM_CPAS_INTF_INITIALIZED()) {
  521. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  522. return -ENODEV;
  523. }
  524. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  525. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  526. g_cpas_intf->hw_intf->hw_priv,
  527. CAM_CPAS_HW_CMD_ACTIVATE_LLC, &type,
  528. sizeof(type));
  529. if (rc)
  530. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  531. } else {
  532. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  533. rc = -EINVAL;
  534. }
  535. return rc;
  536. }
  537. EXPORT_SYMBOL(cam_cpas_activate_llcc);
  538. int cam_cpas_deactivate_llcc(
  539. enum cam_sys_cache_config_types type)
  540. {
  541. int rc;
  542. if (!CAM_CPAS_INTF_INITIALIZED()) {
  543. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  544. return -ENODEV;
  545. }
  546. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  547. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  548. g_cpas_intf->hw_intf->hw_priv,
  549. CAM_CPAS_HW_CMD_DEACTIVATE_LLC, &type,
  550. sizeof(type));
  551. if (rc)
  552. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  553. } else {
  554. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  555. rc = -EINVAL;
  556. }
  557. return rc;
  558. }
  559. EXPORT_SYMBOL(cam_cpas_deactivate_llcc);
  560. int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
  561. struct cam_control *cmd)
  562. {
  563. int rc = 0;
  564. if (!cmd) {
  565. CAM_ERR(CAM_CPAS, "Invalid input cmd");
  566. return -EINVAL;
  567. }
  568. switch (cmd->op_code) {
  569. case CAM_QUERY_CAP: {
  570. struct cam_cpas_query_cap query;
  571. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  572. sizeof(query));
  573. if (rc) {
  574. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  575. rc);
  576. break;
  577. }
  578. rc = cam_cpas_get_hw_info(&query.camera_family,
  579. &query.camera_version, &query.cpas_version,
  580. &query.reserved, NULL);
  581. if (rc)
  582. break;
  583. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  584. sizeof(query));
  585. if (rc)
  586. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  587. break;
  588. }
  589. case CAM_QUERY_CAP_V2: {
  590. struct cam_cpas_query_cap_v2 query;
  591. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  592. sizeof(query));
  593. if (rc) {
  594. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  595. rc);
  596. break;
  597. }
  598. rc = cam_cpas_get_hw_info(&query.camera_family,
  599. &query.camera_version, &query.cpas_version,
  600. &query.reserved,
  601. &query.fuse_info);
  602. if (rc)
  603. break;
  604. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  605. sizeof(query));
  606. if (rc)
  607. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  608. break;
  609. }
  610. case CAM_SD_SHUTDOWN:
  611. break;
  612. default:
  613. CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code);
  614. rc = -EINVAL;
  615. break;
  616. }
  617. return rc;
  618. }
  619. static int cam_cpas_subdev_open(struct v4l2_subdev *sd,
  620. struct v4l2_subdev_fh *fh)
  621. {
  622. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  623. if (!cpas_intf || !cpas_intf->probe_done) {
  624. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  625. return -ENODEV;
  626. }
  627. mutex_lock(&cpas_intf->intf_lock);
  628. cpas_intf->open_cnt++;
  629. CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt);
  630. mutex_unlock(&cpas_intf->intf_lock);
  631. return 0;
  632. }
  633. static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
  634. struct v4l2_subdev_fh *fh)
  635. {
  636. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  637. if (!cpas_intf || !cpas_intf->probe_done) {
  638. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  639. return -ENODEV;
  640. }
  641. mutex_lock(&cpas_intf->intf_lock);
  642. cpas_intf->open_cnt--;
  643. CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt);
  644. mutex_unlock(&cpas_intf->intf_lock);
  645. return 0;
  646. }
  647. static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
  648. unsigned int cmd, void *arg)
  649. {
  650. int32_t rc;
  651. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  652. if (!cpas_intf || !cpas_intf->probe_done) {
  653. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  654. return -ENODEV;
  655. }
  656. switch (cmd) {
  657. case VIDIOC_CAM_CONTROL:
  658. rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
  659. break;
  660. default:
  661. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  662. rc = -EINVAL;
  663. break;
  664. }
  665. return rc;
  666. }
  667. #ifdef CONFIG_COMPAT
  668. static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
  669. unsigned int cmd, unsigned long arg)
  670. {
  671. struct cam_control cmd_data;
  672. int32_t rc;
  673. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  674. if (!cpas_intf || !cpas_intf->probe_done) {
  675. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  676. return -ENODEV;
  677. }
  678. if (copy_from_user(&cmd_data, (void __user *)arg,
  679. sizeof(cmd_data))) {
  680. CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu",
  681. (void __user *)arg, sizeof(cmd_data));
  682. return -EFAULT;
  683. }
  684. switch (cmd) {
  685. case VIDIOC_CAM_CONTROL:
  686. rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
  687. break;
  688. default:
  689. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  690. rc = -EINVAL;
  691. break;
  692. }
  693. if (!rc) {
  694. if (copy_to_user((void __user *)arg, &cmd_data,
  695. sizeof(cmd_data))) {
  696. CAM_ERR(CAM_CPAS,
  697. "Failed to copy to user_ptr=%pK size=%zu",
  698. (void __user *)arg, sizeof(cmd_data));
  699. rc = -EFAULT;
  700. }
  701. }
  702. return rc;
  703. }
  704. #endif
  705. static struct v4l2_subdev_core_ops cpas_subdev_core_ops = {
  706. .ioctl = cam_cpas_subdev_ioctl,
  707. #ifdef CONFIG_COMPAT
  708. .compat_ioctl32 = cam_cpas_subdev_compat_ioctl,
  709. #endif
  710. };
  711. static const struct v4l2_subdev_ops cpas_subdev_ops = {
  712. .core = &cpas_subdev_core_ops,
  713. };
  714. static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = {
  715. .open = cam_cpas_subdev_open,
  716. .close = cam_cpas_subdev_close,
  717. };
  718. static int cam_cpas_subdev_register(struct platform_device *pdev)
  719. {
  720. int rc;
  721. struct cam_subdev *subdev;
  722. if (!g_cpas_intf)
  723. return -EINVAL;
  724. subdev = &g_cpas_intf->subdev;
  725. subdev->name = CAM_CPAS_DEV_NAME;
  726. subdev->pdev = pdev;
  727. subdev->ops = &cpas_subdev_ops;
  728. subdev->internal_ops = &cpas_subdev_intern_ops;
  729. subdev->token = g_cpas_intf;
  730. subdev->sd_flags =
  731. V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
  732. subdev->ent_function = CAM_CPAS_DEVICE_TYPE;
  733. rc = cam_register_subdev(subdev);
  734. if (rc) {
  735. CAM_ERR(CAM_CPAS, "failed register subdev: %s!",
  736. CAM_CPAS_DEV_NAME);
  737. return rc;
  738. }
  739. platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf);
  740. return rc;
  741. }
  742. static int cam_cpas_dev_component_bind(struct device *dev,
  743. struct device *master_dev, void *data)
  744. {
  745. struct cam_cpas_hw_caps *hw_caps;
  746. struct cam_hw_intf *hw_intf;
  747. int rc;
  748. struct platform_device *pdev = to_platform_device(dev);
  749. if (g_cpas_intf) {
  750. CAM_ERR(CAM_CPAS, "cpas component already binded");
  751. return -EALREADY;
  752. }
  753. g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL);
  754. if (!g_cpas_intf)
  755. return -ENOMEM;
  756. mutex_init(&g_cpas_intf->intf_lock);
  757. g_cpas_intf->pdev = pdev;
  758. rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf);
  759. if (rc || (g_cpas_intf->hw_intf == NULL)) {
  760. CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc);
  761. goto error_destroy_mem;
  762. }
  763. hw_intf = g_cpas_intf->hw_intf;
  764. hw_caps = &g_cpas_intf->hw_caps;
  765. if (hw_intf->hw_ops.get_hw_caps) {
  766. rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv,
  767. hw_caps, sizeof(struct cam_cpas_hw_caps));
  768. if (rc) {
  769. CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc);
  770. goto error_hw_remove;
  771. }
  772. } else {
  773. CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops");
  774. goto error_hw_remove;
  775. }
  776. rc = cam_cpas_subdev_register(pdev);
  777. if (rc)
  778. goto error_hw_remove;
  779. g_cpas_intf->probe_done = true;
  780. CAM_DBG(CAM_CPAS,
  781. "Component bound successfully %d, %d.%d.%d, %d.%d.%d, 0x%x",
  782. hw_caps->camera_family, hw_caps->camera_version.major,
  783. hw_caps->camera_version.minor, hw_caps->camera_version.incr,
  784. hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
  785. hw_caps->cpas_version.incr, hw_caps->camera_capability);
  786. return rc;
  787. error_hw_remove:
  788. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  789. error_destroy_mem:
  790. mutex_destroy(&g_cpas_intf->intf_lock);
  791. kfree(g_cpas_intf);
  792. g_cpas_intf = NULL;
  793. CAM_ERR(CAM_CPAS, "CPAS component bind failed");
  794. return rc;
  795. }
  796. static void cam_cpas_dev_component_unbind(struct device *dev,
  797. struct device *master_dev, void *data)
  798. {
  799. if (!CAM_CPAS_INTF_INITIALIZED()) {
  800. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  801. return;
  802. }
  803. mutex_lock(&g_cpas_intf->intf_lock);
  804. g_cpas_intf->probe_done = false;
  805. cam_unregister_subdev(&g_cpas_intf->subdev);
  806. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  807. mutex_unlock(&g_cpas_intf->intf_lock);
  808. mutex_destroy(&g_cpas_intf->intf_lock);
  809. kfree(g_cpas_intf);
  810. g_cpas_intf = NULL;
  811. }
  812. const static struct component_ops cam_cpas_dev_component_ops = {
  813. .bind = cam_cpas_dev_component_bind,
  814. .unbind = cam_cpas_dev_component_unbind,
  815. };
  816. static int cam_cpas_dev_probe(struct platform_device *pdev)
  817. {
  818. int rc = 0;
  819. CAM_DBG(CAM_CPAS, "Adding CPAS INTF component");
  820. rc = component_add(&pdev->dev, &cam_cpas_dev_component_ops);
  821. if (rc)
  822. CAM_ERR(CAM_CPAS, "failed to add component rc: %d", rc);
  823. return rc;
  824. }
  825. static int cam_cpas_dev_remove(struct platform_device *pdev)
  826. {
  827. component_del(&pdev->dev, &cam_cpas_dev_component_ops);
  828. return 0;
  829. }
  830. static const struct of_device_id cam_cpas_dt_match[] = {
  831. {.compatible = "qcom,cam-cpas"},
  832. {}
  833. };
  834. struct platform_driver cam_cpas_driver = {
  835. .probe = cam_cpas_dev_probe,
  836. .remove = cam_cpas_dev_remove,
  837. .driver = {
  838. .name = CAM_CPAS_DEV_NAME,
  839. .owner = THIS_MODULE,
  840. .of_match_table = cam_cpas_dt_match,
  841. .suppress_bind_attrs = true,
  842. },
  843. };
  844. int cam_cpas_dev_init_module(void)
  845. {
  846. return platform_driver_register(&cam_cpas_driver);
  847. }
  848. void cam_cpas_dev_exit_module(void)
  849. {
  850. platform_driver_unregister(&cam_cpas_driver);
  851. }
  852. MODULE_DESCRIPTION("MSM CPAS driver");
  853. MODULE_LICENSE("GPL v2");