1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hisoc/uart.h"
17 #include "los_magickey.h"
18 #include "los_task.h"
19 #include "hdf_log.h"
20 #include "osal_io.h"
21 #include "osal_irq.h"
22 #include "osal_time.h"
23 #include "uart_pl011.h"
24 
25 #define HDF_LOG_TAG       uart_pl011
26 #define FIFO_SIZE         128
27 #define UART_WAIT_MS      10
28 #define IBRD_COEFFICIENTS 16
29 #define FBRD_COEFFICIENTS 8
Pl011Irq(uint32_t irq, void *data)30 static uint32_t Pl011Irq(uint32_t irq, void *data)
31 {
32     uint32_t status;
33     uint32_t fr;
34     char buf[FIFO_SIZE];
35     uint32_t count = 0;
36     struct UartPl011Port *port = NULL;
37     struct UartDriverData *udd = (struct UartDriverData *)data;
38 
39     UNUSED(irq);
40     if (udd == NULL || udd->private == NULL) {
41         HDF_LOGE("%s: invalid parame", __func__);
42         return HDF_FAILURE;
43     }
44     port = (struct UartPl011Port *)udd->private;
45     status = OSAL_READW(port->physBase + UART_MIS);
46     if (status & (UART_MIS_RX | UART_IMSC_TIMEOUT)) {
47         do {
48             fr = OSAL_READB(port->physBase + UART_FR);
49             if (fr & UART_FR_RXFE) {
50                 break;
51             }
52             buf[count++] = OSAL_READB(port->physBase + UART_DR);
53             if (udd->num != CONSOLE_UART) {
54                 continue;
55             }
56             if (CheckMagicKey(buf[count - 1], CONSOLE_SERIAL)) {
57                 goto end;
58             }
59         } while (count < FIFO_SIZE);
60         udd->recv(udd, buf, count);
61     }
62 end:
63     /* clear all interrupt */
64     OSAL_WRITEW(0xFFFF, port->physBase + UART_CLR);
65     return HDF_SUCCESS;
66 }
67 
Pl011ConfigBaudrate(const struct UartDriverData *udd, const struct UartPl011Port *port)68 static void Pl011ConfigBaudrate(const struct UartDriverData *udd, const struct UartPl011Port *port)
69 {
70     uint64_t tmp;
71     uint32_t value;
72     uint32_t divider;
73     uint32_t remainder;
74     uint32_t fraction;
75 
76     tmp = (uint64_t)IBRD_COEFFICIENTS * (uint64_t)udd->baudrate;
77     if (tmp == 0 || tmp > UINT32_MAX) {
78         HDF_LOGE("%s: err, baudrate %u is invalid", __func__, udd->baudrate);
79         return;
80     }
81 
82     value = IBRD_COEFFICIENTS * udd->baudrate;
83     divider = CONFIG_UART_CLK_INPUT / value;
84     remainder = CONFIG_UART_CLK_INPUT % value;
85     value = (FBRD_COEFFICIENTS * remainder) / udd->baudrate;
86     fraction = (value >> 1) + (value & 1);
87     OSAL_WRITEL(divider, port->physBase + UART_IBRD);
88     OSAL_WRITEL(fraction, port->physBase + UART_FBRD);
89 }
90 
Pl011ConfigDataBits(const struct UartDriverData *udd, uint32_t *lcrh)91 static void Pl011ConfigDataBits(const struct UartDriverData *udd, uint32_t *lcrh)
92 {
93     *lcrh &= ~UART_LCR_H_8_BIT;
94     switch (udd->attr.dataBits) {
95         case UART_ATTR_DATABIT_5:
96             *lcrh |= UART_LCR_H_5_BIT;
97             break;
98         case UART_ATTR_DATABIT_6:
99             *lcrh |= UART_LCR_H_6_BIT;
100             break;
101         case UART_ATTR_DATABIT_7:
102             *lcrh |= UART_LCR_H_7_BIT;
103             break;
104         case UART_ATTR_DATABIT_8:
105         default:
106             *lcrh |= UART_LCR_H_8_BIT;
107             break;
108     }
109 }
110 
Pl011ConfigParity(const struct UartDriverData *udd, uint32_t *lcrh)111 static void Pl011ConfigParity(const struct UartDriverData *udd, uint32_t *lcrh)
112 {
113     switch (udd->attr.parity) {
114         case UART_ATTR_PARITY_EVEN:
115             *lcrh |= UART_LCR_H_PEN;
116             *lcrh |= UART_LCR_H_EPS;
117             *lcrh |= UART_LCR_H_FIFO_EN;
118             break;
119         case UART_ATTR_PARITY_ODD:
120             *lcrh |= UART_LCR_H_PEN;
121             *lcrh &= ~UART_LCR_H_EPS;
122             *lcrh |= UART_LCR_H_FIFO_EN;
123             break;
124         case UART_ATTR_PARITY_MARK:
125             *lcrh |= UART_LCR_H_PEN;
126             *lcrh &= ~UART_LCR_H_EPS;
127             *lcrh |= UART_LCR_H_FIFO_EN;
128             *lcrh |= UART_LCR_H_SPS;
129             break;
130         case UART_ATTR_PARITY_SPACE:
131             *lcrh |= UART_LCR_H_PEN;
132             *lcrh |= UART_LCR_H_EPS;
133             *lcrh |= UART_LCR_H_FIFO_EN;
134             *lcrh |= UART_LCR_H_SPS;
135             break;
136         case UART_ATTR_PARITY_NONE:
137         default:
138             *lcrh &= ~UART_LCR_H_PEN;
139             *lcrh &= ~UART_LCR_H_SPS;
140             break;
141     }
142 }
143 
Pl011ConfigStopBits(const struct UartDriverData *udd, uint32_t *lcrh)144 static void Pl011ConfigStopBits(const struct UartDriverData *udd, uint32_t *lcrh)
145 {
146     switch (udd->attr.stopBits) {
147         case UART_ATTR_STOPBIT_2:
148             *lcrh |= UART_LCR_H_STP2;
149             break;
150         case UART_ATTR_STOPBIT_1:
151         default:
152             *lcrh &= ~UART_LCR_H_STP2;
153             break;
154     }
155 }
156 
Pl011ConfigLCRH(const struct UartDriverData *udd, const struct UartPl011Port *port, uint32_t lcrh)157 static void Pl011ConfigLCRH(const struct UartDriverData *udd, const struct UartPl011Port *port, uint32_t lcrh)
158 {
159     Pl011ConfigDataBits(udd, &lcrh);
160     lcrh &= ~UART_LCR_H_PEN;
161     lcrh &= ~UART_LCR_H_EPS;
162     lcrh &= ~UART_LCR_H_SPS;
163     Pl011ConfigParity(udd, &lcrh);
164     Pl011ConfigStopBits(udd, &lcrh);
165     if (udd->attr.fifoRxEn || udd->attr.fifoTxEn) {
166         lcrh |= UART_LCR_H_FIFO_EN;
167     }
168     OSAL_WRITEB(lcrh, port->physBase + UART_LCR_H);
169 }
170 
Pl011ConfigIn(struct UartDriverData *udd)171 static int32_t Pl011ConfigIn(struct UartDriverData *udd)
172 {
173     uint32_t cr;
174     uint32_t lcrh;
175     struct UartPl011Port *port = NULL;
176 
177     port = (struct UartPl011Port *)udd->private;
178     if (port == NULL) {
179         HDF_LOGE("%s: port is NULL", __func__);
180         return HDF_ERR_INVALID_PARAM;
181     }
182     /* get CR */
183     cr = OSAL_READW(port->physBase + UART_CR);
184     /* get LCR_H */
185     lcrh = OSAL_READW(port->physBase + UART_LCR_H);
186     /* uart disable */
187     OSAL_WRITEW(0, port->physBase + UART_CR);
188     /* config cts/rts */
189     if (UART_ATTR_CTS_EN == udd->attr.cts) {
190         cr |= UART_CR_CTS;
191     } else {
192         cr &= ~UART_CR_CTS;
193     }
194     if (UART_ATTR_RTS_EN == udd->attr.rts) {
195         cr |= UART_CR_RTS;
196     } else {
197         cr &= ~UART_CR_RTS;
198     }
199     lcrh &= ~UART_LCR_H_FIFO_EN;
200     OSAL_WRITEB(lcrh, port->physBase + UART_LCR_H);
201 
202     cr &= ~UART_CR_EN;
203     OSAL_WRITEW(cr, port->physBase + UART_CR);
204 
205     /* set baud rate */
206     Pl011ConfigBaudrate(udd, port);
207 
208     /* config lcr_h */
209     Pl011ConfigLCRH(udd, port, lcrh);
210 
211     cr |= UART_CR_EN;
212     /* resume CR */
213     OSAL_WRITEW(cr, port->physBase + UART_CR);
214     return HDF_SUCCESS;
215 }
216 
Pl011StartUp(struct UartDriverData *udd)217 static int32_t Pl011StartUp(struct UartDriverData *udd)
218 {
219     int32_t ret;
220     uint32_t cr;
221     struct UartPl011Port *port = NULL;
222 
223     if (udd == NULL) {
224         HDF_LOGE("%s: udd is null", __func__);
225         return HDF_ERR_INVALID_PARAM;
226     }
227     port = (struct UartPl011Port *)udd->private;
228     if (port == NULL) {
229         HDF_LOGE("%s: port is null", __func__);
230         return HDF_ERR_INVALID_PARAM;
231     }
232     /* enable the clock */
233     LOS_TaskLock();
234     uart_clk_cfg(udd->num, true);
235     LOS_TaskUnlock();
236     /* uart disable */
237     OSAL_WRITEW(0, port->physBase + UART_CR);
238     OSAL_WRITEW(0xFF, port->physBase + UART_RSR);
239     /* clear all interrupt,set mask */
240     OSAL_WRITEW(0xFFFF, port->physBase + UART_CLR);
241     /* mask all interrupt */
242     OSAL_WRITEW(0x0, port->physBase + UART_IMSC);
243     /* interrupt trigger line RX: 4/8, TX 7/8 */
244     OSAL_WRITEW(UART_IFLS_RX4_8 | UART_IFLS_TX7_8, port->physBase + UART_IFLS);
245     if (!(udd->flags & UART_FLG_DMA_RX)) {
246         if (!(port->flags & PL011_FLG_IRQ_REQUESTED)) {
247             ret = OsalRegisterIrq(port->irqNum, 0, Pl011Irq, "uart_pl011", udd);
248             if (ret == 0) {
249                 port->flags |= PL011_FLG_IRQ_REQUESTED;
250                 /* enable rx and timeout interrupt */
251                 OSAL_WRITEW(UART_IMSC_RX | UART_IMSC_TIMEOUT, port->physBase + UART_IMSC);
252             }
253         }
254     }
255     cr = OSAL_READW(port->physBase + UART_CR);
256     cr |= UART_CR_EN | UART_CR_RX_EN | UART_CR_TX_EN;
257     OSAL_WRITEL(cr, port->physBase + UART_CR);
258     ret = Pl011ConfigIn(udd);
259     return ret;
260 }
261 
Pl011ShutDown(struct UartDriverData *udd)262 static int32_t Pl011ShutDown(struct UartDriverData *udd)
263 {
264     uint32_t reg_tmp;
265     struct UartPl011Port *port = NULL;
266 
267     if (udd == NULL) {
268         HDF_LOGE("%s: udd is null", __func__);
269         return HDF_ERR_INVALID_PARAM;
270     }
271     port = (struct UartPl011Port *)udd->private;
272     if (port == NULL) {
273         HDF_LOGE("%s: port is null", __func__);
274         return HDF_ERR_INVALID_PARAM;
275     }
276     OSAL_WRITEW(0, port->physBase + UART_IMSC);
277     OSAL_WRITEW(0xFFFF, port->physBase + UART_CLR);
278     if (port->flags & PL011_FLG_IRQ_REQUESTED) {
279         OsalUnregisterIrq(port->irqNum, udd);
280         port->flags &= ~PL011_FLG_IRQ_REQUESTED;
281     }
282 
283     reg_tmp = OSAL_READW(port->physBase + UART_CR);
284     reg_tmp &= ~UART_CR_TX_EN;
285     reg_tmp &= ~UART_CR_RX_EN;
286     reg_tmp &= ~UART_CR_EN;
287     OSAL_WRITEW(reg_tmp, port->physBase + UART_CR);
288 
289     /* disable break and fifo */
290     reg_tmp = OSAL_READW(port->physBase + UART_LCR_H);
291     reg_tmp &= ~(UART_LCR_H_BREAK);
292     reg_tmp &= ~(UART_LCR_H_FIFO_EN);
293     OSAL_WRITEW(reg_tmp, port->physBase + UART_LCR_H);
294 
295     /* shut down the clock */
296     LOS_TaskLock();
297     uart_clk_cfg(udd->num, false);
298     LOS_TaskUnlock();
299     return HDF_SUCCESS;
300 }
301 
Pl011StartTx(struct UartDriverData *udd, const char *buf, size_t count)302 static int32_t Pl011StartTx(struct UartDriverData *udd, const char *buf, size_t count)
303 {
304     struct UartPl011Port *port = NULL;
305 
306     if (udd == NULL || buf == NULL || count == 0) {
307         HDF_LOGE("%s: invalid parame", __func__);
308         return HDF_ERR_INVALID_PARAM;
309     }
310     port = (struct UartPl011Port *)udd->private;
311     if (port == NULL) {
312         HDF_LOGE("%s: port is null", __func__);
313         return HDF_ERR_INVALID_PARAM;
314     }
315     /* UART_WITH_LOCK: there is a spinlock in the function to write reg in order. */
316     (void)UartPutsReg(port->physBase, buf, count, UART_WITH_LOCK);
317     return HDF_SUCCESS;
318 }
319 
Pl011Config(struct UartDriverData *udd)320 static int32_t Pl011Config(struct UartDriverData *udd)
321 {
322     uint32_t fr;
323     struct UartPl011Port *port = NULL;
324 
325     if (udd == NULL) {
326         HDF_LOGE("%s: udd is null", __func__);
327         return HDF_ERR_INVALID_PARAM;
328     }
329     port = (struct UartPl011Port *)udd->private;
330     if (port == NULL) {
331         HDF_LOGE("%s: port is null", __func__);
332         return HDF_ERR_INVALID_PARAM;
333     }
334     /* wait for send finish */
335     do {
336         fr = OSAL_READB(port->physBase + UART_FR);
337         if (!(fr & UART_FR_BUSY)) {
338             break;
339         }
340         OsalMSleep(UART_WAIT_MS);
341     } while (1);
342     return Pl011ConfigIn(udd);
343 }
344 
345 struct UartOps g_pl011Uops = {
346     .StartUp        = Pl011StartUp,
347     .ShutDown       = Pl011ShutDown,
348     .StartTx        = Pl011StartTx,
349     .Config         = Pl011Config,
350     .DmaStartUp     = NULL,
351     .DmaShutDown    = NULL,
352 };
353 
Pl011Read(struct UartDriverData *udd, char *buf, size_t count)354 int32_t Pl011Read(struct UartDriverData *udd, char *buf, size_t count)
355 {
356     uint32_t wp;
357     uint32_t rp;
358     uint32_t upperHalf;
359     uint32_t lowerHalf = 0;
360     unsigned long data;
361 
362     if (udd == NULL || buf == NULL || count == 0 || udd->rxTransfer == NULL) {
363         HDF_LOGE("%s: invalid parameter", __func__);
364         return HDF_ERR_INVALID_PARAM;
365     }
366     wp = udd->rxTransfer->wp;
367     rp = udd->rxTransfer->rp;
368     data = (unsigned long)(udd->rxTransfer->data);
369 
370     if (rp == wp) {
371         return 0; // buffer empty
372     }
373 
374     if (rp < wp) { // rp behind
375         upperHalf = (count > (wp - rp)) ? (wp - rp) : count;
376         if (upperHalf > 0 && memcpy_s(buf, upperHalf, (void *)(data + rp), upperHalf) != EOK) {
377             return HDF_ERR_IO;
378         }
379         rp += upperHalf;
380     } else { // wp behind
381         count = (count > (BUF_SIZE - rp + wp)) ? (BUF_SIZE - rp + wp) : count;
382         upperHalf = (count > (BUF_SIZE - rp)) ? (BUF_SIZE - rp) : count;
383         lowerHalf = (count > (BUF_SIZE - rp)) ? (count - (BUF_SIZE - rp)) : 0;
384         if (upperHalf > 0 && memcpy_s(buf, upperHalf, (void *)(data + rp), upperHalf) != EOK) {
385             return HDF_ERR_IO;
386         }
387         if (lowerHalf > 0 && memcpy_s(buf + upperHalf, lowerHalf, (void *)(data), lowerHalf) != EOK) {
388             return HDF_ERR_IO;
389         }
390         rp += upperHalf;
391         if (rp >= BUF_SIZE) {
392             rp = lowerHalf;
393         }
394     }
395     udd->rxTransfer->rp = rp;
396     return (upperHalf + lowerHalf);
397 }
398 
Pl011Notify(struct wait_queue_head *wait)399 static int32_t Pl011Notify(struct wait_queue_head *wait)
400 {
401     if (wait == NULL) {
402         return HDF_ERR_INVALID_PARAM;
403     }
404     LOS_EventWrite(&wait->stEvent, 0x1);
405     notify_poll(wait);
406     return HDF_SUCCESS;
407 }
408 
PL011UartRecvNotify(struct UartDriverData *udd, const char *buf, size_t count)409 int32_t PL011UartRecvNotify(struct UartDriverData *udd, const char *buf, size_t count)
410 {
411     uint32_t wp;
412     uint32_t rp;
413     uint32_t upperHalf;
414     uint32_t lowerHalf = 0;
415     unsigned long data;
416 
417     if (udd == NULL || buf == NULL || count == 0 || udd->rxTransfer == NULL) {
418         HDF_LOGE("%s: invalid parameter", __func__);
419         return HDF_ERR_INVALID_PARAM;
420     }
421     wp = udd->rxTransfer->wp;
422     rp = udd->rxTransfer->rp;
423     data = (unsigned long)(udd->rxTransfer->data);
424 
425     if (wp < rp) { // wp behind
426         upperHalf = (count > (rp - wp - 1)) ? (rp - wp - 1) : count;
427         if (upperHalf > 0 && memcpy_s((void *)(data + wp), upperHalf, buf, upperHalf) != EOK) {
428             return HDF_ERR_IO;
429         }
430         wp += upperHalf;
431     } else { // rp behind
432         count = (count > ((BUF_SIZE - wp) + rp - 1)) ? (BUF_SIZE - wp) + rp - 1 : count;
433         upperHalf = (count > (BUF_SIZE - wp)) ? (BUF_SIZE - wp) : count;
434         lowerHalf = (count > (BUF_SIZE - wp)) ? (count - (BUF_SIZE - wp)) : 0;
435         if (upperHalf > 0 && memcpy_s((void *)(data + wp), upperHalf, buf, upperHalf) != EOK) {
436             return HDF_ERR_IO;
437         }
438         if (lowerHalf > 0 && memcpy_s((void *)(data), lowerHalf, buf + upperHalf, lowerHalf) != EOK) {
439             return HDF_ERR_IO;
440         }
441         wp += upperHalf;
442         if (wp >= BUF_SIZE) {
443             wp = lowerHalf;
444         }
445     }
446 
447     if (Pl011Notify(&udd->wait) != HDF_SUCCESS) {
448         HDF_LOGE("%s: Pl011 notify err", __func__);
449         return HDF_FAILURE;
450     }
451     udd->rxTransfer->wp = wp;
452     return (upperHalf + lowerHalf);
453 }
454 
PL011UartRxBufEmpty(struct UartDriverData *udd)455 bool PL011UartRxBufEmpty(struct UartDriverData *udd)
456 {
457     struct UartTransfer *transfer = udd->rxTransfer;
458     return (transfer->wp == transfer->rp);
459 }
460 
Pl011GetOps(void)461 struct UartOps *Pl011GetOps(void)
462 {
463     return &g_pl011Uops;
464 }
465