voice_mhi.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/dma-mapping.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/of.h>
  8. #include <linux/of_address.h>
  9. #include <linux/list.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <linux/mhi.h>
  13. #include <linux/mutex.h>
  14. #include "voice_mhi.h"
  15. #include <dsp/msm_audio_ion.h>
  16. #include <dsp/spf-core.h>
  17. #include <dsp/audio_prm.h>
  18. #include <ipc/gpr-lite.h>
  19. #define VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG 0x080011E7
  20. #define VOICE_MHI_STATE_SET(a, b) ((a) |= (1UL<<(b)))
  21. #define VOICE_MHI_STATE_RESET(a, b) ((a) &= ~(1UL<<(b)))
  22. #define VOICE_MHI_STATE_CHECK(a, b) (1UL & (a >> b))
  23. #define CMD_STATUS_SUCCESS 0
  24. #define CMD_STATUS_FAIL 1
  25. #define TIMEOUT_MS 500
  26. #define PORT_NUM 0x01
  27. #define PORT_MASK 0x03
  28. #define CONVERT_PORT_APR(x, y) (x << 8 | y)
  29. #define VCPM_MODULE_INSTANCE_ID 0x00000004
  30. #define APM_CMD_SET_CFG 0x01001006
  31. enum voice_states {
  32. VOICE_MHI_INIT = 0,
  33. VOICE_MHI_PROBED = VOICE_MHI_INIT,
  34. VOICE_MHI_ADSP_UP,
  35. VOICE_MHI_SDX_UP,
  36. VOICE_MHI_INCALL
  37. };
  38. struct voice_mhi_addr {
  39. dma_addr_t base;
  40. uint32_t size;
  41. };
  42. struct voice_mhi_dev_info {
  43. struct platform_device *pdev;
  44. struct voice_mhi_addr phys_addr;
  45. struct voice_mhi_addr iova_pcie;
  46. struct voice_mhi_addr iova_adsp;
  47. };
  48. struct voice_mhi {
  49. struct voice_mhi_dev_info dev_info;
  50. struct mhi_device *mhi_dev;
  51. uint32_t vote_count;
  52. struct mutex mutex;
  53. enum voice_states voice_mhi_state;
  54. bool vote_enable;
  55. bool pcie_enabled;
  56. struct gpr_device *gdev;
  57. struct work_struct voice_mhi_work_pcie;
  58. struct work_struct voice_mhi_work_adsp;
  59. wait_queue_head_t voice_mhi_wait;
  60. u32 mvm_state;
  61. u32 async_err;
  62. };
  63. typedef struct vcpm_param_id_mailbox_memory_config_t
  64. {
  65. uint32_t mailbox_mem_address_adsp_lsw;
  66. /**< Lower 32 bits of IO virtual address(understandable to ADSP) of Mailbox Memory carved out from APQ DDR
  67. specifically for mailbox packet exchange between ADSP and MDM. */
  68. uint32_t mailbox_mem_address_adsp_msw;
  69. /**< Upper 32 bits of IO virtual address(understandable to ADSP) of Mailbox Memory carved out from APQ DDR
  70. specifically for mailbox packet exchange between ADSP and MDM. */
  71. uint32_t mailbox_mem_address_pcie_lsw;
  72. /**< Lower 32 bits of IO virtual address(understandable to PCIe) of Mailbox Memory carved out from APQ DDR
  73. specifically for mailbox packet exchange between ADSP and MDM. */
  74. uint32_t mailbox_mem_address_pcie_msw;
  75. /**< Upper 32 bits of IO virtual address(understandable to PCIe) of Mailbox Memory carved out from APQ DDR
  76. specifically for mailbox packet exchange between ADSP and MDM. */
  77. uint32_t mem_size;
  78. /**< Size(in bytes) of the Mailbox Memory carved out from APQ DDR.
  79. */
  80. }vcpm_param_id_mailbox_memory_config_t;
  81. typedef struct vcpm_cmd_set_cfg_t {
  82. apm_cmd_header_t payload_header;
  83. apm_module_param_data_t module_payload;
  84. vcpm_param_id_mailbox_memory_config_t mb_memory_config;
  85. }vcpm_cmd_set_cfg_t;
  86. static struct voice_mhi voice_mhi_lcl;
  87. static int voice_mhi_pcie_up_callback(struct mhi_device *,
  88. const struct mhi_device_id *);
  89. static void voice_mhi_pcie_down_callback(struct mhi_device *);
  90. static void voice_mhi_pcie_status_callback(struct mhi_device *, enum MHI_CB);
  91. static int32_t voice_mhi_gpr_callback(struct gpr_device *adev, void *data);
  92. //static int voice_mhi_notifier_service_cb(struct notifier_block *nb,
  93. // unsigned long opcode, void *ptr);
  94. // static struct notifier_block voice_mhi_service_nb = {
  95. // .notifier_call = voice_mhi_notifier_service_cb,
  96. // .priority = -INT_MAX,
  97. // };
  98. static const struct mhi_device_id voice_mhi_match_table[] = {
  99. { .chan = "AUDIO_VOICE_0", .driver_data = 0 },
  100. {},
  101. };
  102. static struct mhi_driver voice_mhi_driver = {
  103. .id_table = voice_mhi_match_table,
  104. .probe = voice_mhi_pcie_up_callback,
  105. .remove = voice_mhi_pcie_down_callback,
  106. .status_cb = voice_mhi_pcie_status_callback,
  107. .driver = {
  108. .name = "voice_mhi_audio",
  109. .owner = THIS_MODULE,
  110. },
  111. };
  112. // static int voice_mhi_notifier_service_cb(struct notifier_block *nb,
  113. // unsigned long opcode, void *ptr)
  114. // {
  115. // pr_err("%s: opcode 0x%lx\n", __func__, opcode);
  116. // switch (opcode) {
  117. // case AUDIO_NOTIFIER_SERVICE_DOWN:
  118. // if (voice_mhi_lcl.apr_mvm_handle) {
  119. // apr_reset(voice_mhi_lcl.apr_mvm_handle);
  120. // voice_mhi_lcl.apr_mvm_handle = NULL;
  121. // VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state,
  122. // VOICE_MHI_ADSP_UP);
  123. // }
  124. // break;
  125. // case AUDIO_NOTIFIER_SERVICE_UP:
  126. // if (!VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
  127. // VOICE_MHI_ADSP_UP)) {
  128. // VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
  129. // VOICE_MHI_ADSP_UP);
  130. // schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
  131. // }
  132. // break;
  133. // default:
  134. // break;
  135. // }
  136. // return NOTIFY_OK;
  137. // }
  138. static int32_t voice_mhi_gpr_callback(struct gpr_device *adev, void *data)
  139. {
  140. struct gpr_hdr *hdr = (struct gpr_hdr *)data;
  141. uint32_t *payload = GPR_PKT_GET_PAYLOAD(uint32_t, data);
  142. //bool resp_recieved = false;
  143. if (data == NULL) {
  144. pr_err("%s: data is NULL\n", __func__);
  145. return -EINVAL;
  146. }
  147. switch (hdr->opcode) {
  148. case GPR_IBASIC_RSP_RESULT:
  149. pr_err("%s: GPR_IBASIC_RSP_RESULT received",__func__);
  150. voice_mhi_lcl.mvm_state = CMD_STATUS_SUCCESS;
  151. voice_mhi_lcl.async_err = payload[1];
  152. wake_up(&voice_mhi_lcl.voice_mhi_wait);
  153. break;
  154. case VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG:
  155. pr_err("%s: cmd VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG\n",
  156. __func__);
  157. voice_mhi_lcl.mvm_state = CMD_STATUS_SUCCESS;
  158. voice_mhi_lcl.async_err = payload[1];
  159. wake_up(&voice_mhi_lcl.voice_mhi_wait);
  160. break;
  161. default:
  162. pr_err("%s: Invalid opcode %d\n", __func__,
  163. hdr->opcode);
  164. break;
  165. }
  166. return 0;
  167. }
  168. /**
  169. * voice_mhi_start -
  170. * Start vote for MHI/PCIe clock
  171. *
  172. * Returns 0 on success or error on failure
  173. */
  174. int voice_mhi_start(void)
  175. {
  176. int ret = 0;
  177. mutex_lock(&voice_mhi_lcl.mutex);
  178. if (voice_mhi_lcl.pcie_enabled) {
  179. if (!voice_mhi_lcl.mhi_dev) {
  180. pr_err("%s: NULL device found\n", __func__);
  181. ret = -EINVAL;
  182. goto done;
  183. }
  184. if (voice_mhi_lcl.vote_count == 0) {
  185. ret = mhi_device_get_sync(voice_mhi_lcl.mhi_dev,
  186. MHI_VOTE_DEVICE);
  187. if (ret) {
  188. pr_err("%s: mhi_device_get_sync failed\n",
  189. __func__);
  190. ret = -EINVAL;
  191. goto done;
  192. }
  193. pr_err("%s: mhi_device_get_sync success\n", __func__);
  194. } else {
  195. /* For DSDA, no additional voting is needed */
  196. pr_err("%s: mhi is already voted\n", __func__);
  197. }
  198. voice_mhi_lcl.vote_count++;
  199. } else {
  200. /* PCIe not supported - return success*/
  201. goto done;
  202. }
  203. done:
  204. mutex_unlock(&voice_mhi_lcl.mutex);
  205. return ret;
  206. }
  207. EXPORT_SYMBOL(voice_mhi_start);
  208. /**
  209. * voice_mhi_end -
  210. * End vote for MHI/PCIe clock
  211. *
  212. * Returns 0 on success or error on failure
  213. */
  214. int voice_mhi_end(void)
  215. {
  216. mutex_lock(&voice_mhi_lcl.mutex);
  217. if (voice_mhi_lcl.pcie_enabled) {
  218. if (!voice_mhi_lcl.mhi_dev || voice_mhi_lcl.vote_count == 0) {
  219. pr_err("%s: NULL device found\n", __func__);
  220. mutex_unlock(&voice_mhi_lcl.mutex);
  221. return -EINVAL;
  222. }
  223. if (voice_mhi_lcl.vote_count == 1)
  224. mhi_device_put(voice_mhi_lcl.mhi_dev, MHI_VOTE_DEVICE);
  225. voice_mhi_lcl.vote_count--;
  226. }
  227. mutex_unlock(&voice_mhi_lcl.mutex);
  228. return 0;
  229. }
  230. EXPORT_SYMBOL(voice_mhi_end);
  231. static int voice_mhi_set_mailbox_memory_config(void)
  232. {
  233. struct gpr_pkt *pkt;
  234. int ret = 0;
  235. struct gpr_device *gdev;
  236. vcpm_cmd_set_cfg_t vcpm_set_cfg;
  237. uint32_t size;
  238. //return 0;
  239. size = GPR_HDR_SIZE + sizeof (vcpm_cmd_set_cfg_t);
  240. pkt = kzalloc(size, GFP_KERNEL);
  241. if (!pkt) {
  242. pr_err("%s: memory allocation failed\n", __func__);
  243. return -ENOMEM;
  244. }
  245. if (!voice_mhi_lcl.gdev) {
  246. pr_err("%s: GPR handle is NULL\n", __func__);
  247. return -EINVAL;
  248. }
  249. memset(pkt, 0, sizeof(struct gpr_pkt));
  250. memset(&vcpm_set_cfg, 0, sizeof(vcpm_cmd_set_cfg_t));
  251. pkt->hdr.header = GPR_SET_FIELD(GPR_PKT_VERSION, GPR_PKT_VER) |
  252. GPR_SET_FIELD(GPR_PKT_HEADER_SIZE, GPR_PKT_HEADER_WORD_SIZE_V) |
  253. GPR_SET_FIELD(GPR_PKT_PACKET_SIZE, size);
  254. pkt->hdr.opcode = APM_CMD_SET_CFG;
  255. pkt->hdr.dst_port = VCPM_MODULE_INSTANCE_ID;
  256. pkt->hdr.src_port = GPR_SVC_VPM;
  257. pkt->hdr.dst_domain_id = GPR_IDS_DOMAIN_ID_ADSP_V;
  258. pkt->hdr.src_domain_id = GPR_IDS_DOMAIN_ID_APPS_V;
  259. mutex_lock(&voice_mhi_lcl.mutex);
  260. gdev = voice_mhi_lcl.gdev;
  261. /*
  262. * Handle can be NULL as it is not tied to any session
  263. */
  264. vcpm_set_cfg.payload_header.payload_address_lsw = 0;
  265. vcpm_set_cfg.payload_header.payload_address_msw = 0;
  266. vcpm_set_cfg.payload_header.mem_map_handle = 0;
  267. vcpm_set_cfg.payload_header.payload_size = sizeof(vcpm_cmd_set_cfg_t) - sizeof(apm_cmd_header_t);
  268. vcpm_set_cfg.module_payload.module_instance_id = VCPM_MODULE_INSTANCE_ID;
  269. vcpm_set_cfg.module_payload.error_code = 0;
  270. vcpm_set_cfg.module_payload.param_id = VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG;
  271. vcpm_set_cfg.module_payload.param_size =
  272. sizeof(vcpm_cmd_set_cfg_t) - sizeof(apm_cmd_header_t) - sizeof(apm_module_param_data_t);
  273. vcpm_set_cfg.mb_memory_config.mailbox_mem_address_pcie_lsw =
  274. (uint32_t) voice_mhi_lcl.dev_info.iova_pcie.base;
  275. vcpm_set_cfg.mb_memory_config.mailbox_mem_address_pcie_msw =
  276. (uint64_t) voice_mhi_lcl.dev_info.iova_pcie.base >> 32;
  277. vcpm_set_cfg.mb_memory_config.mailbox_mem_address_adsp_lsw =
  278. (uint32_t) voice_mhi_lcl.dev_info.iova_adsp.base;
  279. vcpm_set_cfg.mb_memory_config.mailbox_mem_address_adsp_msw =
  280. (uint64_t) voice_mhi_lcl.dev_info.iova_adsp.base >> 32;
  281. vcpm_set_cfg.mb_memory_config.mem_size = voice_mhi_lcl.dev_info.iova_adsp.size;
  282. voice_mhi_lcl.mvm_state = CMD_STATUS_FAIL;
  283. voice_mhi_lcl.async_err = 0;
  284. memcpy(&pkt->payload, &vcpm_set_cfg, sizeof(vcpm_cmd_set_cfg_t));
  285. ret = gpr_send_pkt(gdev, pkt);
  286. if (ret < 0) {
  287. pr_err("%s: Set mailbox memory config failed ret = %d\n",
  288. __func__, ret);
  289. goto unlock;
  290. }
  291. ret = wait_event_timeout(voice_mhi_lcl.voice_mhi_wait,
  292. (voice_mhi_lcl.mvm_state ==
  293. CMD_STATUS_SUCCESS),
  294. msecs_to_jiffies(TIMEOUT_MS));
  295. if (!ret) {
  296. pr_err("%s: wait_event timeout\n", __func__);
  297. ret = -ETIME;
  298. goto unlock;
  299. }
  300. if (voice_mhi_lcl.async_err > 0) {
  301. pr_err("%s: DSP returned error[%d]\n",
  302. __func__, voice_mhi_lcl.async_err);
  303. ret = voice_mhi_lcl.async_err;
  304. goto unlock;
  305. }
  306. ret = 0;
  307. unlock:
  308. mutex_unlock(&voice_mhi_lcl.mutex);
  309. return ret;
  310. }
  311. static void voice_mhi_map_pcie_and_send(struct work_struct *work)
  312. {
  313. dma_addr_t iova, phys_addr;
  314. uint32_t mem_size;
  315. struct device *md;
  316. mutex_lock(&voice_mhi_lcl.mutex);
  317. if (voice_mhi_lcl.mhi_dev) {
  318. md = &voice_mhi_lcl.mhi_dev->dev;
  319. } else {
  320. pr_err("%s: MHI device handle is NULL\n", __func__);
  321. goto err;
  322. }
  323. phys_addr = voice_mhi_lcl.dev_info.phys_addr.base;
  324. mem_size = voice_mhi_lcl.dev_info.iova_pcie.size;
  325. if (md) {
  326. iova = dma_map_resource(md->parent, phys_addr, mem_size,
  327. DMA_BIDIRECTIONAL, 0);
  328. if (dma_mapping_error(md->parent, iova)) {
  329. pr_err("%s: dma_mapping_error\n", __func__);
  330. goto err;
  331. }
  332. pr_err("%s: dma_mapping_success iova:0x%lx\n",
  333. __func__, (unsigned long)iova);
  334. voice_mhi_lcl.dev_info.iova_pcie.base = iova;
  335. mutex_unlock(&voice_mhi_lcl.mutex);
  336. if (spf_core_is_apm_ready()) {
  337. voice_mhi_set_mailbox_memory_config();
  338. voice_mhi_start();
  339. }
  340. return;
  341. }
  342. err:
  343. mutex_unlock(&voice_mhi_lcl.mutex);
  344. return;
  345. }
  346. static void voice_mhi_gpr_send(struct work_struct *work)
  347. {
  348. // ret = voice_mhi_apr_register();
  349. // if (ret) {
  350. // pr_err("%s: APR registration failed %d\n", __func__, ret);
  351. // return;
  352. // }
  353. pr_err("%s: GPR is up \n", __func__);
  354. mutex_lock(&voice_mhi_lcl.mutex);
  355. if (VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
  356. VOICE_MHI_SDX_UP)) {
  357. mutex_unlock(&voice_mhi_lcl.mutex);
  358. if (spf_core_is_apm_ready()) {
  359. voice_mhi_set_mailbox_memory_config();
  360. voice_mhi_start();
  361. return;
  362. } else {
  363. pr_err("%s: Gecko core not ready \n", __func__);
  364. }
  365. } else {
  366. mutex_unlock(&voice_mhi_lcl.mutex);
  367. schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
  368. }
  369. }
  370. static int voice_mhi_pcie_up_callback(struct mhi_device *voice_mhi_dev,
  371. const struct mhi_device_id *id)
  372. {
  373. if ((!voice_mhi_dev) || (id != &voice_mhi_match_table[0])) {
  374. pr_err("%s: Invalid device or table received\n", __func__);
  375. return -EINVAL;
  376. }
  377. pr_err("%s: MHI PCIe UP callback\n", __func__);
  378. mutex_lock(&voice_mhi_lcl.mutex);
  379. voice_mhi_lcl.mhi_dev = voice_mhi_dev;
  380. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state, VOICE_MHI_SDX_UP);
  381. mutex_unlock(&voice_mhi_lcl.mutex);
  382. schedule_work(&voice_mhi_lcl.voice_mhi_work_pcie);
  383. return 0;
  384. }
  385. static void voice_mhi_pcie_down_callback(struct mhi_device *voice_mhi_dev)
  386. {
  387. dma_addr_t iova;
  388. struct device *md = NULL;
  389. mutex_lock(&voice_mhi_lcl.mutex);
  390. if (voice_mhi_lcl.mhi_dev)
  391. md = &voice_mhi_lcl.mhi_dev->dev;
  392. VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state, VOICE_MHI_SDX_UP);
  393. iova = voice_mhi_lcl.dev_info.iova_pcie.base;
  394. if (md)
  395. dma_unmap_resource(md->parent, iova, PAGE_SIZE,
  396. DMA_BIDIRECTIONAL, 0);
  397. voice_mhi_lcl.mhi_dev = NULL;
  398. voice_mhi_lcl.vote_count = 0;
  399. mutex_unlock(&voice_mhi_lcl.mutex);
  400. }
  401. static void voice_mhi_pcie_status_callback(struct mhi_device *voice_mhi_dev,
  402. enum MHI_CB mhi_cb)
  403. {
  404. }
  405. static int voice_mhi_gpr_probe(struct gpr_device *gdev)
  406. {
  407. int ret = 0;
  408. pr_err("%s Enter ", __func__);
  409. mutex_lock(&voice_mhi_lcl.mutex);
  410. voice_mhi_lcl.gdev = gdev;
  411. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
  412. VOICE_MHI_ADSP_UP);
  413. mutex_unlock(&voice_mhi_lcl.mutex);
  414. //schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
  415. pr_err("%s Exit ", __func__);
  416. return ret;
  417. }
  418. static int voice_mhi_gpr_exit(struct gpr_device *gdev)
  419. {
  420. voice_mhi_end();
  421. mutex_lock(&voice_mhi_lcl.mutex);
  422. voice_mhi_lcl.gdev = NULL;
  423. VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state,
  424. VOICE_MHI_ADSP_UP);
  425. mutex_unlock(&voice_mhi_lcl.mutex);
  426. return 0;
  427. }
  428. static const struct of_device_id voice_mhi_gpr_device_id[] = {
  429. { .compatible = "qcom,voice_mhi_gpr" },
  430. {},
  431. };
  432. MODULE_DEVICE_TABLE(of, voice_mhi_gpr_device_id);
  433. static struct gpr_driver voice_mhi_gpr_driver = {
  434. .probe = voice_mhi_gpr_probe,
  435. .remove = voice_mhi_gpr_exit,
  436. .callback = voice_mhi_gpr_callback,
  437. .driver = {
  438. .name = "qcom-voice_mhi_gpr",
  439. .of_match_table = of_match_ptr(voice_mhi_gpr_device_id),
  440. },
  441. };
  442. // static int voice_mhi_apr_register(void)
  443. // {
  444. // int ret = 0;
  445. // mutex_lock(&voice_mhi_lcl.mutex);
  446. // voice_mhi_lcl.apr_mvm_handle = apr_register("ADSP", "MVM",
  447. // (apr_fn)voice_mhi_apr_callback,
  448. // CONVERT_PORT_APR(PORT_NUM,
  449. // PORT_MASK),
  450. // &voice_mhi_lcl);
  451. // if (voice_mhi_lcl.apr_mvm_handle == NULL) {
  452. // pr_err("%s: error in APR register\n", __func__);
  453. // ret = -ENODEV;
  454. // }
  455. // mutex_unlock(&voice_mhi_lcl.mutex);
  456. // return ret;
  457. // }
  458. static int voice_mhi_probe(struct platform_device *pdev)
  459. {
  460. int ret = 0;
  461. struct device_node *node;
  462. uint32_t mem_size = 0;
  463. void *ptr;
  464. dma_addr_t phys_addr, iova;
  465. const __be32 *cell;
  466. pr_err("%s: Enter\n", __func__);
  467. memset(&voice_mhi_lcl, 0, sizeof(voice_mhi_lcl));
  468. mutex_init(&voice_mhi_lcl.mutex);
  469. /* Add remaining init here */
  470. voice_mhi_lcl.pcie_enabled = false;
  471. voice_mhi_lcl.voice_mhi_state = VOICE_MHI_INIT;
  472. voice_mhi_lcl.vote_count = 0;
  473. voice_mhi_lcl.gdev = NULL;
  474. INIT_WORK(&voice_mhi_lcl.voice_mhi_work_pcie,
  475. voice_mhi_map_pcie_and_send);
  476. INIT_WORK(&voice_mhi_lcl.voice_mhi_work_adsp,
  477. voice_mhi_gpr_send);
  478. init_waitqueue_head(&voice_mhi_lcl.voice_mhi_wait);
  479. node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
  480. if (node) {
  481. cell = of_get_property(node, "size", NULL);
  482. if (cell)
  483. mem_size = of_read_number(cell, 2);
  484. else {
  485. pr_err("%s: cell not found\n", __func__);
  486. ret = -EINVAL;
  487. goto done;
  488. }
  489. } else {
  490. pr_err("%s: Node read failed\n", __func__);
  491. ret = -EINVAL;
  492. goto done;
  493. }
  494. pr_err("%s: mem_size = %d\n", __func__, mem_size);
  495. if (mem_size) {
  496. ptr = dma_alloc_attrs(&pdev->dev, mem_size, &phys_addr,
  497. GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
  498. if (IS_ERR_OR_NULL(ptr)) {
  499. pr_err("%s: Memory alloc failed\n", __func__);
  500. ret = -ENOMEM;
  501. goto done;
  502. } else {
  503. pr_err("%s: Memory alloc success phys_addr:0x%lx\n",
  504. __func__, (unsigned long)phys_addr);
  505. }
  506. ret = msm_audio_ion_dma_map(&phys_addr, &iova, mem_size,
  507. DMA_BIDIRECTIONAL);
  508. if (ret) {
  509. pr_err("%s: dma mapping failed %d\n", __func__, ret);
  510. goto err_free;
  511. }
  512. pr_err("%s: dma_mapping_success iova:0x%lx\n",
  513. __func__, (unsigned long)iova);
  514. voice_mhi_lcl.dev_info.iova_adsp.size = mem_size;
  515. voice_mhi_lcl.dev_info.iova_pcie.size = mem_size;
  516. voice_mhi_lcl.dev_info.pdev = pdev;
  517. voice_mhi_lcl.dev_info.phys_addr.base = phys_addr;
  518. voice_mhi_lcl.dev_info.iova_adsp.base = iova;
  519. ret = gpr_driver_register(&voice_mhi_gpr_driver);
  520. if (ret) {
  521. pr_err("%s: gpr driver register failed = %d\n",
  522. __func__, ret);
  523. ret = -EINVAL;
  524. goto err_free;
  525. }
  526. pr_err("%s: gpr register success",__func__);
  527. ret = mhi_driver_register(&voice_mhi_driver);
  528. if (ret) {
  529. pr_err("%s: mhi register failed %d\n", __func__, ret);
  530. goto err_free;
  531. }
  532. mutex_lock(&voice_mhi_lcl.mutex);
  533. voice_mhi_lcl.pcie_enabled = true;
  534. VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
  535. VOICE_MHI_PROBED);
  536. mutex_unlock(&voice_mhi_lcl.mutex);
  537. } else {
  538. pr_err("%s: Memory size can't be zero\n", __func__);
  539. ret = -ENOMEM;
  540. goto done;
  541. }
  542. done:
  543. return ret;
  544. err_free:
  545. dma_free_attrs(&pdev->dev, mem_size, ptr, phys_addr,
  546. DMA_ATTR_NO_KERNEL_MAPPING);
  547. return ret;
  548. }
  549. static int voice_mhi_remove(struct platform_device *pdev)
  550. {
  551. if (voice_mhi_lcl.gdev)
  552. voice_mhi_lcl.gdev = NULL;
  553. mhi_driver_unregister(&voice_mhi_driver);
  554. gpr_driver_unregister(&voice_mhi_gpr_driver);
  555. memset(&voice_mhi_lcl, 0, sizeof(voice_mhi_lcl));
  556. mutex_destroy(&voice_mhi_lcl.mutex);
  557. return 0;
  558. }
  559. static const struct of_device_id voice_mhi_of_match[] = {
  560. { .compatible = "qcom,voice-mhi-audio", },
  561. {},
  562. };
  563. static struct platform_driver voice_mhi_platform_driver = {
  564. .probe = voice_mhi_probe,
  565. .remove = voice_mhi_remove,
  566. .driver = {
  567. .name = "voice_mhi_audio",
  568. .owner = THIS_MODULE,
  569. .of_match_table = voice_mhi_of_match,
  570. .suppress_bind_attrs = true,
  571. }
  572. };
  573. module_platform_driver(voice_mhi_platform_driver);
  574. MODULE_DESCRIPTION("Voice MHI module");
  575. MODULE_LICENSE("GPL v2");