1*cdd2fe13SRouven Czerwinski // SPDX-License-Identifier: BSD-2-Clause
2*cdd2fe13SRouven Czerwinski /*
3*cdd2fe13SRouven Czerwinski * Qualcomm GENI serial engine UART driver
4*cdd2fe13SRouven Czerwinski *
5*cdd2fe13SRouven Czerwinski * Copyright (c) 2025, Linaro Limited
6*cdd2fe13SRouven Czerwinski * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
7*cdd2fe13SRouven Czerwinski */
8*cdd2fe13SRouven Czerwinski
9*cdd2fe13SRouven Czerwinski #include <drivers/qcom_geni_uart.h>
10*cdd2fe13SRouven Czerwinski #include <io.h>
11*cdd2fe13SRouven Czerwinski
12*cdd2fe13SRouven Czerwinski #define GENI_STATUS_REG 0x40
13*cdd2fe13SRouven Czerwinski #define GENI_STATUS_REG_CMD_ACTIVE BIT(0)
14*cdd2fe13SRouven Czerwinski #define GENI_TX_FIFO_REG 0x700
15*cdd2fe13SRouven Czerwinski #define GENI_TX_TRANS_LEN_REG 0x270
16*cdd2fe13SRouven Czerwinski #define GENI_M_CMD0_REG 0x600
17*cdd2fe13SRouven Czerwinski
18*cdd2fe13SRouven Czerwinski #define GENI_M_CMD_TX 0x8000000
19*cdd2fe13SRouven Czerwinski #define GENI_TIMEOUT_US 1000000
20*cdd2fe13SRouven Czerwinski
qcom_geni_uart_putc(struct serial_chip * chip,int ch)21*cdd2fe13SRouven Czerwinski static void qcom_geni_uart_putc(struct serial_chip *chip, int ch)
22*cdd2fe13SRouven Czerwinski {
23*cdd2fe13SRouven Czerwinski struct qcom_geni_uart_data *pd =
24*cdd2fe13SRouven Czerwinski container_of(chip, struct qcom_geni_uart_data, chip);
25*cdd2fe13SRouven Czerwinski vaddr_t base = io_pa_or_va(&pd->base, GENI_UART_REG_SIZE);
26*cdd2fe13SRouven Czerwinski uint64_t timer = timeout_init_us(GENI_TIMEOUT_US);
27*cdd2fe13SRouven Czerwinski
28*cdd2fe13SRouven Czerwinski while (io_read32(base + GENI_STATUS_REG) & GENI_STATUS_REG_CMD_ACTIVE)
29*cdd2fe13SRouven Czerwinski if (timeout_elapsed(timer))
30*cdd2fe13SRouven Czerwinski return;
31*cdd2fe13SRouven Czerwinski
32*cdd2fe13SRouven Czerwinski io_write32(base + GENI_TX_TRANS_LEN_REG, 1);
33*cdd2fe13SRouven Czerwinski io_write32(base + GENI_M_CMD0_REG, GENI_M_CMD_TX);
34*cdd2fe13SRouven Czerwinski io_write32(base + GENI_TX_FIFO_REG, ch);
35*cdd2fe13SRouven Czerwinski }
36*cdd2fe13SRouven Czerwinski
37*cdd2fe13SRouven Czerwinski static const struct serial_ops qcom_geni_uart_ops = {
38*cdd2fe13SRouven Czerwinski .putc = qcom_geni_uart_putc,
39*cdd2fe13SRouven Czerwinski };
40*cdd2fe13SRouven Czerwinski DECLARE_KEEP_PAGER(qcom_geni_uart_ops);
41*cdd2fe13SRouven Czerwinski
qcom_geni_uart_init(struct qcom_geni_uart_data * pd,paddr_t base)42*cdd2fe13SRouven Czerwinski void qcom_geni_uart_init(struct qcom_geni_uart_data *pd, paddr_t base)
43*cdd2fe13SRouven Czerwinski {
44*cdd2fe13SRouven Czerwinski pd->base.pa = base;
45*cdd2fe13SRouven Czerwinski pd->chip.ops = &qcom_geni_uart_ops;
46*cdd2fe13SRouven Czerwinski
47*cdd2fe13SRouven Czerwinski /*
48*cdd2fe13SRouven Czerwinski * Do nothing, debug uart is shared with normal world, everything
49*cdd2fe13SRouven Czerwinski * for debug uart initialization is done in the bootloader.
50*cdd2fe13SRouven Czerwinski */
51*cdd2fe13SRouven Czerwinski }
52