bmi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. // SPDX-License-Identifier: ISC
  2. /*
  3. * Copyright (c) 2005-2011 Atheros Communications Inc.
  4. * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc.
  5. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  6. */
  7. #include "bmi.h"
  8. #include "hif.h"
  9. #include "debug.h"
  10. #include "htc.h"
  11. #include "hw.h"
  12. void ath10k_bmi_start(struct ath10k *ar)
  13. {
  14. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
  15. ar->bmi.done_sent = false;
  16. }
  17. EXPORT_SYMBOL(ath10k_bmi_start);
  18. int ath10k_bmi_done(struct ath10k *ar)
  19. {
  20. struct bmi_cmd cmd;
  21. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
  22. int ret;
  23. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
  24. if (ar->bmi.done_sent) {
  25. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
  26. return 0;
  27. }
  28. ar->bmi.done_sent = true;
  29. cmd.id = __cpu_to_le32(BMI_DONE);
  30. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
  31. if (ret) {
  32. ath10k_warn(ar, "unable to write to the device: %d\n", ret);
  33. return ret;
  34. }
  35. return 0;
  36. }
  37. int ath10k_bmi_get_target_info(struct ath10k *ar,
  38. struct bmi_target_info *target_info)
  39. {
  40. struct bmi_cmd cmd;
  41. union bmi_resp resp;
  42. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
  43. u32 resplen = sizeof(resp.get_target_info);
  44. int ret;
  45. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
  46. if (ar->bmi.done_sent) {
  47. ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
  48. return -EBUSY;
  49. }
  50. cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
  51. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
  52. if (ret) {
  53. ath10k_warn(ar, "unable to get target info from device\n");
  54. return ret;
  55. }
  56. if (resplen < sizeof(resp.get_target_info)) {
  57. ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
  58. resplen);
  59. return -EIO;
  60. }
  61. target_info->version = __le32_to_cpu(resp.get_target_info.version);
  62. target_info->type = __le32_to_cpu(resp.get_target_info.type);
  63. return 0;
  64. }
  65. #define TARGET_VERSION_SENTINAL 0xffffffffu
  66. int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
  67. struct bmi_target_info *target_info)
  68. {
  69. struct bmi_cmd cmd;
  70. union bmi_resp resp;
  71. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
  72. u32 resplen, ver_len;
  73. __le32 tmp;
  74. int ret;
  75. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n");
  76. if (ar->bmi.done_sent) {
  77. ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
  78. return -EBUSY;
  79. }
  80. cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
  81. /* Step 1: Read 4 bytes of the target info and check if it is
  82. * the special sentinel version word or the first word in the
  83. * version response.
  84. */
  85. resplen = sizeof(u32);
  86. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen);
  87. if (ret) {
  88. ath10k_warn(ar, "unable to read from device\n");
  89. return ret;
  90. }
  91. /* Some SDIO boards have a special sentinel byte before the real
  92. * version response.
  93. */
  94. if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {
  95. /* Step 1b: Read the version length */
  96. resplen = sizeof(u32);
  97. ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp,
  98. &resplen);
  99. if (ret) {
  100. ath10k_warn(ar, "unable to read from device\n");
  101. return ret;
  102. }
  103. }
  104. ver_len = __le32_to_cpu(tmp);
  105. /* Step 2: Check the target info length */
  106. if (ver_len != sizeof(resp.get_target_info)) {
  107. ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n",
  108. ver_len, sizeof(resp.get_target_info));
  109. return -EINVAL;
  110. }
  111. /* Step 3: Read the rest of the version response */
  112. resplen = sizeof(resp.get_target_info) - sizeof(u32);
  113. ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0,
  114. &resp.get_target_info.version,
  115. &resplen);
  116. if (ret) {
  117. ath10k_warn(ar, "unable to read from device\n");
  118. return ret;
  119. }
  120. target_info->version = __le32_to_cpu(resp.get_target_info.version);
  121. target_info->type = __le32_to_cpu(resp.get_target_info.type);
  122. return 0;
  123. }
  124. int ath10k_bmi_read_memory(struct ath10k *ar,
  125. u32 address, void *buffer, u32 length)
  126. {
  127. struct bmi_cmd cmd;
  128. union bmi_resp resp;
  129. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
  130. u32 rxlen;
  131. int ret;
  132. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
  133. address, length);
  134. if (ar->bmi.done_sent) {
  135. ath10k_warn(ar, "command disallowed\n");
  136. return -EBUSY;
  137. }
  138. while (length) {
  139. rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
  140. cmd.id = __cpu_to_le32(BMI_READ_MEMORY);
  141. cmd.read_mem.addr = __cpu_to_le32(address);
  142. cmd.read_mem.len = __cpu_to_le32(rxlen);
  143. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
  144. &resp, &rxlen);
  145. if (ret) {
  146. ath10k_warn(ar, "unable to read from the device (%d)\n",
  147. ret);
  148. return ret;
  149. }
  150. memcpy(buffer, resp.read_mem.payload, rxlen);
  151. address += rxlen;
  152. buffer += rxlen;
  153. length -= rxlen;
  154. }
  155. return 0;
  156. }
  157. EXPORT_SYMBOL(ath10k_bmi_read_memory);
  158. int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
  159. {
  160. struct bmi_cmd cmd;
  161. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
  162. int ret;
  163. ath10k_dbg(ar, ATH10K_DBG_BMI,
  164. "bmi write soc register 0x%08x val 0x%08x\n",
  165. address, reg_val);
  166. if (ar->bmi.done_sent) {
  167. ath10k_warn(ar, "bmi write soc register command in progress\n");
  168. return -EBUSY;
  169. }
  170. cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
  171. cmd.write_soc_reg.addr = __cpu_to_le32(address);
  172. cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
  173. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
  174. if (ret) {
  175. ath10k_warn(ar, "Unable to write soc register to device: %d\n",
  176. ret);
  177. return ret;
  178. }
  179. return 0;
  180. }
  181. int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
  182. {
  183. struct bmi_cmd cmd;
  184. union bmi_resp resp;
  185. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
  186. u32 resplen = sizeof(resp.read_soc_reg);
  187. int ret;
  188. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
  189. address);
  190. if (ar->bmi.done_sent) {
  191. ath10k_warn(ar, "bmi read soc register command in progress\n");
  192. return -EBUSY;
  193. }
  194. cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
  195. cmd.read_soc_reg.addr = __cpu_to_le32(address);
  196. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
  197. if (ret) {
  198. ath10k_warn(ar, "Unable to read soc register from device: %d\n",
  199. ret);
  200. return ret;
  201. }
  202. *reg_val = __le32_to_cpu(resp.read_soc_reg.value);
  203. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
  204. *reg_val);
  205. return 0;
  206. }
  207. int ath10k_bmi_write_memory(struct ath10k *ar,
  208. u32 address, const void *buffer, u32 length)
  209. {
  210. struct bmi_cmd cmd;
  211. u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
  212. u32 txlen;
  213. int ret;
  214. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
  215. address, length);
  216. if (ar->bmi.done_sent) {
  217. ath10k_warn(ar, "command disallowed\n");
  218. return -EBUSY;
  219. }
  220. while (length) {
  221. txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
  222. /* copy before roundup to avoid reading beyond buffer*/
  223. memcpy(cmd.write_mem.payload, buffer, txlen);
  224. txlen = roundup(txlen, 4);
  225. cmd.id = __cpu_to_le32(BMI_WRITE_MEMORY);
  226. cmd.write_mem.addr = __cpu_to_le32(address);
  227. cmd.write_mem.len = __cpu_to_le32(txlen);
  228. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
  229. NULL, NULL);
  230. if (ret) {
  231. ath10k_warn(ar, "unable to write to the device (%d)\n",
  232. ret);
  233. return ret;
  234. }
  235. /* fixup roundup() so `length` zeroes out for last chunk */
  236. txlen = min(txlen, length);
  237. address += txlen;
  238. buffer += txlen;
  239. length -= txlen;
  240. }
  241. return 0;
  242. }
  243. int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
  244. {
  245. struct bmi_cmd cmd;
  246. union bmi_resp resp;
  247. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
  248. u32 resplen = sizeof(resp.execute);
  249. int ret;
  250. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
  251. address, param);
  252. if (ar->bmi.done_sent) {
  253. ath10k_warn(ar, "command disallowed\n");
  254. return -EBUSY;
  255. }
  256. cmd.id = __cpu_to_le32(BMI_EXECUTE);
  257. cmd.execute.addr = __cpu_to_le32(address);
  258. cmd.execute.param = __cpu_to_le32(param);
  259. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
  260. if (ret) {
  261. ath10k_warn(ar, "unable to read from the device\n");
  262. return ret;
  263. }
  264. if (resplen < sizeof(resp.execute)) {
  265. ath10k_warn(ar, "invalid execute response length (%d)\n",
  266. resplen);
  267. return -EIO;
  268. }
  269. *result = __le32_to_cpu(resp.execute.result);
  270. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
  271. return 0;
  272. }
  273. static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 length)
  274. {
  275. struct bmi_cmd *cmd;
  276. u32 hdrlen = sizeof(cmd->id) + sizeof(cmd->lz_data);
  277. u32 txlen;
  278. int ret;
  279. size_t buf_len;
  280. ath10k_dbg(ar, ATH10K_DBG_BMI, "large bmi lz data buffer 0x%pK length %d\n",
  281. buffer, length);
  282. if (ar->bmi.done_sent) {
  283. ath10k_warn(ar, "command disallowed\n");
  284. return -EBUSY;
  285. }
  286. buf_len = sizeof(*cmd) + BMI_MAX_LARGE_DATA_SIZE - BMI_MAX_DATA_SIZE;
  287. cmd = kzalloc(buf_len, GFP_KERNEL);
  288. if (!cmd)
  289. return -ENOMEM;
  290. while (length) {
  291. txlen = min(length, BMI_MAX_LARGE_DATA_SIZE - hdrlen);
  292. WARN_ON_ONCE(txlen & 3);
  293. cmd->id = __cpu_to_le32(BMI_LZ_DATA);
  294. cmd->lz_data.len = __cpu_to_le32(txlen);
  295. memcpy(cmd->lz_data.payload, buffer, txlen);
  296. ret = ath10k_hif_exchange_bmi_msg(ar, cmd, hdrlen + txlen,
  297. NULL, NULL);
  298. if (ret) {
  299. ath10k_warn(ar, "unable to write to the device\n");
  300. kfree(cmd);
  301. return ret;
  302. }
  303. buffer += txlen;
  304. length -= txlen;
  305. }
  306. kfree(cmd);
  307. return 0;
  308. }
  309. int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
  310. {
  311. struct bmi_cmd cmd;
  312. u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
  313. u32 txlen;
  314. int ret;
  315. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%pK length %d\n",
  316. buffer, length);
  317. if (ar->bmi.done_sent) {
  318. ath10k_warn(ar, "command disallowed\n");
  319. return -EBUSY;
  320. }
  321. while (length) {
  322. txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
  323. WARN_ON_ONCE(txlen & 3);
  324. cmd.id = __cpu_to_le32(BMI_LZ_DATA);
  325. cmd.lz_data.len = __cpu_to_le32(txlen);
  326. memcpy(cmd.lz_data.payload, buffer, txlen);
  327. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
  328. NULL, NULL);
  329. if (ret) {
  330. ath10k_warn(ar, "unable to write to the device\n");
  331. return ret;
  332. }
  333. buffer += txlen;
  334. length -= txlen;
  335. }
  336. return 0;
  337. }
  338. int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
  339. {
  340. struct bmi_cmd cmd;
  341. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
  342. int ret;
  343. ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
  344. address);
  345. if (ar->bmi.done_sent) {
  346. ath10k_warn(ar, "command disallowed\n");
  347. return -EBUSY;
  348. }
  349. cmd.id = __cpu_to_le32(BMI_LZ_STREAM_START);
  350. cmd.lz_start.addr = __cpu_to_le32(address);
  351. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
  352. if (ret) {
  353. ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
  354. return ret;
  355. }
  356. return 0;
  357. }
  358. int ath10k_bmi_fast_download(struct ath10k *ar,
  359. u32 address, const void *buffer, u32 length)
  360. {
  361. u8 trailer[4] = {};
  362. u32 head_len = rounddown(length, 4);
  363. u32 trailer_len = length - head_len;
  364. int ret;
  365. ath10k_dbg(ar, ATH10K_DBG_BMI,
  366. "bmi fast download address 0x%x buffer 0x%pK length %d\n",
  367. address, buffer, length);
  368. ret = ath10k_bmi_lz_stream_start(ar, address);
  369. if (ret)
  370. return ret;
  371. /* copy the last word into a zero padded buffer */
  372. if (trailer_len > 0)
  373. memcpy(trailer, buffer + head_len, trailer_len);
  374. if (ar->hw_params.bmi_large_size_download)
  375. ret = ath10k_bmi_lz_data_large(ar, buffer, head_len);
  376. else
  377. ret = ath10k_bmi_lz_data(ar, buffer, head_len);
  378. if (ret)
  379. return ret;
  380. if (trailer_len > 0)
  381. ret = ath10k_bmi_lz_data(ar, trailer, 4);
  382. if (ret != 0)
  383. return ret;
  384. /*
  385. * Close compressed stream and open a new (fake) one.
  386. * This serves mainly to flush Target caches.
  387. */
  388. ret = ath10k_bmi_lz_stream_start(ar, 0x00);
  389. return ret;
  390. }
  391. int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
  392. {
  393. struct bmi_cmd cmd;
  394. u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
  395. int ret;
  396. if (ar->bmi.done_sent) {
  397. ath10k_warn(ar, "bmi set start command disallowed\n");
  398. return -EBUSY;
  399. }
  400. cmd.id = __cpu_to_le32(BMI_SET_APP_START);
  401. cmd.set_app_start.addr = __cpu_to_le32(address);
  402. ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
  403. if (ret) {
  404. ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
  405. return ret;
  406. }
  407. return 0;
  408. }