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