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