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