11bd4fe43Sopenharmony_ci/*
21bd4fe43Sopenharmony_ci * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
31bd4fe43Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
41bd4fe43Sopenharmony_ci * you may not use this file except in compliance with the License.
51bd4fe43Sopenharmony_ci * You may obtain a copy of the License at
61bd4fe43Sopenharmony_ci *
71bd4fe43Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
81bd4fe43Sopenharmony_ci *
91bd4fe43Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
101bd4fe43Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
111bd4fe43Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121bd4fe43Sopenharmony_ci * See the License for the specific language governing permissions and
131bd4fe43Sopenharmony_ci * limitations under the License.
141bd4fe43Sopenharmony_ci */
151bd4fe43Sopenharmony_ci
161bd4fe43Sopenharmony_ci#include "hisoc/uart.h"
171bd4fe43Sopenharmony_ci#include "los_magickey.h"
181bd4fe43Sopenharmony_ci#include "los_task.h"
191bd4fe43Sopenharmony_ci#include "hdf_log.h"
201bd4fe43Sopenharmony_ci#include "osal_io.h"
211bd4fe43Sopenharmony_ci#include "osal_irq.h"
221bd4fe43Sopenharmony_ci#include "osal_time.h"
231bd4fe43Sopenharmony_ci#include "uart_pl011.h"
241bd4fe43Sopenharmony_ci
251bd4fe43Sopenharmony_ci#define HDF_LOG_TAG       uart_pl011
261bd4fe43Sopenharmony_ci#define FIFO_SIZE         128
271bd4fe43Sopenharmony_ci#define UART_WAIT_MS      10
281bd4fe43Sopenharmony_ci#define IBRD_COEFFICIENTS 16
291bd4fe43Sopenharmony_ci#define FBRD_COEFFICIENTS 8
301bd4fe43Sopenharmony_cistatic uint32_t Pl011Irq(uint32_t irq, void *data)
311bd4fe43Sopenharmony_ci{
321bd4fe43Sopenharmony_ci    uint32_t status;
331bd4fe43Sopenharmony_ci    uint32_t fr;
341bd4fe43Sopenharmony_ci    char buf[FIFO_SIZE];
351bd4fe43Sopenharmony_ci    uint32_t count = 0;
361bd4fe43Sopenharmony_ci    struct UartPl011Port *port = NULL;
371bd4fe43Sopenharmony_ci    struct UartDriverData *udd = (struct UartDriverData *)data;
381bd4fe43Sopenharmony_ci
391bd4fe43Sopenharmony_ci    UNUSED(irq);
401bd4fe43Sopenharmony_ci    if (udd == NULL || udd->private == NULL) {
411bd4fe43Sopenharmony_ci        HDF_LOGE("%s: invalid parame", __func__);
421bd4fe43Sopenharmony_ci        return HDF_FAILURE;
431bd4fe43Sopenharmony_ci    }
441bd4fe43Sopenharmony_ci    port = (struct UartPl011Port *)udd->private;
451bd4fe43Sopenharmony_ci    status = OSAL_READW(port->physBase + UART_MIS);
461bd4fe43Sopenharmony_ci    if (status & (UART_MIS_RX | UART_IMSC_TIMEOUT)) {
471bd4fe43Sopenharmony_ci        do {
481bd4fe43Sopenharmony_ci            fr = OSAL_READB(port->physBase + UART_FR);
491bd4fe43Sopenharmony_ci            if (fr & UART_FR_RXFE) {
501bd4fe43Sopenharmony_ci                break;
511bd4fe43Sopenharmony_ci            }
521bd4fe43Sopenharmony_ci            buf[count++] = OSAL_READB(port->physBase + UART_DR);
531bd4fe43Sopenharmony_ci            if (udd->num != CONSOLE_UART) {
541bd4fe43Sopenharmony_ci                continue;
551bd4fe43Sopenharmony_ci            }
561bd4fe43Sopenharmony_ci            if (CheckMagicKey(buf[count - 1], CONSOLE_SERIAL)) {
571bd4fe43Sopenharmony_ci                goto end;
581bd4fe43Sopenharmony_ci            }
591bd4fe43Sopenharmony_ci        } while (count < FIFO_SIZE);
601bd4fe43Sopenharmony_ci        udd->recv(udd, buf, count);
611bd4fe43Sopenharmony_ci    }
621bd4fe43Sopenharmony_ciend:
631bd4fe43Sopenharmony_ci    /* clear all interrupt */
641bd4fe43Sopenharmony_ci    OSAL_WRITEW(0xFFFF, port->physBase + UART_CLR);
651bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
661bd4fe43Sopenharmony_ci}
671bd4fe43Sopenharmony_ci
681bd4fe43Sopenharmony_cistatic void Pl011ConfigBaudrate(const struct UartDriverData *udd, const struct UartPl011Port *port)
691bd4fe43Sopenharmony_ci{
701bd4fe43Sopenharmony_ci    uint64_t tmp;
711bd4fe43Sopenharmony_ci    uint32_t value;
721bd4fe43Sopenharmony_ci    uint32_t divider;
731bd4fe43Sopenharmony_ci    uint32_t remainder;
741bd4fe43Sopenharmony_ci    uint32_t fraction;
751bd4fe43Sopenharmony_ci
761bd4fe43Sopenharmony_ci    tmp = (uint64_t)IBRD_COEFFICIENTS * (uint64_t)udd->baudrate;
771bd4fe43Sopenharmony_ci    if (tmp == 0 || tmp > UINT32_MAX) {
781bd4fe43Sopenharmony_ci        HDF_LOGE("%s: err, baudrate %u is invalid", __func__, udd->baudrate);
791bd4fe43Sopenharmony_ci        return;
801bd4fe43Sopenharmony_ci    }
811bd4fe43Sopenharmony_ci
821bd4fe43Sopenharmony_ci    value = IBRD_COEFFICIENTS * udd->baudrate;
831bd4fe43Sopenharmony_ci    divider = CONFIG_UART_CLK_INPUT / value;
841bd4fe43Sopenharmony_ci    remainder = CONFIG_UART_CLK_INPUT % value;
851bd4fe43Sopenharmony_ci    value = (FBRD_COEFFICIENTS * remainder) / udd->baudrate;
861bd4fe43Sopenharmony_ci    fraction = (value >> 1) + (value & 1);
871bd4fe43Sopenharmony_ci    OSAL_WRITEL(divider, port->physBase + UART_IBRD);
881bd4fe43Sopenharmony_ci    OSAL_WRITEL(fraction, port->physBase + UART_FBRD);
891bd4fe43Sopenharmony_ci}
901bd4fe43Sopenharmony_ci
911bd4fe43Sopenharmony_cistatic void Pl011ConfigDataBits(const struct UartDriverData *udd, uint32_t *lcrh)
921bd4fe43Sopenharmony_ci{
931bd4fe43Sopenharmony_ci    *lcrh &= ~UART_LCR_H_8_BIT;
941bd4fe43Sopenharmony_ci    switch (udd->attr.dataBits) {
951bd4fe43Sopenharmony_ci        case UART_ATTR_DATABIT_5:
961bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_5_BIT;
971bd4fe43Sopenharmony_ci            break;
981bd4fe43Sopenharmony_ci        case UART_ATTR_DATABIT_6:
991bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_6_BIT;
1001bd4fe43Sopenharmony_ci            break;
1011bd4fe43Sopenharmony_ci        case UART_ATTR_DATABIT_7:
1021bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_7_BIT;
1031bd4fe43Sopenharmony_ci            break;
1041bd4fe43Sopenharmony_ci        case UART_ATTR_DATABIT_8:
1051bd4fe43Sopenharmony_ci        default:
1061bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_8_BIT;
1071bd4fe43Sopenharmony_ci            break;
1081bd4fe43Sopenharmony_ci    }
1091bd4fe43Sopenharmony_ci}
1101bd4fe43Sopenharmony_ci
1111bd4fe43Sopenharmony_cistatic void Pl011ConfigParity(const struct UartDriverData *udd, uint32_t *lcrh)
1121bd4fe43Sopenharmony_ci{
1131bd4fe43Sopenharmony_ci    switch (udd->attr.parity) {
1141bd4fe43Sopenharmony_ci        case UART_ATTR_PARITY_EVEN:
1151bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_PEN;
1161bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_EPS;
1171bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_FIFO_EN;
1181bd4fe43Sopenharmony_ci            break;
1191bd4fe43Sopenharmony_ci        case UART_ATTR_PARITY_ODD:
1201bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_PEN;
1211bd4fe43Sopenharmony_ci            *lcrh &= ~UART_LCR_H_EPS;
1221bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_FIFO_EN;
1231bd4fe43Sopenharmony_ci            break;
1241bd4fe43Sopenharmony_ci        case UART_ATTR_PARITY_MARK:
1251bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_PEN;
1261bd4fe43Sopenharmony_ci            *lcrh &= ~UART_LCR_H_EPS;
1271bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_FIFO_EN;
1281bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_SPS;
1291bd4fe43Sopenharmony_ci            break;
1301bd4fe43Sopenharmony_ci        case UART_ATTR_PARITY_SPACE:
1311bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_PEN;
1321bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_EPS;
1331bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_FIFO_EN;
1341bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_SPS;
1351bd4fe43Sopenharmony_ci            break;
1361bd4fe43Sopenharmony_ci        case UART_ATTR_PARITY_NONE:
1371bd4fe43Sopenharmony_ci        default:
1381bd4fe43Sopenharmony_ci            *lcrh &= ~UART_LCR_H_PEN;
1391bd4fe43Sopenharmony_ci            *lcrh &= ~UART_LCR_H_SPS;
1401bd4fe43Sopenharmony_ci            break;
1411bd4fe43Sopenharmony_ci    }
1421bd4fe43Sopenharmony_ci}
1431bd4fe43Sopenharmony_ci
1441bd4fe43Sopenharmony_cistatic void Pl011ConfigStopBits(const struct UartDriverData *udd, uint32_t *lcrh)
1451bd4fe43Sopenharmony_ci{
1461bd4fe43Sopenharmony_ci    switch (udd->attr.stopBits) {
1471bd4fe43Sopenharmony_ci        case UART_ATTR_STOPBIT_2:
1481bd4fe43Sopenharmony_ci            *lcrh |= UART_LCR_H_STP2;
1491bd4fe43Sopenharmony_ci            break;
1501bd4fe43Sopenharmony_ci        case UART_ATTR_STOPBIT_1:
1511bd4fe43Sopenharmony_ci        default:
1521bd4fe43Sopenharmony_ci            *lcrh &= ~UART_LCR_H_STP2;
1531bd4fe43Sopenharmony_ci            break;
1541bd4fe43Sopenharmony_ci    }
1551bd4fe43Sopenharmony_ci}
1561bd4fe43Sopenharmony_ci
1571bd4fe43Sopenharmony_cistatic void Pl011ConfigLCRH(const struct UartDriverData *udd, const struct UartPl011Port *port, uint32_t lcrh)
1581bd4fe43Sopenharmony_ci{
1591bd4fe43Sopenharmony_ci    Pl011ConfigDataBits(udd, &lcrh);
1601bd4fe43Sopenharmony_ci    lcrh &= ~UART_LCR_H_PEN;
1611bd4fe43Sopenharmony_ci    lcrh &= ~UART_LCR_H_EPS;
1621bd4fe43Sopenharmony_ci    lcrh &= ~UART_LCR_H_SPS;
1631bd4fe43Sopenharmony_ci    Pl011ConfigParity(udd, &lcrh);
1641bd4fe43Sopenharmony_ci    Pl011ConfigStopBits(udd, &lcrh);
1651bd4fe43Sopenharmony_ci    if (udd->attr.fifoRxEn || udd->attr.fifoTxEn) {
1661bd4fe43Sopenharmony_ci        lcrh |= UART_LCR_H_FIFO_EN;
1671bd4fe43Sopenharmony_ci    }
1681bd4fe43Sopenharmony_ci    OSAL_WRITEB(lcrh, port->physBase + UART_LCR_H);
1691bd4fe43Sopenharmony_ci}
1701bd4fe43Sopenharmony_ci
1711bd4fe43Sopenharmony_cistatic int32_t Pl011ConfigIn(struct UartDriverData *udd)
1721bd4fe43Sopenharmony_ci{
1731bd4fe43Sopenharmony_ci    uint32_t cr;
1741bd4fe43Sopenharmony_ci    uint32_t lcrh;
1751bd4fe43Sopenharmony_ci    struct UartPl011Port *port = NULL;
1761bd4fe43Sopenharmony_ci
1771bd4fe43Sopenharmony_ci    port = (struct UartPl011Port *)udd->private;
1781bd4fe43Sopenharmony_ci    if (port == NULL) {
1791bd4fe43Sopenharmony_ci        HDF_LOGE("%s: port is NULL", __func__);
1801bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
1811bd4fe43Sopenharmony_ci    }
1821bd4fe43Sopenharmony_ci    /* get CR */
1831bd4fe43Sopenharmony_ci    cr = OSAL_READW(port->physBase + UART_CR);
1841bd4fe43Sopenharmony_ci    /* get LCR_H */
1851bd4fe43Sopenharmony_ci    lcrh = OSAL_READW(port->physBase + UART_LCR_H);
1861bd4fe43Sopenharmony_ci    /* uart disable */
1871bd4fe43Sopenharmony_ci    OSAL_WRITEW(0, port->physBase + UART_CR);
1881bd4fe43Sopenharmony_ci    /* config cts/rts */
1891bd4fe43Sopenharmony_ci    if (UART_ATTR_CTS_EN == udd->attr.cts) {
1901bd4fe43Sopenharmony_ci        cr |= UART_CR_CTS;
1911bd4fe43Sopenharmony_ci    } else {
1921bd4fe43Sopenharmony_ci        cr &= ~UART_CR_CTS;
1931bd4fe43Sopenharmony_ci    }
1941bd4fe43Sopenharmony_ci    if (UART_ATTR_RTS_EN == udd->attr.rts) {
1951bd4fe43Sopenharmony_ci        cr |= UART_CR_RTS;
1961bd4fe43Sopenharmony_ci    } else {
1971bd4fe43Sopenharmony_ci        cr &= ~UART_CR_RTS;
1981bd4fe43Sopenharmony_ci    }
1991bd4fe43Sopenharmony_ci    lcrh &= ~UART_LCR_H_FIFO_EN;
2001bd4fe43Sopenharmony_ci    OSAL_WRITEB(lcrh, port->physBase + UART_LCR_H);
2011bd4fe43Sopenharmony_ci
2021bd4fe43Sopenharmony_ci    cr &= ~UART_CR_EN;
2031bd4fe43Sopenharmony_ci    OSAL_WRITEW(cr, port->physBase + UART_CR);
2041bd4fe43Sopenharmony_ci
2051bd4fe43Sopenharmony_ci    /* set baud rate */
2061bd4fe43Sopenharmony_ci    Pl011ConfigBaudrate(udd, port);
2071bd4fe43Sopenharmony_ci
2081bd4fe43Sopenharmony_ci    /* config lcr_h */
2091bd4fe43Sopenharmony_ci    Pl011ConfigLCRH(udd, port, lcrh);
2101bd4fe43Sopenharmony_ci
2111bd4fe43Sopenharmony_ci    cr |= UART_CR_EN;
2121bd4fe43Sopenharmony_ci    /* resume CR */
2131bd4fe43Sopenharmony_ci    OSAL_WRITEW(cr, port->physBase + UART_CR);
2141bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
2151bd4fe43Sopenharmony_ci}
2161bd4fe43Sopenharmony_ci
2171bd4fe43Sopenharmony_cistatic int32_t Pl011StartUp(struct UartDriverData *udd)
2181bd4fe43Sopenharmony_ci{
2191bd4fe43Sopenharmony_ci    int32_t ret;
2201bd4fe43Sopenharmony_ci    uint32_t cr;
2211bd4fe43Sopenharmony_ci    struct UartPl011Port *port = NULL;
2221bd4fe43Sopenharmony_ci
2231bd4fe43Sopenharmony_ci    if (udd == NULL) {
2241bd4fe43Sopenharmony_ci        HDF_LOGE("%s: udd is null", __func__);
2251bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
2261bd4fe43Sopenharmony_ci    }
2271bd4fe43Sopenharmony_ci    port = (struct UartPl011Port *)udd->private;
2281bd4fe43Sopenharmony_ci    if (port == NULL) {
2291bd4fe43Sopenharmony_ci        HDF_LOGE("%s: port is null", __func__);
2301bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
2311bd4fe43Sopenharmony_ci    }
2321bd4fe43Sopenharmony_ci    /* enable the clock */
2331bd4fe43Sopenharmony_ci    LOS_TaskLock();
2341bd4fe43Sopenharmony_ci    uart_clk_cfg(udd->num, true);
2351bd4fe43Sopenharmony_ci    LOS_TaskUnlock();
2361bd4fe43Sopenharmony_ci    /* uart disable */
2371bd4fe43Sopenharmony_ci    OSAL_WRITEW(0, port->physBase + UART_CR);
2381bd4fe43Sopenharmony_ci    OSAL_WRITEW(0xFF, port->physBase + UART_RSR);
2391bd4fe43Sopenharmony_ci    /* clear all interrupt,set mask */
2401bd4fe43Sopenharmony_ci    OSAL_WRITEW(0xFFFF, port->physBase + UART_CLR);
2411bd4fe43Sopenharmony_ci    /* mask all interrupt */
2421bd4fe43Sopenharmony_ci    OSAL_WRITEW(0x0, port->physBase + UART_IMSC);
2431bd4fe43Sopenharmony_ci    /* interrupt trigger line RX: 4/8, TX 7/8 */
2441bd4fe43Sopenharmony_ci    OSAL_WRITEW(UART_IFLS_RX4_8 | UART_IFLS_TX7_8, port->physBase + UART_IFLS);
2451bd4fe43Sopenharmony_ci    if (!(udd->flags & UART_FLG_DMA_RX)) {
2461bd4fe43Sopenharmony_ci        if (!(port->flags & PL011_FLG_IRQ_REQUESTED)) {
2471bd4fe43Sopenharmony_ci            ret = OsalRegisterIrq(port->irqNum, 0, Pl011Irq, "uart_pl011", udd);
2481bd4fe43Sopenharmony_ci            if (ret == 0) {
2491bd4fe43Sopenharmony_ci                port->flags |= PL011_FLG_IRQ_REQUESTED;
2501bd4fe43Sopenharmony_ci                /* enable rx and timeout interrupt */
2511bd4fe43Sopenharmony_ci                OSAL_WRITEW(UART_IMSC_RX | UART_IMSC_TIMEOUT, port->physBase + UART_IMSC);
2521bd4fe43Sopenharmony_ci            }
2531bd4fe43Sopenharmony_ci        }
2541bd4fe43Sopenharmony_ci    }
2551bd4fe43Sopenharmony_ci    cr = OSAL_READW(port->physBase + UART_CR);
2561bd4fe43Sopenharmony_ci    cr |= UART_CR_EN | UART_CR_RX_EN | UART_CR_TX_EN;
2571bd4fe43Sopenharmony_ci    OSAL_WRITEL(cr, port->physBase + UART_CR);
2581bd4fe43Sopenharmony_ci    ret = Pl011ConfigIn(udd);
2591bd4fe43Sopenharmony_ci    return ret;
2601bd4fe43Sopenharmony_ci}
2611bd4fe43Sopenharmony_ci
2621bd4fe43Sopenharmony_cistatic int32_t Pl011ShutDown(struct UartDriverData *udd)
2631bd4fe43Sopenharmony_ci{
2641bd4fe43Sopenharmony_ci    uint32_t reg_tmp;
2651bd4fe43Sopenharmony_ci    struct UartPl011Port *port = NULL;
2661bd4fe43Sopenharmony_ci
2671bd4fe43Sopenharmony_ci    if (udd == NULL) {
2681bd4fe43Sopenharmony_ci        HDF_LOGE("%s: udd is null", __func__);
2691bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
2701bd4fe43Sopenharmony_ci    }
2711bd4fe43Sopenharmony_ci    port = (struct UartPl011Port *)udd->private;
2721bd4fe43Sopenharmony_ci    if (port == NULL) {
2731bd4fe43Sopenharmony_ci        HDF_LOGE("%s: port is null", __func__);
2741bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
2751bd4fe43Sopenharmony_ci    }
2761bd4fe43Sopenharmony_ci    OSAL_WRITEW(0, port->physBase + UART_IMSC);
2771bd4fe43Sopenharmony_ci    OSAL_WRITEW(0xFFFF, port->physBase + UART_CLR);
2781bd4fe43Sopenharmony_ci    if (port->flags & PL011_FLG_IRQ_REQUESTED) {
2791bd4fe43Sopenharmony_ci        OsalUnregisterIrq(port->irqNum, udd);
2801bd4fe43Sopenharmony_ci        port->flags &= ~PL011_FLG_IRQ_REQUESTED;
2811bd4fe43Sopenharmony_ci    }
2821bd4fe43Sopenharmony_ci
2831bd4fe43Sopenharmony_ci    reg_tmp = OSAL_READW(port->physBase + UART_CR);
2841bd4fe43Sopenharmony_ci    reg_tmp &= ~UART_CR_TX_EN;
2851bd4fe43Sopenharmony_ci    reg_tmp &= ~UART_CR_RX_EN;
2861bd4fe43Sopenharmony_ci    reg_tmp &= ~UART_CR_EN;
2871bd4fe43Sopenharmony_ci    OSAL_WRITEW(reg_tmp, port->physBase + UART_CR);
2881bd4fe43Sopenharmony_ci
2891bd4fe43Sopenharmony_ci    /* disable break and fifo */
2901bd4fe43Sopenharmony_ci    reg_tmp = OSAL_READW(port->physBase + UART_LCR_H);
2911bd4fe43Sopenharmony_ci    reg_tmp &= ~(UART_LCR_H_BREAK);
2921bd4fe43Sopenharmony_ci    reg_tmp &= ~(UART_LCR_H_FIFO_EN);
2931bd4fe43Sopenharmony_ci    OSAL_WRITEW(reg_tmp, port->physBase + UART_LCR_H);
2941bd4fe43Sopenharmony_ci
2951bd4fe43Sopenharmony_ci    /* shut down the clock */
2961bd4fe43Sopenharmony_ci    LOS_TaskLock();
2971bd4fe43Sopenharmony_ci    uart_clk_cfg(udd->num, false);
2981bd4fe43Sopenharmony_ci    LOS_TaskUnlock();
2991bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
3001bd4fe43Sopenharmony_ci}
3011bd4fe43Sopenharmony_ci
3021bd4fe43Sopenharmony_cistatic int32_t Pl011StartTx(struct UartDriverData *udd, const char *buf, size_t count)
3031bd4fe43Sopenharmony_ci{
3041bd4fe43Sopenharmony_ci    struct UartPl011Port *port = NULL;
3051bd4fe43Sopenharmony_ci
3061bd4fe43Sopenharmony_ci    if (udd == NULL || buf == NULL || count == 0) {
3071bd4fe43Sopenharmony_ci        HDF_LOGE("%s: invalid parame", __func__);
3081bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
3091bd4fe43Sopenharmony_ci    }
3101bd4fe43Sopenharmony_ci    port = (struct UartPl011Port *)udd->private;
3111bd4fe43Sopenharmony_ci    if (port == NULL) {
3121bd4fe43Sopenharmony_ci        HDF_LOGE("%s: port is null", __func__);
3131bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
3141bd4fe43Sopenharmony_ci    }
3151bd4fe43Sopenharmony_ci    /* UART_WITH_LOCK: there is a spinlock in the function to write reg in order. */
3161bd4fe43Sopenharmony_ci    (void)UartPutsReg(port->physBase, buf, count, UART_WITH_LOCK);
3171bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
3181bd4fe43Sopenharmony_ci}
3191bd4fe43Sopenharmony_ci
3201bd4fe43Sopenharmony_cistatic int32_t Pl011Config(struct UartDriverData *udd)
3211bd4fe43Sopenharmony_ci{
3221bd4fe43Sopenharmony_ci    uint32_t fr;
3231bd4fe43Sopenharmony_ci    struct UartPl011Port *port = NULL;
3241bd4fe43Sopenharmony_ci
3251bd4fe43Sopenharmony_ci    if (udd == NULL) {
3261bd4fe43Sopenharmony_ci        HDF_LOGE("%s: udd is null", __func__);
3271bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
3281bd4fe43Sopenharmony_ci    }
3291bd4fe43Sopenharmony_ci    port = (struct UartPl011Port *)udd->private;
3301bd4fe43Sopenharmony_ci    if (port == NULL) {
3311bd4fe43Sopenharmony_ci        HDF_LOGE("%s: port is null", __func__);
3321bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
3331bd4fe43Sopenharmony_ci    }
3341bd4fe43Sopenharmony_ci    /* wait for send finish */
3351bd4fe43Sopenharmony_ci    do {
3361bd4fe43Sopenharmony_ci        fr = OSAL_READB(port->physBase + UART_FR);
3371bd4fe43Sopenharmony_ci        if (!(fr & UART_FR_BUSY)) {
3381bd4fe43Sopenharmony_ci            break;
3391bd4fe43Sopenharmony_ci        }
3401bd4fe43Sopenharmony_ci        OsalMSleep(UART_WAIT_MS);
3411bd4fe43Sopenharmony_ci    } while (1);
3421bd4fe43Sopenharmony_ci    return Pl011ConfigIn(udd);
3431bd4fe43Sopenharmony_ci}
3441bd4fe43Sopenharmony_ci
3451bd4fe43Sopenharmony_cistruct UartOps g_pl011Uops = {
3461bd4fe43Sopenharmony_ci    .StartUp        = Pl011StartUp,
3471bd4fe43Sopenharmony_ci    .ShutDown       = Pl011ShutDown,
3481bd4fe43Sopenharmony_ci    .StartTx        = Pl011StartTx,
3491bd4fe43Sopenharmony_ci    .Config         = Pl011Config,
3501bd4fe43Sopenharmony_ci    .DmaStartUp     = NULL,
3511bd4fe43Sopenharmony_ci    .DmaShutDown    = NULL,
3521bd4fe43Sopenharmony_ci};
3531bd4fe43Sopenharmony_ci
3541bd4fe43Sopenharmony_ciint32_t Pl011Read(struct UartDriverData *udd, char *buf, size_t count)
3551bd4fe43Sopenharmony_ci{
3561bd4fe43Sopenharmony_ci    uint32_t wp;
3571bd4fe43Sopenharmony_ci    uint32_t rp;
3581bd4fe43Sopenharmony_ci    uint32_t upperHalf;
3591bd4fe43Sopenharmony_ci    uint32_t lowerHalf = 0;
3601bd4fe43Sopenharmony_ci    unsigned long data;
3611bd4fe43Sopenharmony_ci
3621bd4fe43Sopenharmony_ci    if (udd == NULL || buf == NULL || count == 0 || udd->rxTransfer == NULL) {
3631bd4fe43Sopenharmony_ci        HDF_LOGE("%s: invalid parameter", __func__);
3641bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
3651bd4fe43Sopenharmony_ci    }
3661bd4fe43Sopenharmony_ci    wp = udd->rxTransfer->wp;
3671bd4fe43Sopenharmony_ci    rp = udd->rxTransfer->rp;
3681bd4fe43Sopenharmony_ci    data = (unsigned long)(udd->rxTransfer->data);
3691bd4fe43Sopenharmony_ci
3701bd4fe43Sopenharmony_ci    if (rp == wp) {
3711bd4fe43Sopenharmony_ci        return 0; // buffer empty
3721bd4fe43Sopenharmony_ci    }
3731bd4fe43Sopenharmony_ci
3741bd4fe43Sopenharmony_ci    if (rp < wp) { // rp behind
3751bd4fe43Sopenharmony_ci        upperHalf = (count > (wp - rp)) ? (wp - rp) : count;
3761bd4fe43Sopenharmony_ci        if (upperHalf > 0 && memcpy_s(buf, upperHalf, (void *)(data + rp), upperHalf) != EOK) {
3771bd4fe43Sopenharmony_ci            return HDF_ERR_IO;
3781bd4fe43Sopenharmony_ci        }
3791bd4fe43Sopenharmony_ci        rp += upperHalf;
3801bd4fe43Sopenharmony_ci    } else { // wp behind
3811bd4fe43Sopenharmony_ci        count = (count > (BUF_SIZE - rp + wp)) ? (BUF_SIZE - rp + wp) : count;
3821bd4fe43Sopenharmony_ci        upperHalf = (count > (BUF_SIZE - rp)) ? (BUF_SIZE - rp) : count;
3831bd4fe43Sopenharmony_ci        lowerHalf = (count > (BUF_SIZE - rp)) ? (count - (BUF_SIZE - rp)) : 0;
3841bd4fe43Sopenharmony_ci        if (upperHalf > 0 && memcpy_s(buf, upperHalf, (void *)(data + rp), upperHalf) != EOK) {
3851bd4fe43Sopenharmony_ci            return HDF_ERR_IO;
3861bd4fe43Sopenharmony_ci        }
3871bd4fe43Sopenharmony_ci        if (lowerHalf > 0 && memcpy_s(buf + upperHalf, lowerHalf, (void *)(data), lowerHalf) != EOK) {
3881bd4fe43Sopenharmony_ci            return HDF_ERR_IO;
3891bd4fe43Sopenharmony_ci        }
3901bd4fe43Sopenharmony_ci        rp += upperHalf;
3911bd4fe43Sopenharmony_ci        if (rp >= BUF_SIZE) {
3921bd4fe43Sopenharmony_ci            rp = lowerHalf;
3931bd4fe43Sopenharmony_ci        }
3941bd4fe43Sopenharmony_ci    }
3951bd4fe43Sopenharmony_ci    udd->rxTransfer->rp = rp;
3961bd4fe43Sopenharmony_ci    return (upperHalf + lowerHalf);
3971bd4fe43Sopenharmony_ci}
3981bd4fe43Sopenharmony_ci
3991bd4fe43Sopenharmony_cistatic int32_t Pl011Notify(struct wait_queue_head *wait)
4001bd4fe43Sopenharmony_ci{
4011bd4fe43Sopenharmony_ci    if (wait == NULL) {
4021bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
4031bd4fe43Sopenharmony_ci    }
4041bd4fe43Sopenharmony_ci    LOS_EventWrite(&wait->stEvent, 0x1);
4051bd4fe43Sopenharmony_ci    notify_poll(wait);
4061bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
4071bd4fe43Sopenharmony_ci}
4081bd4fe43Sopenharmony_ci
4091bd4fe43Sopenharmony_ciint32_t PL011UartRecvNotify(struct UartDriverData *udd, const char *buf, size_t count)
4101bd4fe43Sopenharmony_ci{
4111bd4fe43Sopenharmony_ci    uint32_t wp;
4121bd4fe43Sopenharmony_ci    uint32_t rp;
4131bd4fe43Sopenharmony_ci    uint32_t upperHalf;
4141bd4fe43Sopenharmony_ci    uint32_t lowerHalf = 0;
4151bd4fe43Sopenharmony_ci    unsigned long data;
4161bd4fe43Sopenharmony_ci
4171bd4fe43Sopenharmony_ci    if (udd == NULL || buf == NULL || count == 0 || udd->rxTransfer == NULL) {
4181bd4fe43Sopenharmony_ci        HDF_LOGE("%s: invalid parameter", __func__);
4191bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
4201bd4fe43Sopenharmony_ci    }
4211bd4fe43Sopenharmony_ci    wp = udd->rxTransfer->wp;
4221bd4fe43Sopenharmony_ci    rp = udd->rxTransfer->rp;
4231bd4fe43Sopenharmony_ci    data = (unsigned long)(udd->rxTransfer->data);
4241bd4fe43Sopenharmony_ci
4251bd4fe43Sopenharmony_ci    if (wp < rp) { // wp behind
4261bd4fe43Sopenharmony_ci        upperHalf = (count > (rp - wp - 1)) ? (rp - wp - 1) : count;
4271bd4fe43Sopenharmony_ci        if (upperHalf > 0 && memcpy_s((void *)(data + wp), upperHalf, buf, upperHalf) != EOK) {
4281bd4fe43Sopenharmony_ci            return HDF_ERR_IO;
4291bd4fe43Sopenharmony_ci        }
4301bd4fe43Sopenharmony_ci        wp += upperHalf;
4311bd4fe43Sopenharmony_ci    } else { // rp behind
4321bd4fe43Sopenharmony_ci        count = (count > ((BUF_SIZE - wp) + rp - 1)) ? (BUF_SIZE - wp) + rp - 1 : count;
4331bd4fe43Sopenharmony_ci        upperHalf = (count > (BUF_SIZE - wp)) ? (BUF_SIZE - wp) : count;
4341bd4fe43Sopenharmony_ci        lowerHalf = (count > (BUF_SIZE - wp)) ? (count - (BUF_SIZE - wp)) : 0;
4351bd4fe43Sopenharmony_ci        if (upperHalf > 0 && memcpy_s((void *)(data + wp), upperHalf, buf, upperHalf) != EOK) {
4361bd4fe43Sopenharmony_ci            return HDF_ERR_IO;
4371bd4fe43Sopenharmony_ci        }
4381bd4fe43Sopenharmony_ci        if (lowerHalf > 0 && memcpy_s((void *)(data), lowerHalf, buf + upperHalf, lowerHalf) != EOK) {
4391bd4fe43Sopenharmony_ci            return HDF_ERR_IO;
4401bd4fe43Sopenharmony_ci        }
4411bd4fe43Sopenharmony_ci        wp += upperHalf;
4421bd4fe43Sopenharmony_ci        if (wp >= BUF_SIZE) {
4431bd4fe43Sopenharmony_ci            wp = lowerHalf;
4441bd4fe43Sopenharmony_ci        }
4451bd4fe43Sopenharmony_ci    }
4461bd4fe43Sopenharmony_ci
4471bd4fe43Sopenharmony_ci    if (Pl011Notify(&udd->wait) != HDF_SUCCESS) {
4481bd4fe43Sopenharmony_ci        HDF_LOGE("%s: Pl011 notify err", __func__);
4491bd4fe43Sopenharmony_ci        return HDF_FAILURE;
4501bd4fe43Sopenharmony_ci    }
4511bd4fe43Sopenharmony_ci    udd->rxTransfer->wp = wp;
4521bd4fe43Sopenharmony_ci    return (upperHalf + lowerHalf);
4531bd4fe43Sopenharmony_ci}
4541bd4fe43Sopenharmony_ci
4551bd4fe43Sopenharmony_cibool PL011UartRxBufEmpty(struct UartDriverData *udd)
4561bd4fe43Sopenharmony_ci{
4571bd4fe43Sopenharmony_ci    struct UartTransfer *transfer = udd->rxTransfer;
4581bd4fe43Sopenharmony_ci    return (transfer->wp == transfer->rp);
4591bd4fe43Sopenharmony_ci}
4601bd4fe43Sopenharmony_ci
4611bd4fe43Sopenharmony_cistruct UartOps *Pl011GetOps(void)
4621bd4fe43Sopenharmony_ci{
4631bd4fe43Sopenharmony_ci    return &g_pl011Uops;
4641bd4fe43Sopenharmony_ci}
465