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>
This commit is contained in:
parent
cea0d9c0ff
commit
7ae833bdaa
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
################################################################################
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue