cam_cpas_intf.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  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. int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle)
  127. {
  128. int rc;
  129. if (!CAM_CPAS_INTF_INITIALIZED()) {
  130. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  131. return -ENODEV;
  132. }
  133. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  134. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  135. g_cpas_intf->hw_intf->hw_priv,
  136. CAM_CPAS_HW_CMD_DUMP_BUFF_FILL_INFO, &client_handle,
  137. sizeof(uint32_t));
  138. if (rc)
  139. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  140. } else {
  141. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  142. rc = -EINVAL;
  143. }
  144. return rc;
  145. }
  146. EXPORT_SYMBOL(cam_cpas_dump_camnoc_buff_fill_info);
  147. bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
  148. uint32_t *fuse_val)
  149. {
  150. struct cam_hw_info *cpas_hw = NULL;
  151. struct cam_cpas_private_soc *soc_private = NULL;
  152. bool supported = true;
  153. int32_t i;
  154. if (!CAM_CPAS_INTF_INITIALIZED()) {
  155. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  156. return false;
  157. }
  158. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  159. soc_private =
  160. (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
  161. if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) {
  162. CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag);
  163. return false;
  164. }
  165. for (i = 0; i < soc_private->num_feature_info; i++)
  166. if (soc_private->feature_info[i].feature == flag)
  167. break;
  168. if (i == soc_private->num_feature_info) {
  169. CAM_INFO(CAM_CPAS, "Feature not found, no of featues: %d",
  170. soc_private->num_feature_info);
  171. goto end;
  172. }
  173. if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE
  174. || (soc_private->feature_info[i].type ==
  175. CAM_CPAS_FEATURE_TYPE_ENABLE)) {
  176. if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map)
  177. supported = soc_private->feature_info[i].enable;
  178. else
  179. supported = !soc_private->feature_info[i].enable;
  180. } else {
  181. if (!fuse_val) {
  182. CAM_ERR(CAM_CPAS,
  183. "Invalid arg fuse_val");
  184. } else {
  185. *fuse_val = soc_private->feature_info[i].value;
  186. }
  187. }
  188. end:
  189. return supported;
  190. }
  191. EXPORT_SYMBOL(cam_cpas_is_feature_supported);
  192. int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
  193. {
  194. struct cam_hw_info *cpas_hw = NULL;
  195. if (!CAM_CPAS_INTF_INITIALIZED()) {
  196. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  197. return -ENODEV;
  198. }
  199. if (!hw_version) {
  200. CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version);
  201. return -EINVAL;
  202. }
  203. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  204. *hw_version = cpas_hw->soc_info.hw_version;
  205. if (*hw_version == CAM_CPAS_TITAN_NONE) {
  206. CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d",
  207. *hw_version);
  208. }
  209. return 0;
  210. }
  211. int cam_cpas_get_hw_info(uint32_t *camera_family,
  212. struct cam_hw_version *camera_version,
  213. struct cam_hw_version *cpas_version,
  214. uint32_t *cam_caps,
  215. struct cam_cpas_fuse_info *cam_fuse_info)
  216. {
  217. if (!CAM_CPAS_INTF_INITIALIZED()) {
  218. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  219. return -ENODEV;
  220. }
  221. if (!camera_family || !camera_version || !cpas_version || !cam_caps) {
  222. CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK",
  223. camera_family, camera_version, cpas_version, cam_caps);
  224. return -EINVAL;
  225. }
  226. *camera_family = g_cpas_intf->hw_caps.camera_family;
  227. *camera_version = g_cpas_intf->hw_caps.camera_version;
  228. *cpas_version = g_cpas_intf->hw_caps.cpas_version;
  229. *cam_caps = g_cpas_intf->hw_caps.camera_capability;
  230. if (cam_fuse_info)
  231. *cam_fuse_info = g_cpas_intf->hw_caps.fuse_info;
  232. CAM_DBG(CAM_CPAS, "Family %d, version %d.%d cam_caps %d",
  233. *camera_family, camera_version->major,
  234. camera_version->minor, *cam_caps);
  235. return 0;
  236. }
  237. EXPORT_SYMBOL(cam_cpas_get_hw_info);
  238. int cam_cpas_reg_write(uint32_t client_handle,
  239. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  240. uint32_t value)
  241. {
  242. int rc;
  243. if (!CAM_CPAS_INTF_INITIALIZED()) {
  244. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  245. return -ENODEV;
  246. }
  247. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  248. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write;
  249. cmd_reg_write.client_handle = client_handle;
  250. cmd_reg_write.reg_base = reg_base;
  251. cmd_reg_write.offset = offset;
  252. cmd_reg_write.value = value;
  253. cmd_reg_write.mb = mb;
  254. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  255. g_cpas_intf->hw_intf->hw_priv,
  256. CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write,
  257. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  258. if (rc)
  259. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  260. } else {
  261. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  262. rc = -EINVAL;
  263. }
  264. return rc;
  265. }
  266. EXPORT_SYMBOL(cam_cpas_reg_write);
  267. int cam_cpas_reg_read(uint32_t client_handle,
  268. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  269. uint32_t *value)
  270. {
  271. int rc;
  272. if (!CAM_CPAS_INTF_INITIALIZED()) {
  273. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  274. return -ENODEV;
  275. }
  276. if (!value) {
  277. CAM_ERR(CAM_CPAS, "Invalid arg value");
  278. return -EINVAL;
  279. }
  280. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  281. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read;
  282. cmd_reg_read.client_handle = client_handle;
  283. cmd_reg_read.reg_base = reg_base;
  284. cmd_reg_read.offset = offset;
  285. cmd_reg_read.mb = mb;
  286. cmd_reg_read.value = 0;
  287. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  288. g_cpas_intf->hw_intf->hw_priv,
  289. CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read,
  290. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  291. if (rc) {
  292. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  293. return rc;
  294. }
  295. *value = cmd_reg_read.value;
  296. } else {
  297. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  298. rc = -EINVAL;
  299. }
  300. return rc;
  301. }
  302. EXPORT_SYMBOL(cam_cpas_reg_read);
  303. int cam_cpas_update_axi_vote(uint32_t client_handle,
  304. struct cam_axi_vote *axi_vote)
  305. {
  306. int rc;
  307. if (!CAM_CPAS_INTF_INITIALIZED()) {
  308. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  309. return -ENODEV;
  310. }
  311. if (!axi_vote) {
  312. CAM_ERR(CAM_CPAS, "NULL axi vote");
  313. return -EINVAL;
  314. }
  315. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  316. struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote;
  317. cmd_axi_vote.client_handle = client_handle;
  318. cmd_axi_vote.axi_vote = axi_vote;
  319. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  320. g_cpas_intf->hw_intf->hw_priv,
  321. CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote,
  322. sizeof(struct cam_cpas_hw_cmd_axi_vote));
  323. if (rc)
  324. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  325. } else {
  326. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  327. rc = -EINVAL;
  328. }
  329. return rc;
  330. }
  331. EXPORT_SYMBOL(cam_cpas_update_axi_vote);
  332. int cam_cpas_update_ahb_vote(uint32_t client_handle,
  333. struct cam_ahb_vote *ahb_vote)
  334. {
  335. int rc;
  336. if (!CAM_CPAS_INTF_INITIALIZED()) {
  337. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  338. return -ENODEV;
  339. }
  340. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  341. struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote;
  342. cmd_ahb_vote.client_handle = client_handle;
  343. cmd_ahb_vote.ahb_vote = ahb_vote;
  344. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  345. g_cpas_intf->hw_intf->hw_priv,
  346. CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote,
  347. sizeof(struct cam_cpas_hw_cmd_ahb_vote));
  348. if (rc)
  349. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  350. } else {
  351. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  352. rc = -EINVAL;
  353. }
  354. return rc;
  355. }
  356. EXPORT_SYMBOL(cam_cpas_update_ahb_vote);
  357. int cam_cpas_stop(uint32_t client_handle)
  358. {
  359. int rc;
  360. if (!CAM_CPAS_INTF_INITIALIZED()) {
  361. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  362. return -ENODEV;
  363. }
  364. if (g_cpas_intf->hw_intf->hw_ops.stop) {
  365. struct cam_cpas_hw_cmd_stop cmd_hw_stop;
  366. cmd_hw_stop.client_handle = client_handle;
  367. rc = g_cpas_intf->hw_intf->hw_ops.stop(
  368. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop,
  369. sizeof(struct cam_cpas_hw_cmd_stop));
  370. if (rc)
  371. CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc);
  372. } else {
  373. CAM_ERR(CAM_CPAS, "Invalid stop ops");
  374. rc = -EINVAL;
  375. }
  376. return rc;
  377. }
  378. EXPORT_SYMBOL(cam_cpas_stop);
  379. int cam_cpas_start(uint32_t client_handle,
  380. struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote)
  381. {
  382. int rc;
  383. if (!CAM_CPAS_INTF_INITIALIZED()) {
  384. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  385. return -ENODEV;
  386. }
  387. if (!axi_vote) {
  388. CAM_ERR(CAM_CPAS, "NULL axi vote");
  389. return -EINVAL;
  390. }
  391. if (g_cpas_intf->hw_intf->hw_ops.start) {
  392. struct cam_cpas_hw_cmd_start cmd_hw_start;
  393. cmd_hw_start.client_handle = client_handle;
  394. cmd_hw_start.ahb_vote = ahb_vote;
  395. cmd_hw_start.axi_vote = axi_vote;
  396. rc = g_cpas_intf->hw_intf->hw_ops.start(
  397. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start,
  398. sizeof(struct cam_cpas_hw_cmd_start));
  399. if (rc)
  400. CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc);
  401. } else {
  402. CAM_ERR(CAM_CPAS, "Invalid start ops");
  403. rc = -EINVAL;
  404. }
  405. return rc;
  406. }
  407. EXPORT_SYMBOL(cam_cpas_start);
  408. void cam_cpas_log_votes(void)
  409. {
  410. uint32_t dummy_args;
  411. int rc;
  412. if (!CAM_CPAS_INTF_INITIALIZED()) {
  413. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  414. return;
  415. }
  416. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  417. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  418. g_cpas_intf->hw_intf->hw_priv,
  419. CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args,
  420. sizeof(dummy_args));
  421. if (rc)
  422. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  423. } else {
  424. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  425. }
  426. }
  427. EXPORT_SYMBOL(cam_cpas_log_votes);
  428. int cam_cpas_select_qos_settings(uint32_t selection_mask)
  429. {
  430. int rc = 0;
  431. if (!CAM_CPAS_INTF_INITIALIZED()) {
  432. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  433. return -EBADR;
  434. }
  435. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  436. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  437. g_cpas_intf->hw_intf->hw_priv,
  438. CAM_CPAS_HW_CMD_SELECT_QOS, &selection_mask,
  439. sizeof(selection_mask));
  440. if (rc)
  441. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  442. } else {
  443. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  444. rc = -EBADR;
  445. }
  446. return rc;
  447. }
  448. EXPORT_SYMBOL(cam_cpas_select_qos_settings);
  449. int cam_cpas_notify_event(const char *identifier_string,
  450. int32_t identifier_value)
  451. {
  452. int rc = 0;
  453. if (!CAM_CPAS_INTF_INITIALIZED()) {
  454. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  455. return -EBADR;
  456. }
  457. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  458. struct cam_cpas_hw_cmd_notify_event event = { 0 };
  459. event.identifier_string = identifier_string;
  460. event.identifier_value = identifier_value;
  461. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  462. g_cpas_intf->hw_intf->hw_priv,
  463. CAM_CPAS_HW_CMD_LOG_EVENT, &event,
  464. sizeof(event));
  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 = -EBADR;
  470. }
  471. return rc;
  472. }
  473. EXPORT_SYMBOL(cam_cpas_notify_event);
  474. int cam_cpas_unregister_client(uint32_t client_handle)
  475. {
  476. int rc;
  477. if (!CAM_CPAS_INTF_INITIALIZED()) {
  478. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  479. return -ENODEV;
  480. }
  481. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  482. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  483. g_cpas_intf->hw_intf->hw_priv,
  484. CAM_CPAS_HW_CMD_UNREGISTER_CLIENT,
  485. &client_handle, sizeof(uint32_t));
  486. if (rc)
  487. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  488. } else {
  489. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  490. rc = -EINVAL;
  491. }
  492. return rc;
  493. }
  494. EXPORT_SYMBOL(cam_cpas_unregister_client);
  495. int cam_cpas_register_client(
  496. struct cam_cpas_register_params *register_params)
  497. {
  498. int rc;
  499. if (!CAM_CPAS_INTF_INITIALIZED()) {
  500. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  501. return -ENODEV;
  502. }
  503. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  504. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  505. g_cpas_intf->hw_intf->hw_priv,
  506. CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params,
  507. sizeof(struct cam_cpas_register_params));
  508. if (rc)
  509. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  510. } else {
  511. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  512. rc = -EINVAL;
  513. }
  514. return rc;
  515. }
  516. EXPORT_SYMBOL(cam_cpas_register_client);
  517. int cam_cpas_get_scid(
  518. enum cam_sys_cache_config_types type)
  519. {
  520. int rc;
  521. if (!CAM_CPAS_INTF_INITIALIZED()) {
  522. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  523. return -ENODEV;
  524. }
  525. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  526. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  527. g_cpas_intf->hw_intf->hw_priv,
  528. CAM_CPAS_HW_CMD_GET_SCID, &type,
  529. sizeof(type));
  530. } else {
  531. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  532. rc = -EINVAL;
  533. }
  534. return rc;
  535. }
  536. EXPORT_SYMBOL(cam_cpas_get_scid);
  537. int cam_cpas_activate_llcc(
  538. enum cam_sys_cache_config_types type)
  539. {
  540. int rc;
  541. if (!CAM_CPAS_INTF_INITIALIZED()) {
  542. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  543. return -ENODEV;
  544. }
  545. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  546. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  547. g_cpas_intf->hw_intf->hw_priv,
  548. CAM_CPAS_HW_CMD_ACTIVATE_LLC, &type,
  549. sizeof(type));
  550. if (rc)
  551. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  552. } else {
  553. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  554. rc = -EINVAL;
  555. }
  556. return rc;
  557. }
  558. EXPORT_SYMBOL(cam_cpas_activate_llcc);
  559. int cam_cpas_deactivate_llcc(
  560. enum cam_sys_cache_config_types type)
  561. {
  562. int rc;
  563. if (!CAM_CPAS_INTF_INITIALIZED()) {
  564. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  565. return -ENODEV;
  566. }
  567. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  568. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  569. g_cpas_intf->hw_intf->hw_priv,
  570. CAM_CPAS_HW_CMD_DEACTIVATE_LLC, &type,
  571. sizeof(type));
  572. if (rc)
  573. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  574. } else {
  575. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  576. rc = -EINVAL;
  577. }
  578. return rc;
  579. }
  580. EXPORT_SYMBOL(cam_cpas_deactivate_llcc);
  581. int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
  582. struct cam_control *cmd)
  583. {
  584. int rc = 0;
  585. if (!cmd) {
  586. CAM_ERR(CAM_CPAS, "Invalid input cmd");
  587. return -EINVAL;
  588. }
  589. switch (cmd->op_code) {
  590. case CAM_QUERY_CAP: {
  591. struct cam_cpas_query_cap query;
  592. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  593. sizeof(query));
  594. if (rc) {
  595. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  596. rc);
  597. break;
  598. }
  599. rc = cam_cpas_get_hw_info(&query.camera_family,
  600. &query.camera_version, &query.cpas_version,
  601. &query.reserved, NULL);
  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_QUERY_CAP_V2: {
  611. struct cam_cpas_query_cap_v2 query;
  612. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  613. sizeof(query));
  614. if (rc) {
  615. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  616. rc);
  617. break;
  618. }
  619. rc = cam_cpas_get_hw_info(&query.camera_family,
  620. &query.camera_version, &query.cpas_version,
  621. &query.reserved,
  622. &query.fuse_info);
  623. if (rc)
  624. break;
  625. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  626. sizeof(query));
  627. if (rc)
  628. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  629. break;
  630. }
  631. case CAM_SD_SHUTDOWN:
  632. break;
  633. default:
  634. CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code);
  635. rc = -EINVAL;
  636. break;
  637. }
  638. return rc;
  639. }
  640. static int cam_cpas_subdev_open(struct v4l2_subdev *sd,
  641. struct v4l2_subdev_fh *fh)
  642. {
  643. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  644. if (!cpas_intf || !cpas_intf->probe_done) {
  645. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  646. return -ENODEV;
  647. }
  648. mutex_lock(&cpas_intf->intf_lock);
  649. cpas_intf->open_cnt++;
  650. CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt);
  651. mutex_unlock(&cpas_intf->intf_lock);
  652. return 0;
  653. }
  654. static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
  655. struct v4l2_subdev_fh *fh)
  656. {
  657. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  658. if (!cpas_intf || !cpas_intf->probe_done) {
  659. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  660. return -ENODEV;
  661. }
  662. mutex_lock(&cpas_intf->intf_lock);
  663. cpas_intf->open_cnt--;
  664. CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt);
  665. mutex_unlock(&cpas_intf->intf_lock);
  666. return 0;
  667. }
  668. static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
  669. unsigned int cmd, void *arg)
  670. {
  671. int32_t rc;
  672. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  673. if (!cpas_intf || !cpas_intf->probe_done) {
  674. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  675. return -ENODEV;
  676. }
  677. switch (cmd) {
  678. case VIDIOC_CAM_CONTROL:
  679. rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
  680. break;
  681. default:
  682. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  683. rc = -EINVAL;
  684. break;
  685. }
  686. return rc;
  687. }
  688. #ifdef CONFIG_COMPAT
  689. static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
  690. unsigned int cmd, unsigned long arg)
  691. {
  692. struct cam_control cmd_data;
  693. int32_t rc;
  694. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  695. if (!cpas_intf || !cpas_intf->probe_done) {
  696. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  697. return -ENODEV;
  698. }
  699. if (copy_from_user(&cmd_data, (void __user *)arg,
  700. sizeof(cmd_data))) {
  701. CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu",
  702. (void __user *)arg, sizeof(cmd_data));
  703. return -EFAULT;
  704. }
  705. switch (cmd) {
  706. case VIDIOC_CAM_CONTROL:
  707. rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
  708. break;
  709. default:
  710. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  711. rc = -EINVAL;
  712. break;
  713. }
  714. if (!rc) {
  715. if (copy_to_user((void __user *)arg, &cmd_data,
  716. sizeof(cmd_data))) {
  717. CAM_ERR(CAM_CPAS,
  718. "Failed to copy to user_ptr=%pK size=%zu",
  719. (void __user *)arg, sizeof(cmd_data));
  720. rc = -EFAULT;
  721. }
  722. }
  723. return rc;
  724. }
  725. #endif
  726. static struct v4l2_subdev_core_ops cpas_subdev_core_ops = {
  727. .ioctl = cam_cpas_subdev_ioctl,
  728. #ifdef CONFIG_COMPAT
  729. .compat_ioctl32 = cam_cpas_subdev_compat_ioctl,
  730. #endif
  731. };
  732. static const struct v4l2_subdev_ops cpas_subdev_ops = {
  733. .core = &cpas_subdev_core_ops,
  734. };
  735. static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = {
  736. .open = cam_cpas_subdev_open,
  737. .close = cam_cpas_subdev_close,
  738. };
  739. static int cam_cpas_subdev_register(struct platform_device *pdev)
  740. {
  741. int rc;
  742. struct cam_subdev *subdev;
  743. if (!g_cpas_intf)
  744. return -EINVAL;
  745. subdev = &g_cpas_intf->subdev;
  746. subdev->name = CAM_CPAS_DEV_NAME;
  747. subdev->pdev = pdev;
  748. subdev->ops = &cpas_subdev_ops;
  749. subdev->internal_ops = &cpas_subdev_intern_ops;
  750. subdev->token = g_cpas_intf;
  751. subdev->sd_flags =
  752. V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
  753. subdev->ent_function = CAM_CPAS_DEVICE_TYPE;
  754. rc = cam_register_subdev(subdev);
  755. if (rc) {
  756. CAM_ERR(CAM_CPAS, "failed register subdev: %s!",
  757. CAM_CPAS_DEV_NAME);
  758. return rc;
  759. }
  760. platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf);
  761. return rc;
  762. }
  763. static int cam_cpas_dev_component_bind(struct device *dev,
  764. struct device *master_dev, void *data)
  765. {
  766. struct cam_cpas_hw_caps *hw_caps;
  767. struct cam_hw_intf *hw_intf;
  768. int rc;
  769. struct platform_device *pdev = to_platform_device(dev);
  770. if (g_cpas_intf) {
  771. CAM_ERR(CAM_CPAS, "cpas component already binded");
  772. return -EALREADY;
  773. }
  774. g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL);
  775. if (!g_cpas_intf)
  776. return -ENOMEM;
  777. mutex_init(&g_cpas_intf->intf_lock);
  778. g_cpas_intf->pdev = pdev;
  779. rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf);
  780. if (rc || (g_cpas_intf->hw_intf == NULL)) {
  781. CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc);
  782. goto error_destroy_mem;
  783. }
  784. hw_intf = g_cpas_intf->hw_intf;
  785. hw_caps = &g_cpas_intf->hw_caps;
  786. if (hw_intf->hw_ops.get_hw_caps) {
  787. rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv,
  788. hw_caps, sizeof(struct cam_cpas_hw_caps));
  789. if (rc) {
  790. CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc);
  791. goto error_hw_remove;
  792. }
  793. } else {
  794. CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops");
  795. goto error_hw_remove;
  796. }
  797. rc = cam_cpas_subdev_register(pdev);
  798. if (rc)
  799. goto error_hw_remove;
  800. g_cpas_intf->probe_done = true;
  801. CAM_DBG(CAM_CPAS,
  802. "Component bound successfully %d, %d.%d.%d, %d.%d.%d, 0x%x",
  803. hw_caps->camera_family, hw_caps->camera_version.major,
  804. hw_caps->camera_version.minor, hw_caps->camera_version.incr,
  805. hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
  806. hw_caps->cpas_version.incr, hw_caps->camera_capability);
  807. return rc;
  808. error_hw_remove:
  809. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  810. error_destroy_mem:
  811. mutex_destroy(&g_cpas_intf->intf_lock);
  812. kfree(g_cpas_intf);
  813. g_cpas_intf = NULL;
  814. CAM_ERR(CAM_CPAS, "CPAS component bind failed");
  815. return rc;
  816. }
  817. static void cam_cpas_dev_component_unbind(struct device *dev,
  818. struct device *master_dev, void *data)
  819. {
  820. if (!CAM_CPAS_INTF_INITIALIZED()) {
  821. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  822. return;
  823. }
  824. mutex_lock(&g_cpas_intf->intf_lock);
  825. g_cpas_intf->probe_done = false;
  826. cam_unregister_subdev(&g_cpas_intf->subdev);
  827. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  828. mutex_unlock(&g_cpas_intf->intf_lock);
  829. mutex_destroy(&g_cpas_intf->intf_lock);
  830. kfree(g_cpas_intf);
  831. g_cpas_intf = NULL;
  832. }
  833. const static struct component_ops cam_cpas_dev_component_ops = {
  834. .bind = cam_cpas_dev_component_bind,
  835. .unbind = cam_cpas_dev_component_unbind,
  836. };
  837. static int cam_cpas_dev_probe(struct platform_device *pdev)
  838. {
  839. int rc = 0;
  840. CAM_DBG(CAM_CPAS, "Adding CPAS INTF component");
  841. rc = component_add(&pdev->dev, &cam_cpas_dev_component_ops);
  842. if (rc)
  843. CAM_ERR(CAM_CPAS, "failed to add component rc: %d", rc);
  844. return rc;
  845. }
  846. static int cam_cpas_dev_remove(struct platform_device *pdev)
  847. {
  848. component_del(&pdev->dev, &cam_cpas_dev_component_ops);
  849. return 0;
  850. }
  851. static const struct of_device_id cam_cpas_dt_match[] = {
  852. {.compatible = "qcom,cam-cpas"},
  853. {}
  854. };
  855. struct platform_driver cam_cpas_driver = {
  856. .probe = cam_cpas_dev_probe,
  857. .remove = cam_cpas_dev_remove,
  858. .driver = {
  859. .name = CAM_CPAS_DEV_NAME,
  860. .owner = THIS_MODULE,
  861. .of_match_table = cam_cpas_dt_match,
  862. .suppress_bind_attrs = true,
  863. },
  864. };
  865. int cam_cpas_dev_init_module(void)
  866. {
  867. return platform_driver_register(&cam_cpas_driver);
  868. }
  869. void cam_cpas_dev_exit_module(void)
  870. {
  871. platform_driver_unregister(&cam_cpas_driver);
  872. }
  873. MODULE_DESCRIPTION("MSM CPAS driver");
  874. MODULE_LICENSE("GPL v2");