sspd_ac97.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include "hal.h"
  2. #include "dma/dmad.h"
  3. #include "sspd_ac97.h"
  4. /* SSP FIFO properties */
  5. #define SSPD_HW_TXFIFO_DEPTH 16 /* TX FIFO size, units of 32bit (todo: HW readback?) */
  6. #define SSPD_HW_RXFIFO_DEPTH 16 /* RX FIFO size, units of 32bit (todo: HW readback?) */
  7. /*****************************************************************************
  8. * Data size for each each DMA request
  9. *
  10. * Adjust hint:
  11. *
  12. * AC97DMA_REQ_FRAMES sampling_rate effective data_size(2ch) data_size(6ch)
  13. * ------------------------------------------------------------------------------
  14. * 4096 48k (ac97-fix) 85.33 ms 32768 bytes 98304 bytes
  15. * 8192 48k (ac97-fix) 170.66 ms 65536 bytes 196608 bytes
  16. * 10240 48k (ac97-fix) 213.33 ms 81920 bytes 245760 bytes
  17. * 12288 48k (ac97-fix) 256.00 ms 98304 bytes 294912 bytes
  18. * 20480 48k (ac97-fix) 426.66 ms 163840 bytes 491520 bytes
  19. ****************************************************************************/
  20. #define AC97DMA_REQ_FRAMES (20480) /* number of frames */
  21. #define AC97_RESET_WAIT (0x600000) /* polling loop counter for waiting hw-reset */
  22. enum SSPD_AC97_RESET {
  23. SSPD_AC97_COLDRESET, /* All AC97 logic is initialized to its default state */
  24. SSPD_AC97_WARMRESET, /* Contents of AC97 registers are left unaltered */
  25. SSPD_AC97_REGRESET, /* Only Initialize the AC97 registers to their default states */
  26. };
  27. void sspd_ac97_sdata_out(uint32_t *txb, int cnt)
  28. {
  29. while (cnt > 0) {
  30. uint32_t tfve;
  31. /* Check room in TX FIFO */
  32. tfve = MASK32(I2SAC97_SR, SSPC_SR_TFVE_MASK) >> SSPC_SR_TFVE_SHIFT;
  33. /* Burst send to TX FIFO */
  34. while (tfve++ < SSPD_HW_TXFIFO_DEPTH) {
  35. /* Send one 32-bit word to TX FIFO */
  36. OUT32(I2SAC97_DR, *txb++);
  37. if (--cnt == 0)
  38. break;
  39. }
  40. }
  41. }
  42. void sspd_ac97_cmd_out(int regidx, uint32_t data)
  43. {
  44. uint32_t txb[16];
  45. /* Prepare AC97 write register address (slot1) and data (slot2) */
  46. AC97_MAKE_WCMD(txb, regidx, data);
  47. /* Clear SSP FIFO garbage */
  48. SETR32(I2SAC97_CR2, SSPC_C2_RXFCLR_MASK | SSPC_C2_TXFCLR_MASK);
  49. /* Set frame-tag slot-valid bits */
  50. OUT32(I2SAC97_ACLINK, SSPC_AC97_WCMD_SLOTS_MASK | SSPC_AC97_MAKE_CODECID(0));
  51. /* Feed data to TX FIFO -- AC97 CR-write contains 2 slots */
  52. /*
  53. * [??] According to AC97 2.1 spec, stuff bits with 0 has to be at their
  54. * position during the slot's active time. SSP will smart enough to
  55. * identify giving valid slots and auto stuffs 0s to empty slots in TX
  56. * mode? And whot about the same question in RX mode?
  57. */
  58. sspd_ac97_sdata_out(txb, SSPC_AC97_WCMD_SLOTS);
  59. /* Enable SSP TX data out */
  60. SETR32(I2SAC97_CR2, SSPC_C2_TXDOE_MASK | SSPC_C2_SSPEN_MASK);
  61. while (MASK32(I2SAC97_SR, SSPC_SR_TFVE_MASK))
  62. ;
  63. /* Disable SSP TX data out */
  64. CLRR32(I2SAC97_CR2, SSPC_C2_TXDOE_MASK | SSPC_C2_SSPEN_MASK);
  65. }
  66. void sspd_ac97_reset(enum SSPD_AC97_RESET rest_type)
  67. {
  68. uint32_t core_intl;
  69. core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
  70. /* Disable SSP interrupts */
  71. CLRR32(I2SAC97_INTCR, SSPC_INTCR_RFORIEN_MASK | SSPC_INTCR_TFURIEN_MASK |
  72. SSPC_INTCR_RFTHIEN_MASK | SSPC_INTCR_TFTHIEN_MASK |
  73. SSPC_INTCR_RFDMAEN_MASK | SSPC_INTCR_TFDMAEN_MASK |
  74. SSPC_INTCR_AC97FCEN_MASK);
  75. /* Disable SSP data out */
  76. CLRR32(I2SAC97_CR2, SSPC_C2_SSPEN_MASK | SSPC_C2_TXDOE_MASK);
  77. /* Disable DMA request FIFO trigger */
  78. CLRR32(I2SAC97_INTCR, SSPC_INTCR_TFDMAEN_MASK | SSPC_INTCR_RFDMAEN_MASK);
  79. /* Clear FIFO garbage */
  80. SETR32(I2SAC97_CR2, SSPC_C2_RXFCLR_MASK | SSPC_C2_TXFCLR_MASK);
  81. /* Set SSP frame format as AC97 */
  82. SETR32SHL(I2SAC97_CR0, SSPC_C0_FFMT_MASK, SSPC_C0_FFMT_SHIFT, SSPC_INTEL_ACLINK);
  83. switch (rest_type) {
  84. case SSPD_AC97_COLDRESET: /* All AC97 logic is initialized to its default state */
  85. /* (reset time: SSPCLK * SCLK_DIV) */
  86. DEBUG(1, 1, "SSPD_AC97_COLDRESET\n");
  87. SETB32(I2SAC97_CR2, SSPC_C2_ACCRST_BIT);
  88. while (GETB32(I2SAC97_CR2, SSPC_C2_ACCRST_BIT))
  89. ;
  90. _nds_kwait(AC97_RESET_WAIT);
  91. break;
  92. case SSPD_AC97_WARMRESET: /* Contents of AC97 registers are left unaltered */
  93. /* (reset time: SSPCLK * SCLK_DIV, or wait ACWRST cleared) */
  94. DEBUG(1, 1, "SSPD_AC97_WARMRESET\n");
  95. SETB32(I2SAC97_CR2, SSPC_C2_ACWRST_BIT);
  96. while (GETB32(I2SAC97_CR2, SSPC_C2_ACWRST_BIT))
  97. ;
  98. break;
  99. case SSPD_AC97_REGRESET: /* Only Initialize the AC97 registers to their default states */
  100. DEBUG(1, 1, "SSPD_AC97_REGRESET\n");
  101. /* Write AC97 reset register to do codec register reset */
  102. sspd_ac97_cmd_out(AC97_CRIDX_RESET, 0);
  103. _nds_kwait(AC97_RESET_WAIT);
  104. break;
  105. default:
  106. DEBUG(1, 1, "Invalid reset method!\n");
  107. }
  108. hal_global_int_ctl(core_intl);
  109. }
  110. void sspd_ac97_init(void)
  111. {
  112. uint32_t core_intl;
  113. core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
  114. /*
  115. * Change AC97 codec & SSP clock source
  116. *
  117. * PMU_AC97PINSEL: MFPSR[3]
  118. * 0: X_I2Ssclkout/I2SCLK
  119. * 1: X_ac97_resetn/50MHz in AG101
  120. * PMU_AC97CLKSEL: MFPSR[4]
  121. * 0: AC97CLK (Set AC97 XTL_IN source is from internal PLL. BIT_CLK is XTL_IN / 2)
  122. * 1: GPIO22
  123. * PMU_SSPCLKSEL: MFPSR[6]
  124. * 0: SSPCLK
  125. * 1: GPIO25
  126. * PMU_AC97CLKOUTSEL: MFPSR[13]
  127. * 0: GPIO
  128. * 1: AC97CLK out
  129. */
  130. // SETR32(PMU_MFPSR, PMU_AC97PINSEL_MASK | PMU_AC97CLKSEL_MASK | PMU_SSPCLKSEL_MASK | PMU_AC97CLKOUTSEL_MASK);
  131. // SETR32(PMU_MFPSR, PMU_AC97PINSEL_MASK | PMU_AC97CLKOUTSEL_MASK);
  132. // SETB32(PMU_MFPSR, PMU_AC97CLKSEL_BIT);
  133. #if (MB_AC97_EXT_CLK)
  134. DEBUG(1, 1, "AC97CLK: GPIO22\n");
  135. SETR32(PMU_MFPSR, PMU_AC97PINSEL_MASK | PMU_AC97CLKSEL_MASK | PMU_AC97CLKOUTSEL_MASK);
  136. #else /* MB_AC97_EXT_CLK */
  137. DEBUG(1, 1, "AC97CLK: PLL\n");
  138. SETR32(PMU_MFPSR, PMU_AC97PINSEL_MASK | PMU_AC97CLKOUTSEL_MASK);
  139. CLRB32(PMU_MFPSR, PMU_AC97CLKSEL_BIT);
  140. #endif /* MB_AC97_EXT_CLK */
  141. sspd_ac97_reset(SSPD_AC97_COLDRESET);
  142. /* Setup DMA FIFO trigger threshold */
  143. SETR32SHL(I2SAC97_INTCR, SSPC_INTCR_TFTHOD_MASK, SSPC_INTCR_TFTHOD_SHIFT, 0);
  144. SETR32SHL(I2SAC97_INTCR, SSPC_INTCR_RFTHOD_MASK, SSPC_INTCR_RFTHOD_SHIFT, 0);
  145. /* SSP AC97 codec initialization */
  146. /*
  147. * Default master volume?
  148. * Default mixer-in gain?
  149. * Default record input selection?
  150. */
  151. //sspd_ac97_cmd_out(AC97_CRIDX_MASTER_VOLUME, 0);
  152. hal_global_int_ctl(core_intl);
  153. }
  154. void sspd_ac97_terminate(void)
  155. {
  156. uint32_t core_intl;
  157. core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
  158. /* Disable SSP interrupts */
  159. CLRR32(I2SAC97_INTCR, SSPC_INTCR_RFORIEN_MASK | SSPC_INTCR_TFURIEN_MASK |
  160. SSPC_INTCR_RFTHIEN_MASK | SSPC_INTCR_TFTHIEN_MASK |
  161. SSPC_INTCR_RFDMAEN_MASK | SSPC_INTCR_TFDMAEN_MASK |
  162. SSPC_INTCR_AC97FCEN_MASK);
  163. /* Disable SSP data out */
  164. CLRR32(I2SAC97_CR2, SSPC_C2_SSPEN_MASK | SSPC_C2_TXDOE_MASK);
  165. /* Cold reset AC97 codec */
  166. SETB32(I2SAC97_CR2, SSPC_C2_ACCRST_BIT);
  167. while (GETB32(I2SAC97_CR2, SSPC_C2_ACCRST_BIT))
  168. ;
  169. /* Clear FIFO garbage */
  170. SETR32(I2SAC97_CR2, SSPC_C2_RXFCLR_MASK | SSPC_C2_TXFCLR_MASK);
  171. hal_global_int_ctl(core_intl);
  172. }
  173. void ac97_init(void)
  174. {
  175. sspd_ac97_init();
  176. sspd_ac97_cmd_out(AC97_CRIDX_RESET, 0);
  177. _nds_kwait(AC97_RESET_WAIT);
  178. sspd_ac97_cmd_out(AC97_CRIDX_PCMOUT_GAIN,
  179. AC97_MIXER_GAIN(AC97_MIXER_MAX, AC97_MIXER_MAX));
  180. sspd_ac97_cmd_out(AC97_CRIDX_MASTER_VOLUME,
  181. AC97_STEREO_VOLUME(AC97_VOLUME_MAX - 0x30, AC97_VOLUME_MAX - 0x30));
  182. SETR32SHL(I2SAC97_INTCR, SSPC_INTCR_TFTHOD_MASK, SSPC_INTCR_TFTHOD_SHIFT, 4);
  183. SETR32SHL(I2SAC97_INTCR, SSPC_INTCR_RFTHOD_MASK, SSPC_INTCR_RFTHOD_SHIFT, 4);
  184. OUT32(I2SAC97_ACLINK, SSPC_AC97_PCM_SLOTS_MASK | SSPC_AC97_MAKE_CODECID(0));
  185. SETR32(I2SAC97_INTCR, SSPC_INTCR_TFDMAEN_MASK);
  186. SETR32(I2SAC97_CR2, SSPC_C2_TXDOE_MASK | SSPC_C2_SSPEN_MASK);
  187. SETR32(I2SAC97_CR2, SSPC_C2_RXFCLR_MASK | SSPC_C2_TXFCLR_MASK);
  188. }
  189. volatile int g_buffered_frames;
  190. /* No use and marked by KCLin */
  191. /*
  192. static void psp(void *data)
  193. {
  194. g_buffered_frames -= *(int*)data;
  195. free(data);
  196. }
  197. */
  198. static void rcp(void *data)
  199. {
  200. g_buffered_frames -= *(int*)data;
  201. free(data);
  202. }
  203. extern int ring_idx;
  204. void ac97_play(int frames, uint32_t *pcm_data, void *ac97_data)
  205. {
  206. DMAD_CHANNEL_REQUEST_DESC *ch_req = ac97_data;
  207. while (frames > 0){
  208. int f;
  209. int *data;
  210. DMAD_DRB *drb;
  211. f = (frames < AC97DMA_REQ_FRAMES) ? frames : AC97DMA_REQ_FRAMES;
  212. data = malloc(sizeof(int));
  213. KASSERT(data);
  214. *data = f;
  215. _dmad_alloc_drb(ch_req, &drb);
  216. drb->src_addr = pcm_data;
  217. drb->dst_addr = (void *)I2SAC97_DR;
  218. drb->req_size = (f << 1); /* units of data width (32bit for AC97) */
  219. drb->rcp = rcp;
  220. drb->data = data;
  221. pcm_data += (f << 1);
  222. g_buffered_frames += f;
  223. // DEBUG(1, 1, "FRAME: %d,%d\n", g_buffered_frames,ring_idx);
  224. _dmad_submit_request(ch_req, drb);
  225. frames -= f;
  226. }
  227. }