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