cam_cdm_util.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  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_clear_comp_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. struct cdm_prefetch_disable_event_cmd {
  164. unsigned int reserved : 8;
  165. unsigned int id : 8;
  166. unsigned int id_reserved: 8;
  167. unsigned int cmd : 8;
  168. unsigned int mask1;
  169. unsigned int mask2;
  170. } __attribute__((__packed__));
  171. uint32_t cdm_get_cmd_header_size(unsigned int command)
  172. {
  173. return CDMCmdHeaderSizes[command];
  174. }
  175. uint32_t cdm_required_size_dmi(void)
  176. {
  177. return cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
  178. }
  179. uint32_t cdm_required_size_reg_continuous(uint32_t numVals)
  180. {
  181. return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT) + numVals;
  182. }
  183. uint32_t cdm_required_size_reg_random(uint32_t numRegVals)
  184. {
  185. return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM) +
  186. (2 * numRegVals);
  187. }
  188. uint32_t cdm_required_size_indirect(void)
  189. {
  190. return cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT);
  191. }
  192. uint32_t cdm_required_size_genirq(void)
  193. {
  194. return cdm_get_cmd_header_size(CAM_CDM_CMD_GEN_IRQ);
  195. }
  196. uint32_t cdm_required_size_wait_event(void)
  197. {
  198. return cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT);
  199. }
  200. uint32_t cdm_required_size_changebase(void)
  201. {
  202. return cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE);
  203. }
  204. uint32_t cdm_required_size_comp_wait(void)
  205. {
  206. return cdm_get_cmd_header_size(CAM_CDM_CMD_COMP_WAIT);
  207. }
  208. uint32_t cdm_required_size_clear_comp_event(void)
  209. {
  210. return cdm_get_cmd_header_size(CAM_CDM_CLEAR_COMP_WAIT);
  211. }
  212. uint32_t cdm_required_size_prefetch_disable(void)
  213. {
  214. return cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE);
  215. }
  216. uint32_t cdm_offsetof_dmi_addr(void)
  217. {
  218. return offsetof(struct cdm_dmi_cmd, addr);
  219. }
  220. uint32_t cdm_offsetof_indirect_addr(void)
  221. {
  222. return offsetof(struct cdm_indirect_cmd, addr);
  223. }
  224. uint32_t *cdm_write_dmi(uint32_t *pCmdBuffer, uint8_t dmiCmd,
  225. uint32_t DMIAddr, uint8_t DMISel, uint32_t dmiBufferAddr,
  226. uint32_t length)
  227. {
  228. struct cdm_dmi_cmd *pHeader = (struct cdm_dmi_cmd *)pCmdBuffer;
  229. pHeader->cmd = CAM_CDM_CMD_DMI;
  230. pHeader->addr = dmiBufferAddr;
  231. pHeader->length = length;
  232. pHeader->DMIAddr = DMIAddr;
  233. pHeader->DMISel = DMISel;
  234. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
  235. return pCmdBuffer;
  236. }
  237. uint32_t *cdm_write_regcontinuous(uint32_t *pCmdBuffer, uint32_t reg,
  238. uint32_t numVals, uint32_t *pVals)
  239. {
  240. uint32_t i;
  241. struct cdm_regcontinuous_cmd *pHeader =
  242. (struct cdm_regcontinuous_cmd *)pCmdBuffer;
  243. pHeader->count = numVals;
  244. pHeader->cmd = CAM_CDM_CMD_REG_CONT;
  245. pHeader->reserved0 = 0;
  246. pHeader->reserved1 = 0;
  247. pHeader->offset = reg;
  248. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  249. for (i = 0; i < numVals; i++)
  250. (((uint32_t *)pCmdBuffer)[i]) = (((uint32_t *)pVals)[i]);
  251. pCmdBuffer += numVals;
  252. return pCmdBuffer;
  253. }
  254. uint32_t *cdm_write_regrandom(uint32_t *pCmdBuffer, uint32_t numRegVals,
  255. uint32_t *pRegVals)
  256. {
  257. uint32_t i;
  258. uint32_t *dst, *src;
  259. struct cdm_regrandom_cmd *pHeader =
  260. (struct cdm_regrandom_cmd *)pCmdBuffer;
  261. pHeader->count = numRegVals;
  262. pHeader->cmd = CAM_CDM_CMD_REG_RANDOM;
  263. pHeader->reserved = 0;
  264. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  265. dst = pCmdBuffer;
  266. src = pRegVals;
  267. for (i = 0; i < numRegVals; i++) {
  268. *dst++ = *src++;
  269. *dst++ = *src++;
  270. }
  271. return dst;
  272. }
  273. uint32_t *cdm_write_indirect(uint32_t *pCmdBuffer, uint32_t indirectBufAddr,
  274. uint32_t length)
  275. {
  276. struct cdm_indirect_cmd *pHeader =
  277. (struct cdm_indirect_cmd *)pCmdBuffer;
  278. pHeader->cmd = CAM_CDM_CMD_BUFF_INDIRECT;
  279. pHeader->addr = indirectBufAddr;
  280. pHeader->length = length - 1;
  281. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT);
  282. return pCmdBuffer;
  283. }
  284. void cdm_write_genirq(uint32_t *pCmdBuffer, uint32_t userdata,
  285. bool bit_wr_enable, uint32_t fifo_idx)
  286. {
  287. struct cdm_genirq_cmd *pHeader = (struct cdm_genirq_cmd *)pCmdBuffer;
  288. CAM_DBG(CAM_CDM, "userdata 0x%x, fifo_idx %d",
  289. userdata, fifo_idx);
  290. if (bit_wr_enable)
  291. pHeader->reserved = (unsigned int)((fifo_idx << 1)
  292. | (unsigned int)(bit_wr_enable));
  293. pHeader->cmd = CAM_CDM_CMD_GEN_IRQ;
  294. pHeader->userdata = (userdata << (8 * fifo_idx));
  295. }
  296. uint32_t *cdm_write_wait_event(uint32_t *pcmdbuffer, uint32_t iw,
  297. uint32_t id, uint32_t mask,
  298. uint32_t offset, uint32_t data)
  299. {
  300. struct cdm_wait_event_cmd *pheader =
  301. (struct cdm_wait_event_cmd *)pcmdbuffer;
  302. pheader->cmd = CAM_CDM_CMD_WAIT_EVENT;
  303. pheader->mask = mask;
  304. pheader->data = data;
  305. pheader->id = id;
  306. pheader->iw = iw;
  307. pheader->offset = offset;
  308. pheader->iw_reserved = 0;
  309. pheader->offset_reserved = 0;
  310. pcmdbuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT);
  311. return pcmdbuffer;
  312. }
  313. uint32_t *cdm_write_changebase(uint32_t *pCmdBuffer, uint32_t base)
  314. {
  315. struct cdm_changebase_cmd *pHeader =
  316. (struct cdm_changebase_cmd *)pCmdBuffer;
  317. CAM_DBG(CAM_CDM, "Change to base 0x%x", base);
  318. pHeader->cmd = CAM_CDM_CMD_CHANGE_BASE;
  319. pHeader->base = base;
  320. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE);
  321. return pCmdBuffer;
  322. }
  323. uint32_t *cdm_write_wait_comp_event(
  324. uint32_t *pCmdBuffer, uint32_t mask1, uint32_t mask2)
  325. {
  326. struct cdm_wait_comp_event_cmd *pHeader =
  327. (struct cdm_wait_comp_event_cmd *)pCmdBuffer;
  328. pHeader->cmd = CAM_CDM_CMD_COMP_WAIT;
  329. pHeader->mask1 = mask1;
  330. pHeader->mask2 = mask2;
  331. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_COMP_WAIT);
  332. return pCmdBuffer;
  333. }
  334. uint32_t *cdm_write_clear_comp_event(
  335. uint32_t *pCmdBuffer, uint32_t mask1, uint32_t mask2)
  336. {
  337. struct cdm_clear_comp_event_cmd *pHeader =
  338. (struct cdm_clear_comp_event_cmd *)pCmdBuffer;
  339. pHeader->cmd = CAM_CDM_CLEAR_COMP_WAIT;
  340. pHeader->mask1 = mask1;
  341. pHeader->mask2 = mask2;
  342. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CLEAR_COMP_WAIT);
  343. return pCmdBuffer;
  344. }
  345. uint32_t *cdm_write_wait_prefetch_disable(
  346. uint32_t *pCmdBuffer,
  347. uint32_t id,
  348. uint32_t mask1,
  349. uint32_t mask2)
  350. {
  351. struct cdm_prefetch_disable_event_cmd *pHeader =
  352. (struct cdm_prefetch_disable_event_cmd *)pCmdBuffer;
  353. pHeader->cmd = CAM_CDM_WAIT_PREFETCH_DISABLE;
  354. pHeader->id = id;
  355. pHeader->mask1 = mask1;
  356. pHeader->mask2 = mask2;
  357. pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE);
  358. return pCmdBuffer;
  359. }
  360. struct cam_cdm_utils_ops CDM170_ops = {
  361. cdm_get_cmd_header_size,
  362. cdm_required_size_dmi,
  363. cdm_required_size_reg_continuous,
  364. cdm_required_size_reg_random,
  365. cdm_required_size_indirect,
  366. cdm_required_size_genirq,
  367. cdm_required_size_wait_event,
  368. cdm_required_size_changebase,
  369. cdm_required_size_comp_wait,
  370. cdm_required_size_clear_comp_event,
  371. cdm_required_size_prefetch_disable,
  372. cdm_offsetof_dmi_addr,
  373. cdm_offsetof_indirect_addr,
  374. cdm_write_dmi,
  375. cdm_write_regcontinuous,
  376. cdm_write_regrandom,
  377. cdm_write_indirect,
  378. cdm_write_genirq,
  379. cdm_write_wait_event,
  380. cdm_write_changebase,
  381. cdm_write_wait_comp_event,
  382. cdm_write_clear_comp_event,
  383. cdm_write_wait_prefetch_disable,
  384. };
  385. int cam_cdm_get_ioremap_from_base(uint32_t hw_base,
  386. uint32_t base_array_size,
  387. struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK],
  388. void __iomem **device_base)
  389. {
  390. int ret = -EINVAL, i;
  391. for (i = 0; i < base_array_size; i++) {
  392. if (base_table[i])
  393. CAM_DBG(CAM_CDM, "In loop %d ioremap for %x addr=%x",
  394. i, (base_table[i])->mem_cam_base, hw_base);
  395. if ((base_table[i]) &&
  396. ((base_table[i])->mem_cam_base == hw_base)) {
  397. *device_base = (base_table[i])->mem_base;
  398. ret = 0;
  399. break;
  400. }
  401. }
  402. return ret;
  403. }
  404. static int cam_cdm_util_reg_cont_write(void __iomem *base_addr,
  405. uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes)
  406. {
  407. int ret = 0;
  408. uint32_t *data;
  409. struct cdm_regcontinuous_cmd *reg_cont;
  410. if ((cmd_buf_size < cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) ||
  411. (!base_addr)) {
  412. CAM_ERR(CAM_CDM, "invalid base addr and data length %d %pK",
  413. cmd_buf_size, base_addr);
  414. return -EINVAL;
  415. }
  416. reg_cont = (struct cdm_regcontinuous_cmd *)cmd_buf;
  417. if ((!reg_cont->count) || (reg_cont->count > 0x10000) ||
  418. (((reg_cont->count * sizeof(uint32_t)) +
  419. cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) >
  420. cmd_buf_size)) {
  421. CAM_ERR(CAM_CDM, "buffer size %d is not sufficient for count%d",
  422. cmd_buf_size, reg_cont->count);
  423. return -EINVAL;
  424. }
  425. data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  426. cam_io_memcpy(base_addr + reg_cont->offset, data,
  427. reg_cont->count * sizeof(uint32_t));
  428. *used_bytes = (reg_cont->count * sizeof(uint32_t)) +
  429. (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT));
  430. return ret;
  431. }
  432. static int cam_cdm_util_reg_random_write(void __iomem *base_addr,
  433. uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes)
  434. {
  435. uint32_t i;
  436. struct cdm_regrandom_cmd *reg_random;
  437. uint32_t *data;
  438. if (!base_addr) {
  439. CAM_ERR(CAM_CDM, "invalid base address");
  440. return -EINVAL;
  441. }
  442. reg_random = (struct cdm_regrandom_cmd *) cmd_buf;
  443. if ((!reg_random->count) || (reg_random->count > 0x10000) ||
  444. (((reg_random->count * (sizeof(uint32_t) * 2)) +
  445. cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)) >
  446. cmd_buf_size)) {
  447. CAM_ERR(CAM_CDM, "invalid reg_count %d cmd_buf_size %d",
  448. reg_random->count, cmd_buf_size);
  449. return -EINVAL;
  450. }
  451. data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  452. for (i = 0; i < reg_random->count; i++) {
  453. CAM_DBG(CAM_CDM, "reg random: offset %pK, value 0x%x",
  454. ((void __iomem *)(base_addr + data[0])),
  455. data[1]);
  456. cam_io_w(data[1], base_addr + data[0]);
  457. data += 2;
  458. }
  459. *used_bytes = ((reg_random->count * (sizeof(uint32_t) * 2)) +
  460. (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)));
  461. return 0;
  462. }
  463. static int cam_cdm_util_swd_dmi_write(uint32_t cdm_cmd_type,
  464. void __iomem *base_addr, uint32_t *cmd_buf, uint32_t cmd_buf_size,
  465. uint32_t *used_bytes)
  466. {
  467. uint32_t i;
  468. struct cdm_dmi_cmd *swd_dmi;
  469. uint32_t *data;
  470. swd_dmi = (struct cdm_dmi_cmd *)cmd_buf;
  471. if (cmd_buf_size < (cdm_required_size_dmi() + swd_dmi->length + 1)) {
  472. CAM_ERR(CAM_CDM, "invalid CDM_SWD_DMI length %d",
  473. swd_dmi->length + 1);
  474. return -EINVAL;
  475. }
  476. data = cmd_buf + cdm_required_size_dmi();
  477. if (cdm_cmd_type == CAM_CDM_CMD_SWD_DMI_64) {
  478. for (i = 0; i < (swd_dmi->length + 1)/8; i++) {
  479. cam_io_w_mb(data[0], base_addr +
  480. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET);
  481. cam_io_w_mb(data[1], base_addr +
  482. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_HI_OFFSET);
  483. data += 2;
  484. }
  485. } else if (cdm_cmd_type == CAM_CDM_CMD_DMI) {
  486. for (i = 0; i < (swd_dmi->length + 1)/4; i++) {
  487. cam_io_w_mb(data[0], base_addr +
  488. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_OFFSET);
  489. data += 1;
  490. }
  491. } else {
  492. for (i = 0; i < (swd_dmi->length + 1)/4; i++) {
  493. cam_io_w_mb(data[0], base_addr +
  494. swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET);
  495. data += 1;
  496. }
  497. }
  498. *used_bytes = (4 * cdm_required_size_dmi()) + swd_dmi->length + 1;
  499. return 0;
  500. }
  501. int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base,
  502. uint32_t *cmd_buf, uint32_t cmd_buf_size,
  503. struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK],
  504. uint32_t base_array_size, uint8_t bl_tag)
  505. {
  506. int ret = 0;
  507. uint32_t cdm_cmd_type = 0, total_cmd_buf_size = 0;
  508. uint32_t used_bytes = 0;
  509. total_cmd_buf_size = cmd_buf_size;
  510. while (cmd_buf_size > 0) {
  511. CAM_DBG(CAM_CDM, "cmd data=%x", *cmd_buf);
  512. cdm_cmd_type = (*cmd_buf >> CAM_CDM_COMMAND_OFFSET);
  513. switch (cdm_cmd_type) {
  514. case CAM_CDM_CMD_REG_CONT: {
  515. ret = cam_cdm_util_reg_cont_write(*current_device_base,
  516. cmd_buf, cmd_buf_size, &used_bytes);
  517. if (ret)
  518. break;
  519. if (used_bytes > 0) {
  520. cmd_buf_size -= used_bytes;
  521. cmd_buf += used_bytes/4;
  522. }
  523. }
  524. break;
  525. case CAM_CDM_CMD_REG_RANDOM: {
  526. ret = cam_cdm_util_reg_random_write(
  527. *current_device_base, cmd_buf, cmd_buf_size,
  528. &used_bytes);
  529. if (ret)
  530. break;
  531. if (used_bytes > 0) {
  532. cmd_buf_size -= used_bytes;
  533. cmd_buf += used_bytes / 4;
  534. }
  535. }
  536. break;
  537. case CAM_CDM_CMD_DMI:
  538. case CAM_CDM_CMD_SWD_DMI_32:
  539. case CAM_CDM_CMD_SWD_DMI_64: {
  540. if (*current_device_base == 0) {
  541. CAM_ERR(CAM_CDM,
  542. "Got SWI DMI cmd =%d for invalid hw",
  543. cdm_cmd_type);
  544. ret = -EINVAL;
  545. break;
  546. }
  547. ret = cam_cdm_util_swd_dmi_write(cdm_cmd_type,
  548. *current_device_base, cmd_buf, cmd_buf_size,
  549. &used_bytes);
  550. if (ret)
  551. break;
  552. if (used_bytes > 0) {
  553. cmd_buf_size -= used_bytes;
  554. cmd_buf += used_bytes / 4;
  555. }
  556. }
  557. break;
  558. case CAM_CDM_CMD_CHANGE_BASE: {
  559. struct cdm_changebase_cmd *change_base_cmd =
  560. (struct cdm_changebase_cmd *)cmd_buf;
  561. ret = cam_cdm_get_ioremap_from_base(
  562. change_base_cmd->base, base_array_size,
  563. base_table, current_device_base);
  564. if (ret != 0) {
  565. CAM_ERR(CAM_CDM,
  566. "Get ioremap change base failed %x",
  567. change_base_cmd->base);
  568. break;
  569. }
  570. CAM_DBG(CAM_CDM, "Got ioremap for %x addr=%pK",
  571. change_base_cmd->base,
  572. current_device_base);
  573. cmd_buf_size -= (4 *
  574. cdm_required_size_changebase());
  575. cmd_buf += cdm_required_size_changebase();
  576. }
  577. break;
  578. default:
  579. CAM_ERR(CAM_CDM, "unsupported cdm_cmd_type type 0%x",
  580. cdm_cmd_type);
  581. ret = -EINVAL;
  582. break;
  583. }
  584. if (ret < 0)
  585. break;
  586. }
  587. return ret;
  588. }
  589. static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr,
  590. uint32_t *cmd_buf_addr_end)
  591. {
  592. long ret = 0;
  593. struct cdm_dmi_cmd *p_dmi_cmd;
  594. uint32_t *temp_ptr = cmd_buf_addr;
  595. p_dmi_cmd = (struct cdm_dmi_cmd *)cmd_buf_addr;
  596. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI];
  597. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI];
  598. if (temp_ptr > cmd_buf_addr_end)
  599. CAM_ERR(CAM_CDM,
  600. "Invalid cmd start addr:%pK end addr:%pK",
  601. temp_ptr, cmd_buf_addr_end);
  602. CAM_INFO(CAM_CDM,
  603. "DMI: LEN: %u DMIAddr: 0x%X DMISel: 0x%X LUT_addr: 0x%X",
  604. p_dmi_cmd->length, p_dmi_cmd->DMIAddr,
  605. p_dmi_cmd->DMISel, p_dmi_cmd->addr);
  606. return ret;
  607. }
  608. static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr,
  609. uint32_t *cmd_buf_addr_end)
  610. {
  611. long ret = 0;
  612. struct cdm_indirect_cmd *p_indirect_cmd;
  613. uint32_t *temp_ptr = cmd_buf_addr;
  614. p_indirect_cmd = (struct cdm_indirect_cmd *)cmd_buf_addr;
  615. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT];
  616. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT];
  617. if (temp_ptr > cmd_buf_addr_end)
  618. CAM_ERR(CAM_CDM,
  619. "Invalid cmd start addr:%pK end addr:%pK",
  620. temp_ptr, cmd_buf_addr_end);
  621. CAM_INFO(CAM_CDM,
  622. "Buff Indirect: LEN: %u addr: 0x%X",
  623. p_indirect_cmd->length, p_indirect_cmd->addr);
  624. return ret;
  625. }
  626. static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr,
  627. uint32_t *cmd_buf_addr_end)
  628. {
  629. long ret = 0;
  630. struct cdm_regcontinuous_cmd *p_regcont_cmd;
  631. uint32_t *temp_ptr = cmd_buf_addr;
  632. int i = 0;
  633. p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr;
  634. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT];
  635. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT];
  636. CAM_INFO(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X",
  637. p_regcont_cmd->count, p_regcont_cmd->offset);
  638. for (i = 0; i < p_regcont_cmd->count; i++) {
  639. if (temp_ptr > cmd_buf_addr_end) {
  640. CAM_ERR(CAM_CDM,
  641. "Invalid cmd(%d) start addr:%pK end addr:%pK",
  642. i, temp_ptr, cmd_buf_addr_end);
  643. break;
  644. }
  645. CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i,
  646. *temp_ptr);
  647. temp_ptr++;
  648. ret++;
  649. }
  650. return ret;
  651. }
  652. static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr,
  653. uint32_t *cmd_buf_addr_end)
  654. {
  655. struct cdm_regrandom_cmd *p_regrand_cmd;
  656. uint32_t *temp_ptr = cmd_buf_addr;
  657. long ret = 0;
  658. int i = 0;
  659. p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr;
  660. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM];
  661. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM];
  662. CAM_INFO(CAM_CDM, "REG_RAND: COUNT: %u",
  663. p_regrand_cmd->count);
  664. for (i = 0; i < p_regrand_cmd->count; i++) {
  665. if (temp_ptr > cmd_buf_addr_end) {
  666. CAM_ERR(CAM_CDM,
  667. "Invalid cmd(%d) start addr:%pK end addr:%pK",
  668. i, temp_ptr, cmd_buf_addr_end);
  669. break;
  670. }
  671. CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X",
  672. i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i,
  673. *(temp_ptr + 1));
  674. temp_ptr += 2;
  675. ret += 2;
  676. }
  677. return ret;
  678. }
  679. static long cam_cdm_util_dump_gen_irq_cmd(uint32_t *cmd_buf_addr)
  680. {
  681. long ret = 0;
  682. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ];
  683. CAM_INFO(CAM_CDM, "GEN_IRQ");
  684. return ret;
  685. }
  686. static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr)
  687. {
  688. long ret = 0;
  689. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT];
  690. CAM_INFO(CAM_CDM, "WAIT_EVENT");
  691. return ret;
  692. }
  693. static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr,
  694. uint32_t *cmd_buf_addr_end)
  695. {
  696. long ret = 0;
  697. struct cdm_changebase_cmd *p_cbase_cmd;
  698. uint32_t *temp_ptr = cmd_buf_addr;
  699. p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr;
  700. temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE];
  701. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE];
  702. if (temp_ptr > cmd_buf_addr_end)
  703. CAM_ERR(CAM_CDM,
  704. "Invalid cmd start addr:%pK end addr:%pK",
  705. temp_ptr, cmd_buf_addr_end);
  706. CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X",
  707. p_cbase_cmd->base);
  708. return ret;
  709. }
  710. static long cam_cdm_util_dump_comp_wait_event_cmd(uint32_t *cmd_buf_addr)
  711. {
  712. long ret = 0;
  713. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_COMP_WAIT];
  714. CAM_INFO(CAM_CDM, "WAIT_EVENT");
  715. return ret;
  716. }
  717. static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr)
  718. {
  719. long ret = 0;
  720. ret += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL];
  721. CAM_INFO(CAM_CDM, "PERF_CTRL");
  722. return ret;
  723. }
  724. void cam_cdm_util_dump_cmd_buf(
  725. uint32_t *cmd_buf_start, uint32_t *cmd_buf_end)
  726. {
  727. uint32_t *buf_now = cmd_buf_start;
  728. uint32_t *buf_end = cmd_buf_end;
  729. uint32_t cmd = 0;
  730. if (!cmd_buf_start || !cmd_buf_end) {
  731. CAM_ERR(CAM_CDM, "Invalid args");
  732. return;
  733. }
  734. do {
  735. cmd = *buf_now;
  736. cmd = cmd >> CAM_CDM_COMMAND_OFFSET;
  737. switch (cmd) {
  738. case CAM_CDM_CMD_DMI:
  739. case CAM_CDM_CMD_DMI_32:
  740. case CAM_CDM_CMD_DMI_64:
  741. buf_now += cam_cdm_util_dump_dmi_cmd(buf_now,
  742. buf_end);
  743. break;
  744. case CAM_CDM_CMD_REG_CONT:
  745. buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now,
  746. buf_end);
  747. break;
  748. case CAM_CDM_CMD_REG_RANDOM:
  749. buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now,
  750. buf_end);
  751. break;
  752. case CAM_CDM_CMD_BUFF_INDIRECT:
  753. buf_now += cam_cdm_util_dump_buff_indirect(buf_now,
  754. buf_end);
  755. break;
  756. case CAM_CDM_CMD_GEN_IRQ:
  757. buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now);
  758. break;
  759. case CAM_CDM_CMD_WAIT_EVENT:
  760. buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now);
  761. break;
  762. case CAM_CDM_CMD_CHANGE_BASE:
  763. buf_now += cam_cdm_util_dump_change_base_cmd(buf_now,
  764. buf_end);
  765. break;
  766. case CAM_CDM_CMD_PERF_CTRL:
  767. buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now);
  768. break;
  769. case CAM_CDM_CMD_COMP_WAIT:
  770. buf_now +=
  771. cam_cdm_util_dump_comp_wait_event_cmd(buf_now);
  772. break;
  773. default:
  774. CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x",
  775. cmd, *buf_now);
  776. buf_now++;
  777. break;
  778. }
  779. } while (buf_now <= cmd_buf_end);
  780. }
  781. static uint32_t cam_cdm_util_dump_reg_cont_cmd_v2(
  782. uint32_t *cmd_buf_addr,
  783. struct cam_cdm_cmd_buf_dump_info *dump_info)
  784. {
  785. int i;
  786. long ret;
  787. uint8_t *dst;
  788. size_t remain_len;
  789. uint32_t *temp_ptr = cmd_buf_addr;
  790. uint32_t *addr, *start;
  791. uint32_t min_len;
  792. struct cdm_regcontinuous_cmd *p_regcont_cmd;
  793. struct cam_cdm_cmd_dump_header *hdr;
  794. p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr;
  795. temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  796. ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
  797. min_len = (sizeof(uint32_t) * p_regcont_cmd->count) +
  798. sizeof(struct cam_cdm_cmd_dump_header) +
  799. (2 * sizeof(uint32_t));
  800. remain_len = dump_info->dst_max_size - dump_info->dst_offset;
  801. if (remain_len < min_len) {
  802. CAM_WARN_RATE_LIMIT(CAM_CDM,
  803. "Dump buffer exhaust remain %zu min %u",
  804. remain_len, min_len);
  805. return ret;
  806. }
  807. dst = (char *)dump_info->dst_start + dump_info->dst_offset;
  808. hdr = (struct cam_cdm_cmd_dump_header *)dst;
  809. scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_CONT:");
  810. hdr->word_size = sizeof(uint32_t);
  811. addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header));
  812. start = addr;
  813. *addr++ = p_regcont_cmd->offset;
  814. *addr++ = p_regcont_cmd->count;
  815. for (i = 0; i < p_regcont_cmd->count; i++) {
  816. *addr = *temp_ptr;
  817. temp_ptr++;
  818. addr++;
  819. ret++;
  820. }
  821. hdr->size = hdr->word_size * (addr - start);
  822. dump_info->dst_offset += hdr->size +
  823. sizeof(struct cam_cdm_cmd_dump_header);
  824. return ret;
  825. }
  826. static uint32_t cam_cdm_util_dump_reg_random_cmd_v2(
  827. uint32_t *cmd_buf_addr,
  828. struct cam_cdm_cmd_buf_dump_info *dump_info)
  829. {
  830. int i;
  831. long ret;
  832. uint8_t *dst;
  833. uint32_t *temp_ptr = cmd_buf_addr;
  834. uint32_t *addr, *start;
  835. size_t remain_len;
  836. uint32_t min_len;
  837. struct cdm_regrandom_cmd *p_regrand_cmd;
  838. struct cam_cdm_cmd_dump_header *hdr;
  839. p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr;
  840. temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  841. ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
  842. min_len = (2 * sizeof(uint32_t) * p_regrand_cmd->count) +
  843. sizeof(struct cam_cdm_cmd_dump_header) + sizeof(uint32_t);
  844. remain_len = dump_info->dst_max_size - dump_info->dst_offset;
  845. if (remain_len < min_len) {
  846. CAM_WARN_RATE_LIMIT(CAM_CDM,
  847. "Dump buffer exhaust remain %zu min %u",
  848. remain_len, min_len);
  849. return ret;
  850. }
  851. dst = (char *)dump_info->dst_start + dump_info->dst_offset;
  852. hdr = (struct cam_cdm_cmd_dump_header *)dst;
  853. scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_RANDOM:");
  854. hdr->word_size = sizeof(uint32_t);
  855. addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header));
  856. start = addr;
  857. *addr++ = p_regrand_cmd->count;
  858. for (i = 0; i < p_regrand_cmd->count; i++) {
  859. addr[0] = temp_ptr[0] & CAM_CDM_REG_OFFSET_MASK;
  860. addr[1] = temp_ptr[1];
  861. temp_ptr += 2;
  862. addr += 2;
  863. ret += 2;
  864. }
  865. hdr->size = hdr->word_size * (addr - start);
  866. dump_info->dst_offset += hdr->size +
  867. sizeof(struct cam_cdm_cmd_dump_header);
  868. return ret;
  869. }
  870. int cam_cdm_util_dump_cmd_bufs_v2(
  871. struct cam_cdm_cmd_buf_dump_info *dump_info)
  872. {
  873. uint32_t cmd;
  874. uint32_t *buf_now;
  875. int rc = 0;
  876. if (!dump_info || !dump_info->src_start || !dump_info->src_end ||
  877. !dump_info->dst_start) {
  878. CAM_INFO(CAM_CDM, "Invalid args");
  879. return -EINVAL;
  880. }
  881. buf_now = dump_info->src_start;
  882. do {
  883. if (dump_info->dst_offset >= dump_info->dst_max_size) {
  884. CAM_WARN(CAM_CDM,
  885. "Dump overshoot offset %zu size %zu",
  886. dump_info->dst_offset,
  887. dump_info->dst_max_size);
  888. return -ENOSPC;
  889. }
  890. cmd = *buf_now;
  891. cmd = cmd >> CAM_CDM_COMMAND_OFFSET;
  892. switch (cmd) {
  893. case CAM_CDM_CMD_DMI:
  894. case CAM_CDM_CMD_DMI_32:
  895. case CAM_CDM_CMD_DMI_64:
  896. buf_now += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
  897. break;
  898. case CAM_CDM_CMD_REG_CONT:
  899. buf_now += cam_cdm_util_dump_reg_cont_cmd_v2(buf_now,
  900. dump_info);
  901. break;
  902. case CAM_CDM_CMD_REG_RANDOM:
  903. buf_now += cam_cdm_util_dump_reg_random_cmd_v2(buf_now,
  904. dump_info);
  905. break;
  906. case CAM_CDM_CMD_BUFF_INDIRECT:
  907. buf_now += cdm_get_cmd_header_size(
  908. CAM_CDM_CMD_BUFF_INDIRECT);
  909. break;
  910. case CAM_CDM_CMD_GEN_IRQ:
  911. buf_now += cdm_get_cmd_header_size(
  912. CAM_CDM_CMD_GEN_IRQ);
  913. break;
  914. case CAM_CDM_CMD_WAIT_EVENT:
  915. buf_now += cdm_get_cmd_header_size(
  916. CAM_CDM_CMD_WAIT_EVENT);
  917. break;
  918. case CAM_CDM_CMD_CHANGE_BASE:
  919. buf_now += cdm_get_cmd_header_size(
  920. CAM_CDM_CMD_CHANGE_BASE);
  921. break;
  922. case CAM_CDM_CMD_PERF_CTRL:
  923. buf_now += cdm_get_cmd_header_size(
  924. CAM_CDM_CMD_PERF_CTRL);
  925. break;
  926. case CAM_CDM_CMD_COMP_WAIT:
  927. buf_now += cdm_get_cmd_header_size(
  928. CAM_CDM_CMD_COMP_WAIT);
  929. break;
  930. default:
  931. CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x", cmd);
  932. buf_now++;
  933. break;
  934. }
  935. } while (buf_now <= dump_info->src_end);
  936. return rc;
  937. }