drv_pl041.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-05-25 RT-Thread the first version
  9. */
  10. #include <rtthread.h>
  11. #include <rthw.h>
  12. #include "drv_pl041.h"
  13. #include "drv_ac97.h"
  14. #include "realview.h"
  15. #define DBG_TAG "PL041"
  16. // #define DBG_LVL DBG_LOG
  17. // #define DBG_LVL DBG_INFO
  18. #define DBG_LVL DBG_WARNING
  19. // #define DBG_LVL DBG_ERROR
  20. #include <rtdbg.h>
  21. #define FRAME_PERIOD_US (50)
  22. #define PL041_CHANNEL_NUM (4)
  23. #define PL041_READ(_a) (*(volatile rt_uint32_t *)(_a))
  24. #define PL041_WRITE(_a, _v) (*(volatile rt_uint32_t *)(_a) = (_v))
  25. struct pl041_irq_def
  26. {
  27. pl041_irq_fun_t fun;
  28. void *user_data;
  29. };
  30. static struct pl041_irq_def irq_tbl[PL041_CHANNEL_NUM];
  31. static void aaci_pl041_delay(rt_uint32_t us)
  32. {
  33. volatile int i;
  34. for (i = us * 10; i != 0; i--);
  35. }
  36. static void aaci_ac97_select_codec(void)
  37. {
  38. rt_uint32_t v, maincr;
  39. maincr = AACI_MAINCR_SCRA(0) | AACI_MAINCR_IE | AACI_MAINCR_SL1RXEN | \
  40. AACI_MAINCR_SL1TXEN | AACI_MAINCR_SL2RXEN | AACI_MAINCR_SL2TXEN;
  41. v = PL041_READ(&PL041->slfr);
  42. if (v & AACI_SLFR_2RXV)
  43. {
  44. PL041_READ(&PL041->sl2rx);
  45. }
  46. if (v & AACI_SLFR_1RXV)
  47. {
  48. PL041_READ(&PL041->sl1rx);
  49. }
  50. if (maincr != PL041_READ(&PL041->maincr))
  51. {
  52. PL041_WRITE(&PL041->maincr, maincr);
  53. aaci_pl041_delay(1);
  54. }
  55. }
  56. void aaci_ac97_write(rt_uint16_t reg, rt_uint16_t val)
  57. {
  58. rt_uint32_t v, timeout;
  59. aaci_ac97_select_codec();
  60. PL041_WRITE(&PL041->sl2tx, val << 4);
  61. PL041_WRITE(&PL041->sl1tx, reg << 12);
  62. aaci_pl041_delay(FRAME_PERIOD_US);
  63. timeout = FRAME_PERIOD_US * 8;
  64. do
  65. {
  66. aaci_pl041_delay(1);
  67. v = PL041_READ(&PL041->slfr);
  68. }
  69. while ((v & (AACI_SLFR_1TXB | AACI_SLFR_2TXB)) && --timeout);
  70. if (v & (AACI_SLFR_1TXB | AACI_SLFR_2TXB))
  71. {
  72. LOG_E("timeout waiting for write to complete");
  73. }
  74. }
  75. rt_uint16_t aaci_ac97_read(rt_uint16_t reg)
  76. {
  77. rt_uint32_t v, timeout, retries = 10;
  78. aaci_ac97_select_codec();
  79. PL041_WRITE(&PL041->sl1tx, (reg << 12) | (1 << 19));
  80. aaci_pl041_delay(FRAME_PERIOD_US);
  81. timeout = FRAME_PERIOD_US * 8;
  82. do
  83. {
  84. aaci_pl041_delay(1);
  85. v = PL041_READ(&PL041->slfr);
  86. }
  87. while ((v & AACI_SLFR_1TXB) && --timeout);
  88. if (v & AACI_SLFR_1TXB)
  89. {
  90. LOG_E("timeout on slot 1 TX busy");
  91. v = ~0x0;
  92. return v;
  93. }
  94. aaci_pl041_delay(FRAME_PERIOD_US);
  95. timeout = FRAME_PERIOD_US * 8;
  96. do
  97. {
  98. aaci_pl041_delay(1);
  99. v = PL041_READ(&PL041->slfr) & (AACI_SLFR_1RXV | AACI_SLFR_2RXV);
  100. }
  101. while ((v != (AACI_SLFR_1RXV | AACI_SLFR_2RXV)) && --timeout);
  102. if (v != (AACI_SLFR_1RXV | AACI_SLFR_2RXV))
  103. {
  104. LOG_E("timeout on RX valid");
  105. v = ~0x0;
  106. return v;
  107. }
  108. do
  109. {
  110. v = PL041_READ(&PL041->sl1rx) >> 12;
  111. if (v == reg)
  112. {
  113. v = PL041_READ(&PL041->sl2rx) >> 4;
  114. break;
  115. }
  116. else if (--retries)
  117. {
  118. LOG_E("ac97 read back fail. retry");
  119. continue;
  120. }
  121. else
  122. {
  123. LOG_E("wrong ac97 register read back (%x != %x)", v, reg);
  124. v = ~0x0;
  125. }
  126. }
  127. while (retries);
  128. return v;
  129. }
  130. int aaci_pl041_channel_disable(int channel)
  131. {
  132. rt_uint32_t v;
  133. void *p_rx, *p_tx;
  134. p_rx = (void *)((rt_uint32_t)(&PL041->rxcr1) + channel * 0x14);
  135. p_tx = (void *)((rt_uint32_t)(&PL041->txcr1) + channel * 0x14);
  136. v = PL041_READ(p_rx);
  137. v &= ~AACI_CR_EN;
  138. PL041_WRITE(p_rx, v);
  139. v = PL041_READ(p_tx);
  140. v &= ~AACI_CR_EN;
  141. PL041_WRITE(p_tx, v);
  142. return 0;
  143. }
  144. int aaci_pl041_channel_enable(int channel)
  145. {
  146. rt_uint32_t v;
  147. void *p_rx, *p_tx;
  148. p_rx = (void *)((rt_uint32_t)(&PL041->rxcr1) + channel * 0x14);
  149. p_tx = (void *)((rt_uint32_t)(&PL041->txcr1) + channel * 0x14);
  150. v = PL041_READ(p_rx);
  151. v |= AACI_CR_EN;
  152. PL041_WRITE(p_rx, v);
  153. v = PL041_READ(p_tx);
  154. v |= AACI_CR_EN;
  155. PL041_WRITE(p_tx, v);
  156. return 0;
  157. }
  158. int aaci_pl041_channel_read(int channel, rt_uint16_t *buff, int count)
  159. {
  160. void *p_data, *p_status;
  161. int i = 0;
  162. p_status = (void *)((rt_uint32_t)(&PL041->sr1) + channel * 0x14);
  163. p_data = (void *)((rt_uint32_t)(&(PL041->dr1[0])) + channel * 0x20);
  164. for (i = 0; (!(PL041_READ(p_status) & AACI_SR_RXFE)) && (i < count); i++)
  165. {
  166. buff[i] = (rt_uint16_t)PL041_READ(p_data);
  167. }
  168. return i;
  169. }
  170. int aaci_pl041_channel_write(int channel, rt_uint16_t *buff, int count)
  171. {
  172. void *p_data, *p_status;
  173. int i = 0;
  174. p_status = (void *)((rt_uint32_t)(&PL041->sr1) + channel * 0x14);
  175. p_data = (void *)((rt_uint32_t)(&(PL041->dr1[0])) + channel * 0x20);
  176. for (i = 0; (!(PL041_READ(p_status) & AACI_SR_TXFF)) && (i < count); i++)
  177. {
  178. PL041_WRITE(p_data, buff[i]);
  179. }
  180. return i;
  181. }
  182. int aaci_pl041_channel_cfg(int channel, pl041_cfg_t cgf)
  183. {
  184. rt_uint32_t v;
  185. void *p_rx, *p_tx;
  186. p_rx = (void *)((rt_uint32_t)(&PL041->rxcr1) + channel * 0x14);
  187. p_tx = (void *)((rt_uint32_t)(&PL041->txcr1) + channel * 0x14);
  188. v = AACI_CR_FEN | AACI_CR_SZ16 | cgf->itype;
  189. PL041_WRITE(p_rx, v);
  190. v = AACI_CR_FEN | AACI_CR_SZ16 | cgf->otype;
  191. PL041_WRITE(p_tx, v);
  192. ac97_set_vol(cgf->vol);
  193. ac97_set_rate(cgf->rate);
  194. return 0;
  195. }
  196. void aaci_pl041_irq_enable(int channel, rt_uint32_t vector)
  197. {
  198. rt_uint32_t v;
  199. void *p_irq;
  200. vector &= vector & 0x7f;
  201. p_irq = (void *)((rt_uint32_t)(&PL041->iie1) + channel * 0x14);
  202. v = PL041_READ(p_irq);
  203. v |= vector;
  204. PL041_WRITE(p_irq, v);
  205. }
  206. void aaci_pl041_irq_disable(int channel, rt_uint32_t vector)
  207. {
  208. rt_uint32_t v;
  209. void *p_irq;
  210. vector &= vector & 0x7f;
  211. p_irq = (void *)((rt_uint32_t)(&PL041->iie1) + channel * 0x14);
  212. v = PL041_READ(p_irq);
  213. v &= ~vector;
  214. PL041_WRITE(p_irq, v);
  215. }
  216. rt_err_t aaci_pl041_irq_register(int channel, pl041_irq_fun_t fun, void *user_data)
  217. {
  218. if (channel < 0 || channel >= PL041_CHANNEL_NUM)
  219. {
  220. LOG_E("%s channel:%d err.", __FUNCTION__, channel);
  221. return -RT_ERROR;
  222. }
  223. irq_tbl[channel].fun = fun;
  224. irq_tbl[channel].user_data = user_data;
  225. return RT_EOK;
  226. }
  227. rt_err_t aaci_pl041_irq_unregister(int channel)
  228. {
  229. if (channel < 0 || channel >= PL041_CHANNEL_NUM)
  230. {
  231. LOG_E("%s channel:%d err.", __FUNCTION__, channel);
  232. return -RT_ERROR;
  233. }
  234. irq_tbl[channel].fun = RT_NULL;
  235. irq_tbl[channel].user_data = RT_NULL;
  236. return RT_EOK;
  237. }
  238. static void aaci_pl041_irq_handle(int irqno, void *param)
  239. {
  240. rt_uint32_t mask, channel, m;
  241. struct pl041_irq_def *_irq = param;
  242. void *p_status;
  243. mask = PL041_READ(&PL041->allints);
  244. PL041_WRITE(&PL041->intclr, mask);
  245. for (channel = 0; (channel < PL041_CHANNEL_NUM) && (mask); channel++)
  246. {
  247. mask = mask >> 7;
  248. m = mask & 0x7f;
  249. if (m & AACI_ISR_ORINTR)
  250. {
  251. LOG_W("RX overrun on chan %d", channel);
  252. }
  253. if (m & AACI_ISR_RXTOINTR)
  254. {
  255. LOG_W("RX timeout on chan %d", channel);
  256. }
  257. if (mask & AACI_ISR_URINTR)
  258. {
  259. LOG_W("TX underrun on chan %d", channel);
  260. }
  261. p_status = (void *)((rt_uint32_t)(&PL041->sr1) + channel * 0x14);
  262. if (_irq[channel].fun != RT_NULL)
  263. {
  264. _irq[channel].fun(PL041_READ(p_status), _irq[channel].user_data);
  265. }
  266. }
  267. }
  268. rt_err_t aaci_pl041_init(void)
  269. {
  270. rt_uint32_t i, maincr;
  271. maincr = AACI_MAINCR_SCRA(0) | AACI_MAINCR_IE | AACI_MAINCR_SL1RXEN | \
  272. AACI_MAINCR_SL1TXEN | AACI_MAINCR_SL2RXEN | AACI_MAINCR_SL2TXEN;
  273. for (i = 0; i < 4; i++)
  274. {
  275. void *base = (void *)((rt_uint32_t)(&PL041->rxcr1) + i * 0x14);
  276. PL041_WRITE(base + AACI_IE, 0);
  277. PL041_WRITE(base + AACI_TXCR, 0);
  278. PL041_WRITE(base + AACI_RXCR, 0);
  279. }
  280. PL041_WRITE(&PL041->intclr, 0x1fff);
  281. PL041_WRITE(&PL041->maincr, maincr);
  282. PL041_WRITE(&PL041->reset, 0);
  283. aaci_pl041_delay(2);
  284. PL041_WRITE(&PL041->reset, RESET_NRST);
  285. rt_hw_interrupt_install(43, aaci_pl041_irq_handle, &irq_tbl, "aaci_pl041");
  286. rt_hw_interrupt_umask(43);
  287. return 0;
  288. }
  289. #if 0
  290. #define PL041_DUMP(_v) rt_kprintf("%32s:addr:0x%08x data:0x%08x\n", #_v, &(_v), (_v))
  291. int _aaci_pl041_reg_dump(int argc, char **argv)
  292. {
  293. PL041_DUMP(PL041->rxcr1);
  294. PL041_DUMP(PL041->txcr1);
  295. PL041_DUMP(PL041->sr1);
  296. PL041_DUMP(PL041->isr1);
  297. PL041_DUMP(PL041->iie1);
  298. PL041_DUMP(PL041->rxcr2);
  299. PL041_DUMP(PL041->txcr2);
  300. PL041_DUMP(PL041->sr2);
  301. PL041_DUMP(PL041->isr2);
  302. PL041_DUMP(PL041->iie2);
  303. PL041_DUMP(PL041->rxcr3);
  304. PL041_DUMP(PL041->txcr3);
  305. PL041_DUMP(PL041->sr3);
  306. PL041_DUMP(PL041->isr3);
  307. PL041_DUMP(PL041->iie3);
  308. PL041_DUMP(PL041->rxcr4);
  309. PL041_DUMP(PL041->txcr4);
  310. PL041_DUMP(PL041->sr4);
  311. PL041_DUMP(PL041->isr4);
  312. PL041_DUMP(PL041->iie4);
  313. PL041_DUMP(PL041->sl1rx);
  314. PL041_DUMP(PL041->sl1tx);
  315. PL041_DUMP(PL041->sl2rx);
  316. PL041_DUMP(PL041->sl2tx);
  317. PL041_DUMP(PL041->sl12rx);
  318. PL041_DUMP(PL041->sl12tx);
  319. PL041_DUMP(PL041->slfr);
  320. PL041_DUMP(PL041->slistat);
  321. PL041_DUMP(PL041->slien);
  322. PL041_DUMP(PL041->intclr);
  323. PL041_DUMP(PL041->maincr);
  324. PL041_DUMP(PL041->reset);
  325. PL041_DUMP(PL041->sync);
  326. PL041_DUMP(PL041->allints);
  327. PL041_DUMP(PL041->mainfr);
  328. PL041_DUMP(PL041->dr1[0]);
  329. PL041_DUMP(PL041->dr2[0]);
  330. PL041_DUMP(PL041->dr3[0]);
  331. PL041_DUMP(PL041->dr4[0]);
  332. return 0;
  333. }
  334. MSH_CMD_EXPORT_ALIAS(_aaci_pl041_reg_dump, pl041_dump, aaci pl041 dump reg);
  335. #endif