cam_cdm_util.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/types.h>
  6. #include <linux/kernel.h>
  7. #include <linux/errno.h>
  8. #include <linux/bug.h>
  9. #include "cam_cdm_intf_api.h"
  10. #include "cam_cdm_util.h"
  11. #include "cam_cdm.h"
  12. #include "cam_io_util.h"
  13. #define CAM_CDM_DWORD 4
  14. #define CAM_CDM_SW_CMD_COUNT 2
  15. #define CAM_CMD_LENGTH_MASK 0xFFFF
  16. #define CAM_CDM_COMMAND_OFFSET 24
  17. #define CAM_CDM_REG_OFFSET_MASK 0x00FFFFFF
  18. #define CAM_CDM_DMI_DATA_HI_OFFSET 8
  19. #define CAM_CDM_DMI_DATA_OFFSET 8
  20. #define CAM_CDM_DMI_DATA_LO_OFFSET 12
  21. static unsigned int CDMCmdHeaderSizes[
  22. CAM_CDM_CMD_PRIVATE_BASE + CAM_CDM_SW_CMD_COUNT] = {
  23. 0, /* UNUSED*/
  24. 3, /* DMI*/
  25. 0, /* UNUSED*/
  26. 2, /* RegContinuous*/
  27. 1, /* RegRandom*/
  28. 2, /* BUFFER_INDIREC*/
  29. 2, /* GenerateIRQ*/
  30. 3, /* WaitForEvent*/
  31. 1, /* ChangeBase*/
  32. 1, /* PERF_CONTROL*/
  33. 3, /* DMI32*/
  34. 3, /* DMI64*/
  35. 3, /* WaitCompEvent*/
  36. 3, /* ClearCompEvent*/
  37. 3, /* WaitPrefetchDisable*/
  38. };
  39. /**
  40. * struct cdm_regrandom_cmd - Definition for CDM random register command.
  41. * @count: Number of register writes
  42. * @reserved: reserved bits
  43. * @cmd: Command ID (CDMCmd)
  44. */
  45. struct cdm_regrandom_cmd {
  46. unsigned int count : 16;
  47. unsigned int reserved : 8;
  48. unsigned int cmd : 8;
  49. } __attribute__((__packed__));
  50. /**
  51. * struct cdm_regcontinuous_cmd - Definition for a CDM register range command.
  52. * @count: Number of register writes
  53. * @reserved0: reserved bits
  54. * @cmd: Command ID (CDMCmd)
  55. * @offset: Start address of the range of registers
  56. * @reserved1: reserved bits
  57. */
  58. struct cdm_regcontinuous_cmd {
  59. unsigned int count : 16;
  60. unsigned int reserved0 : 8;
  61. unsigned int cmd : 8;
  62. unsigned int offset : 24;
  63. unsigned int reserved1 : 8;
  64. } __attribute__((__packed__));
  65. /**
  66. * struct cdm_dmi_cmd - Definition for a CDM DMI command.
  67. * @length: Number of bytes in LUT - 1
  68. * @reserved: reserved bits
  69. * @cmd: Command ID (CDMCmd)
  70. * @addr: Address of the LUT in memory
  71. * @DMIAddr: Address of the target DMI config register
  72. * @DMISel: DMI identifier
  73. */
  74. struct cdm_dmi_cmd {
  75. unsigned int length : 16;
  76. unsigned int reserved : 8;
  77. unsigned int cmd : 8;
  78. unsigned int addr;
  79. unsigned int DMIAddr : 24;
  80. unsigned int DMISel : 8;
  81. } __attribute__((__packed__));
  82. /**
  83. * struct cdm_indirect_cmd - Definition for a CDM indirect buffer command.
  84. * @length: Number of bytes in buffer - 1
  85. * @reserved: reserved bits
  86. * @cmd: Command ID (CDMCmd)
  87. * @addr: Device address of the indirect buffer
  88. */
  89. struct cdm_indirect_cmd {
  90. unsigned int length : 16;
  91. unsigned int reserved : 8;
  92. unsigned int cmd : 8;
  93. unsigned int addr;
  94. } __attribute__((__packed__));
  95. /**
  96. * struct cdm_changebase_cmd - Definition for CDM base address change command.
  97. * @base: Base address to be changed to
  98. * @cmd:Command ID (CDMCmd)
  99. */
  100. struct cdm_changebase_cmd {
  101. unsigned int base : 24;
  102. unsigned int cmd : 8;
  103. } __attribute__((__packed__));
  104. /**
  105. * struct cdm_wait_event_cmd - Definition for a CDM Gen IRQ command.
  106. * @mask: Mask for the events
  107. * @id: ID to read back for debug
  108. * @iw_reserved: reserved bits
  109. * @iw: iw AHB write bit
  110. * @cmd:Command ID (CDMCmd)
  111. * @offset: Offset to where data is written
  112. * @offset_reserved: reserved bits
  113. * @data: data returned in IRQ_USR_DATA
  114. */
  115. struct cdm_wait_event_cmd {
  116. unsigned int mask : 8;
  117. unsigned int id : 8;
  118. unsigned int iw_reserved : 7;
  119. unsigned int iw : 1;
  120. unsigned int cmd : 8;
  121. unsigned int offset : 24;
  122. unsigned int offset_reserved : 8;
  123. unsigned int data;
  124. } __attribute__((__packed__));
  125. /**
  126. * struct cdm_genirq_cmd - Definition for a CDM Wait event command.
  127. * @reserved: reserved bits
  128. * @cmd:Command ID (CDMCmd)
  129. * @userdata: userdata returned in IRQ_USR_DATA
  130. */
  131. struct cdm_genirq_cmd {
  132. unsigned int reserved : 24;
  133. unsigned int cmd : 8;
  134. unsigned int userdata;
  135. } __attribute__((__packed__));
  136. /**
  137. * struct cdm_perf_ctrl_cmd_t - Definition for CDM perf control command.
  138. * @perf: perf command
  139. * @reserved: reserved bits
  140. * @cmd:Command ID (CDMCmd)
  141. */
  142. struct cdm_perf_ctrl_cmd {
  143. unsigned int perf : 2;
  144. unsigned int reserved : 22;
  145. unsigned int cmd : 8;
  146. } __attribute__((__packed__));
  147. struct cdm_wait_comp_event_cmd {
  148. unsigned int reserved : 8;
  149. unsigned int id : 8;
  150. unsigned int id_reserved: 8;
  151. unsigned int cmd : 8;
  152. unsigned int mask1;
  153. unsigned int mask2;
  154. } __attribute__((__packed__));
  155. struct cdm_prefetch_disable_event_cmd {
  156. unsigned int reserved : 8;
  157. unsigned int id : 8;
  158. unsigned int id_reserved: 8;
  159. unsigned int cmd : 8;
  160. unsigned int mask1;
  161. unsigned int mask2;
  162. } __attribute__((__packed__));
  163. uint32_t cdm_get_cmd_header_size(unsigned int command)
  164. {
  165. return CDMCmdHeaderSizes[command];
  166. }
  167. uint32_t cdm_required_size_dmi(void)
  168. {
  169. return cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
  170. }
  171. uint32_t cdm_required_size_reg_continuous(uint32_t numVals)
  172. {
  173. return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT) + numVals;
  174. }
  175. uint32_t cdm_required_size_reg_random(uint32_t numRegVals)
  176. {
  177. return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM) +
  178. (2 * numRegVals);
  179. }
  180. uint32_t cdm_required_size_indirect(void)
  181. {
  182. return cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT);
  183. }
  184. uint32_t cdm_required_size_genirq(void)
  185. {
  186. return cdm_get_cmd_header_size(CAM_CDM_CMD_GEN_IRQ);
  187. }
  188. uint32_t cdm_required_size_wait_event(void)
  189. {
  190. return cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT);
  191. }
  192. uint32_t cdm_required_size_changebase(void)
  193. {
  194. return cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE);
  195. }
  196. uint32_t cdm_required_size_comp_wait(void)
  197. {
  198. return cdm_get_cmd_header_size(CAM_CDM_COMP_WAIT);
  199. }
  200. uint32_t cdm_required_size_prefetch_disable(void)
  201. {
  202. return cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE);
  203. }
  204. uint32_t cdm_offsetof_dmi_addr(void)
  205. {
  206. return offsetof(struct cdm_dmi_cmd, addr);
  207. }
  208. uint32_t cdm_offsetof_indirect_addr(void)
  209. {
  210. return offsetof(struct cdm_indirect_cmd, addr);
  211. }
  212. uint32_t *cdm_write_dmi(uint32_t *pCmdBuffer, uint8_t dmiCmd,
  213. uint32_t DMIAddr, uint8_t DMISel, uint32_t dmiBufferAddr,
  214. uint32_t length)
  215. {
  216. struct cdm_dmi_cmd *pHeader = (struct cdm_dmi_cmd *)pCmdBuffer;
  217. pHeader->cmd = CAM_CDM_CMD_DMI;
  218. pHeader->addr = dmiBufferAddr;
  219. pHeader->length = length;
  220. pHeader->DMIAddr = DMIAddr;
  221. pHeader->DMISel = DMISel;
  222. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
  223. return pCmdBuffer;
  224. }
  225. uint32_t *cdm_write_regcontinuous(uint32_t *pCmdBuffer, uint32_t reg,
  226. uint32_t numVals, uint32_t *pVals)
  227. {
  228. uint32_t i;
  229. struct cdm_regcontinuous_cmd *pHeader =
  230. (struct cdm_regcontinuous_cmd *)pCmdBuffer;
  231. pHeader->count = numVals;
  232. pHeader->cmd = CAM_CDM_CMD_REG_CONT;
  233. pHeader->reserved0 = 0;
  234. pHeader->reserved1 = 0;
  235. pHeader->offset = reg;
  236. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  237. for (i = 0; i < numVals; i++)
  238. (((uint32_t *)pCmdBuffer)[i]) = (((uint32_t *)pVals)[i]);
  239. pCmdBuffer += numVals;
  240. return pCmdBuffer;
  241. }
  242. uint32_t *cdm_write_regrandom(uint32_t *pCmdBuffer, uint32_t numRegVals,
  243. uint32_t *pRegVals)
  244. {
  245. uint32_t i;
  246. uint32_t *dst, *src;
  247. struct cdm_regrandom_cmd *pHeader =
  248. (struct cdm_regrandom_cmd *)pCmdBuffer;
  249. pHeader->count = numRegVals;
  250. pHeader->cmd = CAM_CDM_CMD_REG_RANDOM;
  251. pHeader->reserved = 0;
  252. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  253. dst = pCmdBuffer;
  254. src = pRegVals;
  255. for (i = 0; i < numRegVals; i++) {
  256. *dst++ = *src++;
  257. *dst++ = *src++;
  258. }
  259. return dst;
  260. }
  261. uint32_t *cdm_write_indirect(uint32_t *pCmdBuffer, uint32_t indirectBufAddr,
  262. uint32_t length)
  263. {
  264. struct cdm_indirect_cmd *pHeader =
  265. (struct cdm_indirect_cmd *)pCmdBuffer;
  266. pHeader->cmd = CAM_CDM_CMD_BUFF_INDIRECT;
  267. pHeader->addr = indirectBufAddr;
  268. pHeader->length = length - 1;
  269. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT);
  270. return pCmdBuffer;
  271. }
  272. void cdm_write_genirq(uint32_t *pCmdBuffer, uint32_t userdata,
  273. bool bit_wr_enable, uint32_t fifo_idx)
  274. {
  275. struct cdm_genirq_cmd *pHeader = (struct cdm_genirq_cmd *)pCmdBuffer;
  276. CAM_DBG(CAM_CDM, "userdata 0x%x, fifo_idx %d",
  277. userdata, fifo_idx);
  278. if (bit_wr_enable)
  279. pHeader->reserved = (unsigned int)((fifo_idx << 1)
  280. | (unsigned int)(bit_wr_enable));
  281. pHeader->cmd = CAM_CDM_CMD_GEN_IRQ;
  282. pHeader->userdata = (userdata << (8 * fifo_idx));
  283. }
  284. uint32_t *cdm_write_wait_event(uint32_t *pcmdbuffer, uint32_t iw,
  285. uint32_t id, uint32_t mask,
  286. uint32_t offset, uint32_t data)
  287. {
  288. struct cdm_wait_event_cmd *pheader =
  289. (struct cdm_wait_event_cmd *)pcmdbuffer;
  290. pheader->cmd = CAM_CDM_CMD_WAIT_EVENT;
  291. pheader->mask = mask;
  292. pheader->data = data;
  293. pheader->id = id;
  294. pheader->iw = iw;
  295. pheader->offset = offset;
  296. pheader->iw_reserved = 0;
  297. pheader->offset_reserved = 0;
  298. pcmdbuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT);
  299. return pcmdbuffer;
  300. }
  301. uint32_t *cdm_write_changebase(uint32_t *pCmdBuffer, uint32_t base)
  302. {
  303. struct cdm_changebase_cmd *pHeader =
  304. (struct cdm_changebase_cmd *)pCmdBuffer;
  305. CAM_DBG(CAM_CDM, "Change to base 0x%x", base);
  306. pHeader->cmd = CAM_CDM_CMD_CHANGE_BASE;
  307. pHeader->base = base;
  308. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE);
  309. return pCmdBuffer;
  310. }
  311. uint32_t *cdm_write_wait_comp_event(
  312. uint32_t *pCmdBuffer, uint32_t mask1, uint32_t mask2)
  313. {
  314. struct cdm_wait_comp_event_cmd *pHeader =
  315. (struct cdm_wait_comp_event_cmd *)pCmdBuffer;
  316. pHeader->cmd = CAM_CDM_COMP_WAIT;
  317. pHeader->mask1 = mask1;
  318. pHeader->mask2 = mask2;
  319. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_COMP_WAIT);
  320. return pCmdBuffer;
  321. }
  322. uint32_t *cdm_write_wait_prefetch_disable(
  323. uint32_t *pCmdBuffer,
  324. uint32_t id,
  325. uint32_t mask1,
  326. uint32_t mask2)
  327. {
  328. struct cdm_prefetch_disable_event_cmd *pHeader =
  329. (struct cdm_prefetch_disable_event_cmd *)pCmdBuffer;
  330. pHeader->cmd = CAM_CDM_WAIT_PREFETCH_DISABLE;
  331. pHeader->id = id;
  332. pHeader->mask1 = mask1;
  333. pHeader->mask2 = mask2;
  334. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE);
  335. return pCmdBuffer;
  336. }
  337. struct cam_cdm_utils_ops CDM170_ops = {
  338. cdm_get_cmd_header_size,
  339. cdm_required_size_dmi,
  340. cdm_required_size_reg_continuous,
  341. cdm_required_size_reg_random,
  342. cdm_required_size_indirect,
  343. cdm_required_size_genirq,
  344. cdm_required_size_wait_event,
  345. cdm_required_size_changebase,
  346. cdm_required_size_comp_wait,
  347. cdm_required_size_prefetch_disable,
  348. cdm_offsetof_dmi_addr,
  349. cdm_offsetof_indirect_addr,
  350. cdm_write_dmi,
  351. cdm_write_regcontinuous,
  352. cdm_write_regrandom,
  353. cdm_write_indirect,
  354. cdm_write_genirq,
  355. cdm_write_wait_event,
  356. cdm_write_changebase,
  357. cdm_write_wait_comp_event,
  358. cdm_write_wait_prefetch_disable,
  359. };
  360. int cam_cdm_get_ioremap_from_base(uint32_t hw_base,
  361. uint32_t base_array_size,
  362. struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK],
  363. void __iomem **device_base)
  364. {
  365. int ret = -EINVAL, i;
  366. for (i = 0; i < base_array_size; i++) {
  367. if (base_table[i])
  368. CAM_DBG(CAM_CDM, "In loop %d ioremap for %x addr=%x",
  369. i, (base_table[i])->mem_cam_base, hw_base);
  370. if ((base_table[i]) &&
  371. ((base_table[i])->mem_cam_base == hw_base)) {
  372. *device_base = (base_table[i])->mem_base;
  373. ret = 0;
  374. break;
  375. }
  376. }
  377. return ret;
  378. }
  379. static int cam_cdm_util_reg_cont_write(void __iomem *base_addr,
  380. uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes)
  381. {
  382. int ret = 0;
  383. uint32_t *data;
  384. struct cdm_regcontinuous_cmd *reg_cont;
  385. if ((cmd_buf_size < cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) ||
  386. (!base_addr)) {
  387. CAM_ERR(CAM_CDM, "invalid base addr and data length %d %pK",
  388. cmd_buf_size, base_addr);
  389. return -EINVAL;
  390. }
  391. reg_cont = (struct cdm_regcontinuous_cmd *)cmd_buf;
  392. if ((!reg_cont->count) || (reg_cont->count > 0x10000) ||
  393. (((reg_cont->count * sizeof(uint32_t)) +
  394. cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) >
  395. cmd_buf_size)) {
  396. CAM_ERR(CAM_CDM, "buffer size %d is not sufficient for count%d",
  397. cmd_buf_size, reg_cont->count);
  398. return -EINVAL;
  399. }
  400. data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  401. cam_io_memcpy(base_addr + reg_cont->offset, data,
  402. reg_cont->count * sizeof(uint32_t));
  403. *used_bytes = (reg_cont->count * sizeof(uint32_t)) +
  404. (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT));
  405. return ret;
  406. }
  407. static int cam_cdm_util_reg_random_write(void __iomem *base_addr,
  408. uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes)
  409. {
  410. uint32_t i;
  411. struct cdm_regrandom_cmd *reg_random;
  412. uint32_t *data;
  413. if (!base_addr) {
  414. CAM_ERR(CAM_CDM, "invalid base address");
  415. return -EINVAL;
  416. }
  417. reg_random = (struct cdm_regrandom_cmd *) cmd_buf;
  418. if ((!reg_random->count) || (reg_random->count > 0x10000) ||
  419. (((reg_random->count * (sizeof(uint32_t) * 2)) +
  420. cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)) >
  421. cmd_buf_size)) {
  422. CAM_ERR(CAM_CDM, "invalid reg_count %d cmd_buf_size %d",
  423. reg_random->count, cmd_buf_size);
  424. return -EINVAL;
  425. }
  426. data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  427. for (i = 0; i < reg_random->count; i++) {
  428. CAM_DBG(CAM_CDM, "reg random: offset %pK, value 0x%x",
  429. ((void __iomem *)(base_addr + data[0])),
  430. data[1]);
  431. cam_io_w(data[1], base_addr + data[0]);
  432. data += 2;
  433. }
  434. *used_bytes = ((reg_random->count * (sizeof(uint32_t) * 2)) +
  435. (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)));
  436. return 0;
  437. }
  438. static int cam_cdm_util_swd_dmi_write(uint32_t cdm_cmd_type,
  439. void __iomem *base_addr, uint32_t *cmd_buf, uint32_t cmd_buf_size,
  440. uint32_t *used_bytes)
  441. {
  442. uint32_t i;
  443. struct cdm_dmi_cmd *swd_dmi;
  444. uint32_t *data;
  445. swd_dmi = (struct cdm_dmi_cmd *)cmd_buf;
  446. if (cmd_buf_size < (cdm_required_size_dmi() + swd_dmi->length + 1)) {
  447. CAM_ERR(CAM_CDM, "invalid CDM_SWD_DMI length %d",
  448. swd_dmi->length + 1);
  449. return -EINVAL;
  450. }
  451. data = cmd_buf + cdm_required_size_dmi();
  452. if (cdm_cmd_type == CAM_CDM_CMD_SWD_DMI_64) {
  453. for (i = 0; i < (swd_dmi->length + 1)/8; i++) {
  454. cam_io_w_mb(data[0], base_addr +
  455. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET);
  456. cam_io_w_mb(data[1], base_addr +
  457. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_HI_OFFSET);
  458. data += 2;
  459. }
  460. } else if (cdm_cmd_type == CAM_CDM_CMD_DMI) {
  461. for (i = 0; i < (swd_dmi->length + 1)/4; i++) {
  462. cam_io_w_mb(data[0], base_addr +
  463. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_OFFSET);
  464. data += 1;
  465. }
  466. } else {
  467. for (i = 0; i < (swd_dmi->length + 1)/4; i++) {
  468. cam_io_w_mb(data[0], base_addr +
  469. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET);
  470. data += 1;
  471. }
  472. }
  473. *used_bytes = (4 * cdm_required_size_dmi()) + swd_dmi->length + 1;
  474. return 0;
  475. }
  476. int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base,
  477. uint32_t *cmd_buf, uint32_t cmd_buf_size,
  478. struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK],
  479. uint32_t base_array_size, uint8_t bl_tag)
  480. {
  481. int ret = 0;
  482. uint32_t cdm_cmd_type = 0, total_cmd_buf_size = 0;
  483. uint32_t used_bytes = 0;
  484. total_cmd_buf_size = cmd_buf_size;
  485. while (cmd_buf_size > 0) {
  486. CAM_DBG(CAM_CDM, "cmd data=%x", *cmd_buf);
  487. cdm_cmd_type = (*cmd_buf >> CAM_CDM_COMMAND_OFFSET);
  488. switch (cdm_cmd_type) {
  489. case CAM_CDM_CMD_REG_CONT: {
  490. ret = cam_cdm_util_reg_cont_write(*current_device_base,
  491. cmd_buf, cmd_buf_size, &used_bytes);
  492. if (ret)
  493. break;
  494. if (used_bytes > 0) {
  495. cmd_buf_size -= used_bytes;
  496. cmd_buf += used_bytes/4;
  497. }
  498. }
  499. break;
  500. case CAM_CDM_CMD_REG_RANDOM: {
  501. ret = cam_cdm_util_reg_random_write(
  502. *current_device_base, cmd_buf, cmd_buf_size,
  503. &used_bytes);
  504. if (ret)
  505. break;
  506. if (used_bytes > 0) {
  507. cmd_buf_size -= used_bytes;
  508. cmd_buf += used_bytes / 4;
  509. }
  510. }
  511. break;
  512. case CAM_CDM_CMD_DMI:
  513. case CAM_CDM_CMD_SWD_DMI_32:
  514. case CAM_CDM_CMD_SWD_DMI_64: {
  515. if (*current_device_base == 0) {
  516. CAM_ERR(CAM_CDM,
  517. "Got SWI DMI cmd =%d for invalid hw",
  518. cdm_cmd_type);
  519. ret = -EINVAL;
  520. break;
  521. }
  522. ret = cam_cdm_util_swd_dmi_write(cdm_cmd_type,
  523. *current_device_base, cmd_buf, cmd_buf_size,
  524. &used_bytes);
  525. if (ret)
  526. break;
  527. if (used_bytes > 0) {
  528. cmd_buf_size -= used_bytes;
  529. cmd_buf += used_bytes / 4;
  530. }
  531. }
  532. break;
  533. case CAM_CDM_CMD_CHANGE_BASE: {
  534. struct cdm_changebase_cmd *change_base_cmd =
  535. (struct cdm_changebase_cmd *)cmd_buf;
  536. ret = cam_cdm_get_ioremap_from_base(
  537. change_base_cmd->base, base_array_size,
  538. base_table, current_device_base);
  539. if (ret != 0) {
  540. CAM_ERR(CAM_CDM,
  541. "Get ioremap change base failed %x",
  542. change_base_cmd->base);
  543. break;
  544. }
  545. CAM_DBG(CAM_CDM, "Got ioremap for %x addr=%pK",
  546. change_base_cmd->base,
  547. current_device_base);
  548. cmd_buf_size -= (4 *
  549. cdm_required_size_changebase());
  550. cmd_buf += cdm_required_size_changebase();
  551. }
  552. break;
  553. default:
  554. CAM_ERR(CAM_CDM, "unsupported cdm_cmd_type type 0%x",
  555. cdm_cmd_type);
  556. ret = -EINVAL;
  557. break;
  558. }
  559. if (ret < 0)
  560. break;
  561. }
  562. return ret;
  563. }
  564. static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr)
  565. {
  566. long ret = 0;
  567. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI];
  568. CAM_INFO(CAM_CDM, "DMI");
  569. return ret;
  570. }
  571. static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr)
  572. {
  573. long ret = 0;
  574. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT];
  575. CAM_INFO(CAM_CDM, "Buff Indirect");
  576. return ret;
  577. }
  578. static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr)
  579. {
  580. long ret = 0;
  581. struct cdm_regcontinuous_cmd *p_regcont_cmd;
  582. uint32_t *temp_ptr = cmd_buf_addr;
  583. int i = 0;
  584. p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr;
  585. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT];
  586. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT];
  587. CAM_INFO(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X",
  588. p_regcont_cmd->count, p_regcont_cmd->offset);
  589. for (i = 0; i < p_regcont_cmd->count; i++) {
  590. CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i,
  591. *temp_ptr);
  592. temp_ptr++;
  593. ret++;
  594. }
  595. return ret;
  596. }
  597. static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr)
  598. {
  599. struct cdm_regrandom_cmd *p_regrand_cmd;
  600. uint32_t *temp_ptr = cmd_buf_addr;
  601. long ret = 0;
  602. int i = 0;
  603. p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr;
  604. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM];
  605. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM];
  606. CAM_INFO(CAM_CDM, "REG_RAND: COUNT: %u",
  607. p_regrand_cmd->count);
  608. for (i = 0; i < p_regrand_cmd->count; i++) {
  609. CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X",
  610. i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i,
  611. *(temp_ptr + 1));
  612. temp_ptr += 2;
  613. ret += 2;
  614. }
  615. return ret;
  616. }
  617. static long cam_cdm_util_dump_gen_irq_cmd(uint32_t *cmd_buf_addr)
  618. {
  619. long ret = 0;
  620. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ];
  621. CAM_INFO(CAM_CDM, "GEN_IRQ");
  622. return ret;
  623. }
  624. static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr)
  625. {
  626. long ret = 0;
  627. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT];
  628. CAM_INFO(CAM_CDM, "WAIT_EVENT");
  629. return ret;
  630. }
  631. static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr)
  632. {
  633. long ret = 0;
  634. struct cdm_changebase_cmd *p_cbase_cmd;
  635. uint32_t *temp_ptr = cmd_buf_addr;
  636. p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr;
  637. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE];
  638. CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X",
  639. p_cbase_cmd->base);
  640. return ret;
  641. }
  642. static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr)
  643. {
  644. long ret = 0;
  645. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL];
  646. CAM_INFO(CAM_CDM, "PERF_CTRL");
  647. return ret;
  648. }
  649. void cam_cdm_util_dump_cmd_buf(
  650. uint32_t *cmd_buf_start, uint32_t *cmd_buf_end)
  651. {
  652. uint32_t *buf_now = cmd_buf_start;
  653. uint32_t cmd = 0;
  654. if (!cmd_buf_start || !cmd_buf_end) {
  655. CAM_ERR(CAM_CDM, "Invalid args");
  656. return;
  657. }
  658. do {
  659. cmd = *buf_now;
  660. cmd = cmd >> CAM_CDM_COMMAND_OFFSET;
  661. switch (cmd) {
  662. case CAM_CDM_CMD_DMI:
  663. case CAM_CDM_CMD_DMI_32:
  664. case CAM_CDM_CMD_DMI_64:
  665. buf_now += cam_cdm_util_dump_dmi_cmd(buf_now);
  666. break;
  667. case CAM_CDM_CMD_REG_CONT:
  668. buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now);
  669. break;
  670. case CAM_CDM_CMD_REG_RANDOM:
  671. buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now);
  672. break;
  673. case CAM_CDM_CMD_BUFF_INDIRECT:
  674. buf_now += cam_cdm_util_dump_buff_indirect(buf_now);
  675. break;
  676. case CAM_CDM_CMD_GEN_IRQ:
  677. buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now);
  678. break;
  679. case CAM_CDM_CMD_WAIT_EVENT:
  680. buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now);
  681. break;
  682. case CAM_CDM_CMD_CHANGE_BASE:
  683. buf_now += cam_cdm_util_dump_change_base_cmd(buf_now);
  684. break;
  685. case CAM_CDM_CMD_PERF_CTRL:
  686. buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now);
  687. break;
  688. default:
  689. CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x",
  690. cmd, *buf_now);
  691. buf_now++;
  692. break;
  693. }
  694. } while (buf_now <= cmd_buf_end);
  695. }
  696. static uint32_t cam_cdm_util_dump_reg_cont_cmd_v2(
  697. uint32_t *cmd_buf_addr,
  698. struct cam_cdm_cmd_buf_dump_info *dump_info)
  699. {
  700. int i;
  701. long ret;
  702. uint8_t *dst;
  703. size_t remain_len;
  704. uint32_t *temp_ptr = cmd_buf_addr;
  705. uint32_t *addr, *start;
  706. uint32_t min_len;
  707. struct cdm_regcontinuous_cmd *p_regcont_cmd;
  708. struct cam_cdm_cmd_dump_header *hdr;
  709. p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr;
  710. temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  711. ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  712. min_len = (sizeof(uint32_t) * p_regcont_cmd->count) +
  713. sizeof(struct cam_cdm_cmd_dump_header) +
  714. (2 * sizeof(uint32_t));
  715. remain_len = dump_info->dst_max_size - dump_info->dst_offset;
  716. if (remain_len < min_len) {
  717. CAM_WARN_RATE_LIMIT(CAM_CDM,
  718. "Dump buffer exhaust remain %zu min %u",
  719. remain_len, min_len);
  720. return ret;
  721. }
  722. dst = (char *)dump_info->dst_start + dump_info->dst_offset;
  723. hdr = (struct cam_cdm_cmd_dump_header *)dst;
  724. scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_CONT:");
  725. hdr->word_size = sizeof(uint32_t);
  726. addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header));
  727. start = addr;
  728. *addr++ = p_regcont_cmd->offset;
  729. *addr++ = p_regcont_cmd->count;
  730. for (i = 0; i < p_regcont_cmd->count; i++) {
  731. *addr = *temp_ptr;
  732. temp_ptr++;
  733. addr++;
  734. ret++;
  735. }
  736. hdr->size = hdr->word_size * (addr - start);
  737. dump_info->dst_offset += hdr->size +
  738. sizeof(struct cam_cdm_cmd_dump_header);
  739. return ret;
  740. }
  741. static uint32_t cam_cdm_util_dump_reg_random_cmd_v2(
  742. uint32_t *cmd_buf_addr,
  743. struct cam_cdm_cmd_buf_dump_info *dump_info)
  744. {
  745. int i;
  746. long ret;
  747. uint8_t *dst;
  748. uint32_t *temp_ptr = cmd_buf_addr;
  749. uint32_t *addr, *start;
  750. size_t remain_len;
  751. uint32_t min_len;
  752. struct cdm_regrandom_cmd *p_regrand_cmd;
  753. struct cam_cdm_cmd_dump_header *hdr;
  754. p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr;
  755. temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  756. ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  757. min_len = (2 * sizeof(uint32_t) * p_regrand_cmd->count) +
  758. sizeof(struct cam_cdm_cmd_dump_header) + sizeof(uint32_t);
  759. remain_len = dump_info->dst_max_size - dump_info->dst_offset;
  760. if (remain_len < min_len) {
  761. CAM_WARN_RATE_LIMIT(CAM_CDM,
  762. "Dump buffer exhaust remain %zu min %u",
  763. remain_len, min_len);
  764. return ret;
  765. }
  766. dst = (char *)dump_info->dst_start + dump_info->dst_offset;
  767. hdr = (struct cam_cdm_cmd_dump_header *)dst;
  768. scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_RANDOM:");
  769. hdr->word_size = sizeof(uint32_t);
  770. addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header));
  771. start = addr;
  772. *addr++ = p_regrand_cmd->count;
  773. for (i = 0; i < p_regrand_cmd->count; i++) {
  774. addr[0] = temp_ptr[0] & CAM_CDM_REG_OFFSET_MASK;
  775. addr[1] = temp_ptr[1];
  776. temp_ptr += 2;
  777. addr += 2;
  778. ret += 2;
  779. }
  780. hdr->size = hdr->word_size * (addr - start);
  781. dump_info->dst_offset += hdr->size +
  782. sizeof(struct cam_cdm_cmd_dump_header);
  783. return ret;
  784. }
  785. int cam_cdm_util_dump_cmd_bufs_v2(
  786. struct cam_cdm_cmd_buf_dump_info *dump_info)
  787. {
  788. uint32_t cmd;
  789. uint32_t *buf_now;
  790. int rc = 0;
  791. if (!dump_info || !dump_info->src_start || !dump_info->src_end ||
  792. !dump_info->dst_start) {
  793. CAM_INFO(CAM_CDM, "Invalid args");
  794. return -EINVAL;
  795. }
  796. buf_now = dump_info->src_start;
  797. do {
  798. if (dump_info->dst_offset >= dump_info->dst_max_size) {
  799. CAM_WARN(CAM_CDM,
  800. "Dump overshoot offset %zu size %zu",
  801. dump_info->dst_offset,
  802. dump_info->dst_max_size);
  803. return -ENOSPC;
  804. }
  805. cmd = *buf_now;
  806. cmd = cmd >> CAM_CDM_COMMAND_OFFSET;
  807. switch (cmd) {
  808. case CAM_CDM_CMD_DMI:
  809. case CAM_CDM_CMD_DMI_32:
  810. case CAM_CDM_CMD_DMI_64:
  811. buf_now += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
  812. break;
  813. case CAM_CDM_CMD_REG_CONT:
  814. buf_now += cam_cdm_util_dump_reg_cont_cmd_v2(buf_now,
  815. dump_info);
  816. break;
  817. case CAM_CDM_CMD_REG_RANDOM:
  818. buf_now += cam_cdm_util_dump_reg_random_cmd_v2(buf_now,
  819. dump_info);
  820. break;
  821. case CAM_CDM_CMD_BUFF_INDIRECT:
  822. buf_now += cdm_get_cmd_header_size(
  823. CAM_CDM_CMD_BUFF_INDIRECT);
  824. break;
  825. case CAM_CDM_CMD_GEN_IRQ:
  826. buf_now += cdm_get_cmd_header_size(
  827. CAM_CDM_CMD_GEN_IRQ);
  828. break;
  829. case CAM_CDM_CMD_WAIT_EVENT:
  830. buf_now += cdm_get_cmd_header_size(
  831. CAM_CDM_CMD_WAIT_EVENT);
  832. break;
  833. case CAM_CDM_CMD_CHANGE_BASE:
  834. buf_now += cdm_get_cmd_header_size(
  835. CAM_CDM_CMD_CHANGE_BASE);
  836. break;
  837. case CAM_CDM_CMD_PERF_CTRL:
  838. buf_now += cdm_get_cmd_header_size(
  839. CAM_CDM_CMD_PERF_CTRL);
  840. break;
  841. default:
  842. CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x", cmd);
  843. buf_now++;
  844. break;
  845. }
  846. } while (buf_now <= dump_info->src_end);
  847. return rc;
  848. }