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