Patrick Georgi | ac95903 | 2020-05-05 22:49:26 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 2 | |
| 3 | #include <assert.h> |
| 4 | #include <boot/coreboot_tables.h> |
| 5 | #include <console/uart.h> |
| 6 | #include <soc/clock.h> |
| 7 | #include <soc/qcom_qup_se.h> |
Ravi Kumar Bokka | 34960d4 | 2021-07-27 21:02:54 +0530 | [diff] [blame] | 8 | #include <soc/qup_se_handlers_common.h> |
Rajesh Patil | c2800a5 | 2021-06-18 09:17:34 +0530 | [diff] [blame] | 9 | #include <soc/qupv3_config_common.h> |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 10 | #include <types.h> |
| 11 | |
| 12 | /* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */ |
| 13 | |
| 14 | #define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK 0x1 |
| 15 | #define GENI_STATUS_S_GENI_CMD_ACTIVE_MASK 0x1000 |
| 16 | |
| 17 | #define UART_TX_WATERMARK_MARGIN 4 /* Represented in words */ |
| 18 | #define UART_RX_WATERMARK_MARGIN 8 /* Represented in words */ |
| 19 | #define UART_RX_RFR_WATERMARK_MARGIN 4 /* Represented in words */ |
| 20 | #define UART_TX_BITS_PER_WORD 8 |
| 21 | #define UART_RX_BITS_PER_WORD 8 |
| 22 | #define START_UART_TX 0x8000000 |
| 23 | #define START_UART_RX 0x8000000 |
| 24 | |
| 25 | /* UART FIFO Packing Configuration. */ |
| 26 | /* Start_idx:0, direction:0, len:7, stop:0 */ |
| 27 | #define UART_TX_PACK_VECTOR0 0x0E |
| 28 | /* Start_idx:8, direction:0, len:7, stop:0 */ |
| 29 | #define UART_TX_PACK_VECTOR1 0x10E |
| 30 | /* Start_idx:16, direction:0, len:7, stop:0 */ |
| 31 | #define UART_TX_PACK_VECTOR2 0x20E |
| 32 | /* Start_idx:24, direction:0, len:7, stop:1 */ |
| 33 | #define UART_TX_PACK_VECTOR3 0x30F |
| 34 | /* Start_idx:0, direction:0, len:7, stop:1 */ |
| 35 | #define UART_RX_PACK_VECTOR0 0xF |
| 36 | #define UART_RX_PACK_VECTOR2 0x00 |
| 37 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 38 | void uart_tx_flush(unsigned int idx) |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 39 | { |
| 40 | struct qup_regs *regs = qup[idx].regs; |
| 41 | |
| 42 | while (read32(®s->geni_status) & |
| 43 | GENI_STATUS_M_GENI_CMD_ACTIVE_MASK) |
| 44 | ; |
| 45 | } |
| 46 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 47 | void uart_init(unsigned int idx) |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 48 | { |
| 49 | struct qup_regs *regs = qup[idx].regs; |
| 50 | unsigned int reg_value; |
| 51 | unsigned int div, baud_rate, uart_freq; |
| 52 | |
| 53 | /* |
| 54 | * If the RX (secondary) sequencer is already active, it means the core |
| 55 | * has been already initialized in the previous stage. Skip |
| 56 | * configuration |
| 57 | */ |
| 58 | if (read32(®s->geni_status) & GENI_STATUS_S_GENI_CMD_ACTIVE_MASK) |
| 59 | return; |
| 60 | |
| 61 | qupv3_se_fw_load_and_init(idx, SE_PROTOCOL_UART, FIFO); |
| 62 | clock_enable_qup(idx); |
| 63 | |
| 64 | reg_value = read32(®s->geni_fw_revision_ro); |
| 65 | reg_value &= GENI_FW_REVISION_RO_PROTOCOL_MASK; |
| 66 | reg_value >>= GENI_FW_REVISION_RO_PROTOCOL_SHIFT; |
| 67 | |
| 68 | assert(reg_value == SE_PROTOCOL_UART); |
| 69 | |
| 70 | baud_rate = get_uart_baudrate(); |
| 71 | |
Rajesh Patil | c2800a5 | 2021-06-18 09:17:34 +0530 | [diff] [blame] | 72 | /*requires 16 clock pulses to sample 1 bit of data */ |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 73 | uart_freq = baud_rate * 16; |
| 74 | |
Roja Rani Yarubandi | dcf80ab0 | 2020-05-07 16:28:29 +0530 | [diff] [blame] | 75 | div = DIV_ROUND_CLOSEST(SRC_XO_HZ, uart_freq); |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 76 | write32(®s->geni_ser_m_clk_cfg, (div << 4) | 1); |
| 77 | write32(®s->geni_ser_s_clk_cfg, (div << 4) | 1); |
| 78 | |
| 79 | /* GPIO Configuration */ |
| 80 | gpio_configure(qup[idx].pin[2], qup[idx].func[2], GPIO_PULL_UP, |
| 81 | GPIO_2MA, GPIO_OUTPUT); |
| 82 | gpio_configure(qup[idx].pin[3], qup[idx].func[3], GPIO_PULL_UP, |
| 83 | GPIO_2MA, GPIO_INPUT); |
| 84 | |
| 85 | write32(®s->geni_tx_watermark_reg, UART_TX_WATERMARK_MARGIN); |
| 86 | write32(®s->geni_rx_watermark_reg, FIFO_DEPTH |
| 87 | - UART_RX_WATERMARK_MARGIN); |
| 88 | write32(®s->geni_rx_rfr_watermark_reg, |
| 89 | FIFO_DEPTH - UART_RX_RFR_WATERMARK_MARGIN); |
| 90 | |
| 91 | write32(®s->uart_tx_word_len, UART_TX_BITS_PER_WORD); |
| 92 | write32(®s->uart_rx_word_len, UART_RX_BITS_PER_WORD); |
| 93 | |
| 94 | /* Disable TX parity calculation */ |
| 95 | write32(®s->uart_tx_parity_cfg, 0x0); |
| 96 | /* Ignore CTS line status for TX communication */ |
| 97 | write32(®s->uart_tx_trans_cfg_reg, 0x2); |
| 98 | /* Disable RX parity calculation */ |
| 99 | write32(®s->uart_rx_parity_cfg, 0x0); |
| 100 | /* Disable parity, framing and break check on received word */ |
| 101 | write32(®s->uart_rx_trans_cfg, 0x0); |
| 102 | /* Set UART TX stop bit len to one UART bit length */ |
| 103 | write32(®s->uart_tx_stop_bit_len, 0x0); |
| 104 | write32(®s->uart_rx_stale_cnt, 0x16 * 10); |
| 105 | |
| 106 | write32(®s->geni_tx_packing_cfg0, UART_TX_PACK_VECTOR0 | |
| 107 | (UART_TX_PACK_VECTOR1 << 10)); |
| 108 | write32(®s->geni_tx_packing_cfg1, UART_TX_PACK_VECTOR2 | |
| 109 | (UART_TX_PACK_VECTOR3 << 10)); |
| 110 | write32(®s->geni_rx_packing_cfg0, UART_RX_PACK_VECTOR0); |
| 111 | write32(®s->geni_rx_packing_cfg1, UART_RX_PACK_VECTOR2); |
| 112 | |
| 113 | /* Start RX */ |
| 114 | write32(®s->geni_s_cmd0, START_UART_RX); |
| 115 | } |
| 116 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 117 | unsigned char uart_rx_byte(unsigned int idx) |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 118 | { |
| 119 | struct qup_regs *regs = qup[idx].regs; |
| 120 | |
| 121 | if (read32(®s->geni_rx_fifo_status) & RX_FIFO_WC_MSK) |
| 122 | return read32(®s->geni_rx_fifon) & 0xFF; |
| 123 | return 0; |
| 124 | } |
| 125 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 126 | void uart_tx_byte(unsigned int idx, unsigned char data) |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 127 | { |
| 128 | struct qup_regs *regs = qup[idx].regs; |
| 129 | |
| 130 | uart_tx_flush(idx); |
| 131 | |
| 132 | write32(®s->uart_tx_trans_len, 1); |
| 133 | /* Start TX */ |
| 134 | write32(®s->geni_m_cmd0, START_UART_TX); |
| 135 | write32(®s->geni_tx_fifon, data); |
| 136 | } |
| 137 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 138 | uintptr_t uart_platform_base(unsigned int idx) |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 139 | { |
| 140 | return (uintptr_t)qup[idx].regs; |
| 141 | } |
| 142 | |
Arthur Heymans | 9948c52 | 2022-10-24 14:37:40 +0200 | [diff] [blame] | 143 | enum cb_err fill_lb_serial(struct lb_serial *serial) |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 144 | { |
Arthur Heymans | 9948c52 | 2022-10-24 14:37:40 +0200 | [diff] [blame] | 145 | serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED; |
| 146 | serial->baseaddr = (uint32_t)uart_platform_base(CONFIG_UART_FOR_CONSOLE); |
| 147 | serial->baud = get_uart_baudrate(); |
| 148 | serial->regwidth = 4; |
| 149 | serial->input_hertz = SRC_XO_HZ; |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 150 | |
Arthur Heymans | 9948c52 | 2022-10-24 14:37:40 +0200 | [diff] [blame] | 151 | return CB_SUCCESS; |
T Michael Turney | 7ae833b | 2019-10-10 15:29:16 -0700 | [diff] [blame] | 152 | } |