diff options
author | T Michael Turney <mturney@codeaurora.org> | 2019-10-10 15:29:16 -0700 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2020-04-21 21:53:45 +0000 |
commit | 7ae833bdaa3778d476f5d8a0a123c3492ceecef8 (patch) | |
tree | 72ffddf404e7c34cc87b8b7affb4640784fad937 | |
parent | cea0d9c0ffc06359b01310c0dd728b4527c0013d (diff) |
sc7180: Add UART support
This implements the UART driver in SoC
Developer/Reviewer, be aware of this patch from Napali:
https://review.coreboot.org/c/coreboot/+/25373/78
Change-Id: I6494daa108197c030577ac86dab71f9ca6c21bdb
Signed-off-by: Roja Rani Yarubandi <rojay@codeaurora.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/35500
Reviewed-by: Julius Werner <jwerner@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r-- | src/soc/qualcomm/sc7180/Kconfig | 6 | ||||
-rw-r--r-- | src/soc/qualcomm/sc7180/Makefile.inc | 10 | ||||
-rw-r--r-- | src/soc/qualcomm/sc7180/qupv3_uart.c | 166 |
3 files changed, 179 insertions, 3 deletions
diff --git a/src/soc/qualcomm/sc7180/Kconfig b/src/soc/qualcomm/sc7180/Kconfig index 4093c93213..faf036e62b 100644 --- a/src/soc/qualcomm/sc7180/Kconfig +++ b/src/soc/qualcomm/sc7180/Kconfig @@ -31,4 +31,10 @@ config BOOT_DEVICE_SPI_FLASH_BUS int default 16 +config UART_FOR_CONSOLE + int + default 8 + help + Select the QUP instance to be used for UART console output. + endif diff --git a/src/soc/qualcomm/sc7180/Makefile.inc b/src/soc/qualcomm/sc7180/Makefile.inc index 554efd8801..e49521b4bb 100644 --- a/src/soc/qualcomm/sc7180/Makefile.inc +++ b/src/soc/qualcomm/sc7180/Makefile.inc @@ -17,9 +17,11 @@ bootblock-y += qcom_qup_se.c verstage-y += timer.c verstage-y += spi.c verstage-y += gpio.c -verstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c verstage-y += clock.c verstage-$(CONFIG_SC7180_QSPI) += qspi.c +verstage-y += qcom_qup_se.c +verstage-y += qupv3_config.c +verstage-$(CONFIG_DRIVERS_UART) += qupv3_uart.c ################################################################################ romstage-y += cbmem.c @@ -31,22 +33,24 @@ romstage-y += mmu.c romstage-y += usb.c romstage-y += spi.c romstage-y += gpio.c -romstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c romstage-y += clock.c romstage-$(CONFIG_SC7180_QSPI) += qspi.c +romstage-y += qcom_qup_se.c +romstage-y += qupv3_config.c +romstage-$(CONFIG_DRIVERS_UART) += qupv3_uart.c ################################################################################ ramstage-y += soc.c ramstage-y += timer.c ramstage-y += spi.c ramstage-y += gpio.c -ramstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c ramstage-y += clock.c ramstage-$(CONFIG_SC7180_QSPI) += qspi.c ramstage-y += aop_load_reset.c ramstage-y += usb.c ramstage-y += qupv3_config.c ramstage-y += qcom_qup_se.c +ramstage-$(CONFIG_DRIVERS_UART) += qupv3_uart.c ################################################################################ diff --git a/src/soc/qualcomm/sc7180/qupv3_uart.c b/src/soc/qualcomm/sc7180/qupv3_uart.c new file mode 100644 index 0000000000..aba35281c2 --- /dev/null +++ b/src/soc/qualcomm/sc7180/qupv3_uart.c @@ -0,0 +1,166 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <assert.h> +#include <boot/coreboot_tables.h> +#include <console/uart.h> +#include <soc/clock.h> +#include <soc/qcom_qup_se.h> +#include <soc/qupv3_config.h> +#include <types.h> + +/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */ + +#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK 0x1 +#define GENI_STATUS_S_GENI_CMD_ACTIVE_MASK 0x1000 + +#define UART_TX_WATERMARK_MARGIN 4 /* Represented in words */ +#define UART_RX_WATERMARK_MARGIN 8 /* Represented in words */ +#define UART_RX_RFR_WATERMARK_MARGIN 4 /* Represented in words */ +#define UART_TX_BITS_PER_WORD 8 +#define UART_RX_BITS_PER_WORD 8 +#define START_UART_TX 0x8000000 +#define START_UART_RX 0x8000000 + +/* UART FIFO Packing Configuration. */ +/* Start_idx:0, direction:0, len:7, stop:0 */ +#define UART_TX_PACK_VECTOR0 0x0E +/* Start_idx:8, direction:0, len:7, stop:0 */ +#define UART_TX_PACK_VECTOR1 0x10E +/* Start_idx:16, direction:0, len:7, stop:0 */ +#define UART_TX_PACK_VECTOR2 0x20E +/* Start_idx:24, direction:0, len:7, stop:1 */ +#define UART_TX_PACK_VECTOR3 0x30F +/* Start_idx:0, direction:0, len:7, stop:1 */ +#define UART_RX_PACK_VECTOR0 0xF +#define UART_RX_PACK_VECTOR2 0x00 + +void uart_tx_flush(int idx) +{ + struct qup_regs *regs = qup[idx].regs; + + while (read32(®s->geni_status) & + GENI_STATUS_M_GENI_CMD_ACTIVE_MASK) + ; +} + +void uart_init(int idx) +{ + struct qup_regs *regs = qup[idx].regs; + unsigned int reg_value; + unsigned int div, baud_rate, uart_freq; + + /* + * If the RX (secondary) sequencer is already active, it means the core + * has been already initialized in the previous stage. Skip + * configuration + */ + if (read32(®s->geni_status) & GENI_STATUS_S_GENI_CMD_ACTIVE_MASK) + return; + + qupv3_se_fw_load_and_init(idx, SE_PROTOCOL_UART, FIFO); + clock_enable_qup(idx); + + reg_value = read32(®s->geni_fw_revision_ro); + reg_value &= GENI_FW_REVISION_RO_PROTOCOL_MASK; + reg_value >>= GENI_FW_REVISION_RO_PROTOCOL_SHIFT; + + assert(reg_value == SE_PROTOCOL_UART); + + baud_rate = get_uart_baudrate(); + + /* sc7180 requires 16 clock pulses to sample 1 bit of data */ + uart_freq = baud_rate * 16; + + div = DIV_ROUND_CLOSEST(QUPV3_UART_SRC_HZ, uart_freq); + write32(®s->geni_ser_m_clk_cfg, (div << 4) | 1); + write32(®s->geni_ser_s_clk_cfg, (div << 4) | 1); + + /* GPIO Configuration */ + gpio_configure(qup[idx].pin[2], qup[idx].func[2], GPIO_PULL_UP, + GPIO_2MA, GPIO_OUTPUT); + gpio_configure(qup[idx].pin[3], qup[idx].func[3], GPIO_PULL_UP, + GPIO_2MA, GPIO_INPUT); + + write32(®s->geni_tx_watermark_reg, UART_TX_WATERMARK_MARGIN); + write32(®s->geni_rx_watermark_reg, FIFO_DEPTH + - UART_RX_WATERMARK_MARGIN); + write32(®s->geni_rx_rfr_watermark_reg, + FIFO_DEPTH - UART_RX_RFR_WATERMARK_MARGIN); + + write32(®s->uart_tx_word_len, UART_TX_BITS_PER_WORD); + write32(®s->uart_rx_word_len, UART_RX_BITS_PER_WORD); + + /* Disable TX parity calculation */ + write32(®s->uart_tx_parity_cfg, 0x0); + /* Ignore CTS line status for TX communication */ + write32(®s->uart_tx_trans_cfg_reg, 0x2); + /* Disable RX parity calculation */ + write32(®s->uart_rx_parity_cfg, 0x0); + /* Disable parity, framing and break check on received word */ + write32(®s->uart_rx_trans_cfg, 0x0); + /* Set UART TX stop bit len to one UART bit length */ + write32(®s->uart_tx_stop_bit_len, 0x0); + write32(®s->uart_rx_stale_cnt, 0x16 * 10); + + write32(®s->geni_tx_packing_cfg0, UART_TX_PACK_VECTOR0 | + (UART_TX_PACK_VECTOR1 << 10)); + write32(®s->geni_tx_packing_cfg1, UART_TX_PACK_VECTOR2 | + (UART_TX_PACK_VECTOR3 << 10)); + write32(®s->geni_rx_packing_cfg0, UART_RX_PACK_VECTOR0); + write32(®s->geni_rx_packing_cfg1, UART_RX_PACK_VECTOR2); + + /* Start RX */ + write32(®s->geni_s_cmd0, START_UART_RX); +} + +unsigned char uart_rx_byte(int idx) +{ + struct qup_regs *regs = qup[idx].regs; + + if (read32(®s->geni_rx_fifo_status) & RX_FIFO_WC_MSK) + return read32(®s->geni_rx_fifon) & 0xFF; + return 0; +} + +void uart_tx_byte(int idx, unsigned char data) +{ + struct qup_regs *regs = qup[idx].regs; + + uart_tx_flush(idx); + + write32(®s->uart_tx_trans_len, 1); + /* Start TX */ + write32(®s->geni_m_cmd0, START_UART_TX); + write32(®s->geni_tx_fifon, data); +} + +uintptr_t uart_platform_base(int idx) +{ + return (uintptr_t)qup[idx].regs; +} + +void uart_fill_lb(void *data) +{ + struct lb_serial serial = {0}; + + serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED; + serial.baseaddr = (uint32_t)uart_platform_base(CONFIG_UART_FOR_CONSOLE); + serial.baud = get_uart_baudrate(); + serial.regwidth = 4; + serial.input_hertz = QUPV3_UART_SRC_HZ; + + lb_add_serial(&serial, data); +} |