diff options
author | Prudhvi Yarlagadda <pyarlaga@codeaurora.org> | 2019-03-22 15:26:02 +0530 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-06-04 14:15:26 +0000 |
commit | 37e957f3349c461371e15cd3d6f754514506ce47 (patch) | |
tree | 341279b6c1b96ee47b47ec76f055807207d4e101 /src/soc/qualcomm/qcs405/uart.c | |
parent | 1b05479a7fc1605e1d9735575300bd09b55e6a5d (diff) | |
download | coreboot-37e957f3349c461371e15cd3d6f754514506ce47.tar.xz |
qcs405: Add UART support
Add support for UART driver in coreboot.
TEST=build & run
Change-Id: Id9626c68eadead8b8ec5ffbc08cab7b0ec36478f
Signed-off-by: Prudhvi Yarlagadda<pyarlaga@codeaurora.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Nitheesh Sekar <nsekar@codeaurora.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/29964
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/qualcomm/qcs405/uart.c')
-rw-r--r-- | src/soc/qualcomm/qcs405/uart.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/src/soc/qualcomm/qcs405/uart.c b/src/soc/qualcomm/qcs405/uart.c new file mode 100644 index 0000000000..4a4331220a --- /dev/null +++ b/src/soc/qualcomm/qcs405/uart.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Source : APQ8064 LK boot + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <device/mmio.h> +#include <boot/coreboot_tables.h> +#include <console/console.h> +#include <console/uart.h> +#include <delay.h> +#include <gpio.h> +#include <soc/clock.h> +#include <soc/blsp.h> +#include <soc/uart.h> +#include <soc/cdp.h> +#include <stdint.h> +#include <stdlib.h> +#include <soc/iomap.h> + +#define FIFO_DATA_SIZE 4 + +typedef struct { + void *uart_dm_base; + unsigned int blsp_uart; + gpio_func_data_t dbg_uart_gpio[NO_OF_DBG_UART_GPIOS]; +} uart_params_t; + +void ipq_configure_gpio(const gpio_func_data_t *gpio, unsigned int count) +{ + int i; + + for (i = 0; i < count; i++) { + gpio_configure(gpio->gpio, gpio->func, + gpio->pull, gpio->drvstr, gpio->enable); + gpio++; + } +} + +static const uart_params_t uart_board_param = { + .uart_dm_base = UART2_DM_BASE, + .blsp_uart = BLSP1_UART2, + .dbg_uart_gpio = { + { + .gpio = GPIO(17), + .func = 1, + .dir = GPIO_OUTPUT, + .pull = GPIO_PULL_UP, + .enable = GPIO_OUTPUT + }, + { + .gpio = GPIO(18), + .func = 1, + .dir = GPIO_INPUT, + .pull = GPIO_NO_PULL, + .enable = GPIO_INPUT + }, + }, +}; + +/** + * @brief msm_boot_uart_dm_init_rx_transfer - Init Rx transfer + * @param uart_dm_base: UART controller base address + */ +static unsigned int msm_boot_uart_dm_init_rx_transfer(void *uart_dm_base) +{ + /* Reset receiver */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CMD_RESET_RX); + + /* Enable receiver */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CR_RX_ENABLE); + write32(MSM_BOOT_UART_DM_DMRX(uart_dm_base), + MSM_BOOT_UART_DM_DMRX_DEF_VALUE); + + /* Clear stale event */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CMD_RES_STALE_INT); + + /* Enable stale event */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_GCMD_ENA_STALE_EVT); + + return MSM_BOOT_UART_DM_E_SUCCESS; +} + +#if CONFIG(DRIVERS_UART) +static unsigned int msm_boot_uart_dm_init(void *uart_dm_base); + +/* Received data is valid or not */ +static int valid_data = 0; + +/* Received data */ +static unsigned int word = 0; + + +void uart_tx_byte(int idx, unsigned char data) +{ + int num_of_chars = 1; + void *base = uart_board_param.uart_dm_base; + + /* Wait until transmit FIFO is empty. */ + while (!(read32(MSM_BOOT_UART_DM_SR(base)) & + MSM_BOOT_UART_DM_SR_TXEMT)) + udelay(1); + /* + * TX FIFO is ready to accept new character(s). First write number of + * characters to be transmitted. + */ + write32(MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base), num_of_chars); + + /* And now write the character(s) */ + write32(MSM_BOOT_UART_DM_TF(base, 0), data); +} +#endif /* CONFIG_SERIAL_UART */ + +/** + * @brief msm_boot_uart_dm_reset - resets UART controller + * @param base: UART controller base address + */ +static unsigned int msm_boot_uart_dm_reset(void *base) +{ + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RESET_RX); + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RESET_TX); + write32(MSM_BOOT_UART_DM_CR(base), + MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT); + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RES_TX_ERR); + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RES_STALE_INT); + + return MSM_BOOT_UART_DM_E_SUCCESS; +} + +/** + * @brief msm_boot_uart_dm_init - initilaizes UART controller + * @param uart_dm_base: UART controller base address + */ +unsigned int msm_boot_uart_dm_init(void *uart_dm_base) +{ + /* Configure UART mode registers MR1 and MR2 */ + /* Hardware flow control isn't supported */ + write32(MSM_BOOT_UART_DM_MR1(uart_dm_base), 0x0); + + /* 8-N-1 configuration: 8 data bits - No parity - 1 stop bit */ + write32(MSM_BOOT_UART_DM_MR2(uart_dm_base), + MSM_BOOT_UART_DM_8_N_1_MODE); + + /* Configure Interrupt Mask register IMR */ + write32(MSM_BOOT_UART_DM_IMR(uart_dm_base), + MSM_BOOT_UART_DM_IMR_ENABLED); + + /* + * Configure Tx and Rx watermarks configuration registers + * TX watermark value is set to 0 - interrupt is generated when + * FIFO level is less than or equal to 0 + */ + write32(MSM_BOOT_UART_DM_TFWR(uart_dm_base), + MSM_BOOT_UART_DM_TFW_VALUE); + + /* RX watermark value */ + write32(MSM_BOOT_UART_DM_RFWR(uart_dm_base), + MSM_BOOT_UART_DM_RFW_VALUE); + + /* Configure Interrupt Programming Register */ + /* Set initial Stale timeout value */ + write32(MSM_BOOT_UART_DM_IPR(uart_dm_base), + MSM_BOOT_UART_DM_STALE_TIMEOUT_LSB); + + /* Configure IRDA if required */ + /* Disabling IRDA mode */ + write32(MSM_BOOT_UART_DM_IRDA(uart_dm_base), 0x0); + + /* Configure hunt character value in HCR register */ + /* Keep it in reset state */ + write32(MSM_BOOT_UART_DM_HCR(uart_dm_base), 0x0); + + /* + * Configure Rx FIFO base address + * Both TX/RX shares same SRAM and default is half-n-half. + * Sticking with default value now. + * As such RAM size is (2^RAM_ADDR_WIDTH, 32-bit entries). + * We have found RAM_ADDR_WIDTH = 0x7f + */ + + /* Issue soft reset command */ + msm_boot_uart_dm_reset(uart_dm_base); + + /* Enable/Disable Rx/Tx DM interfaces */ + /* Data Mover not currently utilized. */ + write32(MSM_BOOT_UART_DM_DMEN(uart_dm_base), 0x0); + + /* Enable transmitter */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CR_TX_ENABLE); + + /* Initialize Receive Path */ + msm_boot_uart_dm_init_rx_transfer(uart_dm_base); + + return 0; +} + +/** + * @brief qcs405_uart_init - initializes UART + * + * Initializes clocks, GPIO and UART controller. + */ +void uart_init(int idx) +{ + /* Note int idx isn't used in this driver. */ + void *dm_base; + + dm_base = uart_board_param.uart_dm_base; + + if (read32(MSM_BOOT_UART_DM_CSR(dm_base)) == 0xFF) + return; /* UART must have been already initialized. */ + + clock_configure_uart(1843200); + clock_enable_uart(); + + ipq_configure_gpio(uart_board_param.dbg_uart_gpio, + NO_OF_DBG_UART_GPIOS); + + write32(MSM_BOOT_UART_DM_CSR(dm_base), 0xFF); + + /* Initialize UART_DM */ + msm_boot_uart_dm_init(dm_base); +} + +/* for the benefit of non-console uart init */ +void qcs405_uart_init(void) +{ + uart_init(0); +} + +/** + * @brief uart_tx_flush - transmits a string of data + * @param idx: string to transmit + */ +void uart_tx_flush(int idx) +{ + void *base = uart_board_param.uart_dm_base; + + while (!(read32(MSM_BOOT_UART_DM_SR(base)) & + MSM_BOOT_UART_DM_SR_TXEMT)) + ; +} + +#if CONFIG(DRIVERS_UART) +/** + * qcs405_serial_getc - reads a character + * + * Returns the character read from serial port. + */ +uint8_t uart_rx_byte(int idx) +{ + uint8_t byte; + + byte = (uint8_t)(word & 0xff); + word = word >> 8; + valid_data--; + + return byte; +} +#endif + +#ifndef __PRE_RAM__ +void uart_fill_lb(void *data) +{ + struct lb_serial serial; + + serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED; + serial.baseaddr = (uint64_t)UART2_DM_BASE; + serial.baud = get_uart_baudrate(); + serial.regwidth = 1; + + lb_add_serial(&serial, data); + lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data); +} +#endif |