Home | History | Annotate | Download | only in serial
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Qualcomm UART driver
      4  *
      5  * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski (at) gmail.com>
      6  *
      7  * UART will work in Data Mover mode.
      8  * Based on Linux driver.
      9  */
     10 
     11 #include <common.h>
     12 #include <clk.h>
     13 #include <dm.h>
     14 #include <errno.h>
     15 #include <serial.h>
     16 #include <watchdog.h>
     17 #include <asm/io.h>
     18 #include <linux/compiler.h>
     19 #include <dm/pinctrl.h>
     20 
     21 /* Serial registers - this driver works in uartdm mode*/
     22 
     23 #define UARTDM_DMRX             0x34 /* Max RX transfer length */
     24 #define UARTDM_NCF_TX           0x40 /* Number of chars to TX */
     25 
     26 #define UARTDM_RXFS             0x50 /* RX channel status register */
     27 #define UARTDM_RXFS_BUF_SHIFT   0x7  /* Number of bytes in the packing buffer */
     28 #define UARTDM_RXFS_BUF_MASK    0x7
     29 #define UARTDM_MR1				 0x00
     30 #define UARTDM_MR2				 0x04
     31 #define UARTDM_CSR				 0xA0
     32 
     33 #define UARTDM_SR                0xA4 /* Status register */
     34 #define UARTDM_SR_RX_READY       (1 << 0) /* Word is the receiver FIFO */
     35 #define UARTDM_SR_TX_EMPTY       (1 << 3) /* Transmitter underrun */
     36 #define UARTDM_SR_UART_OVERRUN   (1 << 4) /* Receive overrun */
     37 
     38 #define UARTDM_CR                         0xA8 /* Command register */
     39 #define UARTDM_CR_CMD_RESET_ERR           (3 << 4) /* Clear overrun error */
     40 #define UARTDM_CR_CMD_RESET_STALE_INT     (8 << 4) /* Clears stale irq */
     41 #define UARTDM_CR_CMD_RESET_TX_READY      (3 << 8) /* Clears TX Ready irq*/
     42 #define UARTDM_CR_CMD_FORCE_STALE         (4 << 8) /* Causes stale event */
     43 #define UARTDM_CR_CMD_STALE_EVENT_DISABLE (6 << 8) /* Disable stale event */
     44 
     45 #define UARTDM_IMR                0xB0 /* Interrupt mask register */
     46 #define UARTDM_ISR                0xB4 /* Interrupt status register */
     47 #define UARTDM_ISR_TX_READY       0x80 /* TX FIFO empty */
     48 
     49 #define UARTDM_TF               0x100 /* UART Transmit FIFO register */
     50 #define UARTDM_RF               0x140 /* UART Receive FIFO register */
     51 
     52 #define UART_DM_CLK_RX_TX_BIT_RATE 0xCC
     53 #define MSM_BOOT_UART_DM_8_N_1_MODE 0x34
     54 #define MSM_BOOT_UART_DM_CMD_RESET_RX 0x10
     55 #define MSM_BOOT_UART_DM_CMD_RESET_TX 0x20
     56 
     57 DECLARE_GLOBAL_DATA_PTR;
     58 
     59 struct msm_serial_data {
     60 	phys_addr_t base;
     61 	unsigned chars_cnt; /* number of buffered chars */
     62 	uint32_t chars_buf; /* buffered chars */
     63 };
     64 
     65 static int msm_serial_fetch(struct udevice *dev)
     66 {
     67 	struct msm_serial_data *priv = dev_get_priv(dev);
     68 	unsigned sr;
     69 
     70 	if (priv->chars_cnt)
     71 		return priv->chars_cnt;
     72 
     73 	/* Clear error in case of buffer overrun */
     74 	if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN)
     75 		writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR);
     76 
     77 	/* We need to fetch new character */
     78 	sr = readl(priv->base + UARTDM_SR);
     79 
     80 	if (sr & UARTDM_SR_RX_READY) {
     81 		/* There are at least 4 bytes in fifo */
     82 		priv->chars_buf = readl(priv->base + UARTDM_RF);
     83 		priv->chars_cnt = 4;
     84 	} else {
     85 		/* Check if there is anything in fifo */
     86 		priv->chars_cnt = readl(priv->base + UARTDM_RXFS);
     87 		/* Extract number of characters in UART packing buffer*/
     88 		priv->chars_cnt = (priv->chars_cnt >>
     89 				   UARTDM_RXFS_BUF_SHIFT) &
     90 				  UARTDM_RXFS_BUF_MASK;
     91 		if (!priv->chars_cnt)
     92 			return 0;
     93 
     94 		/* There is at least one charcter, move it to fifo */
     95 		writel(UARTDM_CR_CMD_FORCE_STALE,
     96 		       priv->base + UARTDM_CR);
     97 
     98 		priv->chars_buf = readl(priv->base + UARTDM_RF);
     99 		writel(UARTDM_CR_CMD_RESET_STALE_INT,
    100 		       priv->base + UARTDM_CR);
    101 		writel(0x7, priv->base + UARTDM_DMRX);
    102 	}
    103 
    104 	return priv->chars_cnt;
    105 }
    106 
    107 static int msm_serial_getc(struct udevice *dev)
    108 {
    109 	struct msm_serial_data *priv = dev_get_priv(dev);
    110 	char c;
    111 
    112 	if (!msm_serial_fetch(dev))
    113 		return -EAGAIN;
    114 
    115 	c = priv->chars_buf & 0xFF;
    116 	priv->chars_buf >>= 8;
    117 	priv->chars_cnt--;
    118 
    119 	return c;
    120 }
    121 
    122 static int msm_serial_putc(struct udevice *dev, const char ch)
    123 {
    124 	struct msm_serial_data *priv = dev_get_priv(dev);
    125 
    126 	if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
    127 	    !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
    128 		return -EAGAIN;
    129 
    130 	writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR);
    131 
    132 	writel(1, priv->base + UARTDM_NCF_TX);
    133 	writel(ch, priv->base + UARTDM_TF);
    134 
    135 	return 0;
    136 }
    137 
    138 static int msm_serial_pending(struct udevice *dev, bool input)
    139 {
    140 	if (input) {
    141 		if (msm_serial_fetch(dev))
    142 			return 1;
    143 	}
    144 
    145 	return 0;
    146 }
    147 
    148 static const struct dm_serial_ops msm_serial_ops = {
    149 	.putc = msm_serial_putc,
    150 	.pending = msm_serial_pending,
    151 	.getc = msm_serial_getc,
    152 };
    153 
    154 static int msm_uart_clk_init(struct udevice *dev)
    155 {
    156 	uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
    157 					"clock-frequency", 115200);
    158 	uint clkd[2]; /* clk_id and clk_no */
    159 	int clk_offset;
    160 	struct udevice *clk_dev;
    161 	struct clk clk;
    162 	int ret;
    163 
    164 	ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "clock",
    165 				   clkd, 2);
    166 	if (ret)
    167 		return ret;
    168 
    169 	clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
    170 	if (clk_offset < 0)
    171 		return clk_offset;
    172 
    173 	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
    174 	if (ret)
    175 		return ret;
    176 
    177 	clk.id = clkd[1];
    178 	ret = clk_request(clk_dev, &clk);
    179 	if (ret < 0)
    180 		return ret;
    181 
    182 	ret = clk_set_rate(&clk, clk_rate);
    183 	clk_free(&clk);
    184 	if (ret < 0)
    185 		return ret;
    186 
    187 	return 0;
    188 }
    189 
    190 static void uart_dm_init(struct msm_serial_data *priv)
    191 {
    192 	writel(UART_DM_CLK_RX_TX_BIT_RATE, priv->base + UARTDM_CSR);
    193 	writel(0x0, priv->base + UARTDM_MR1);
    194 	writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2);
    195 	writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR);
    196 	writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR);
    197 }
    198 static int msm_serial_probe(struct udevice *dev)
    199 {
    200 	int ret;
    201 	struct msm_serial_data *priv = dev_get_priv(dev);
    202 
    203 	/* No need to reinitialize the UART after relocation */
    204 	if (gd->flags & GD_FLG_RELOC)
    205 		return 0;
    206 
    207 	ret = msm_uart_clk_init(dev);
    208 	if (ret)
    209 		return ret;
    210 
    211 	pinctrl_select_state(dev, "uart");
    212 	uart_dm_init(priv);
    213 
    214 	return 0;
    215 }
    216 
    217 static int msm_serial_ofdata_to_platdata(struct udevice *dev)
    218 {
    219 	struct msm_serial_data *priv = dev_get_priv(dev);
    220 
    221 	priv->base = devfdt_get_addr(dev);
    222 	if (priv->base == FDT_ADDR_T_NONE)
    223 		return -EINVAL;
    224 
    225 	return 0;
    226 }
    227 
    228 static const struct udevice_id msm_serial_ids[] = {
    229 	{ .compatible = "qcom,msm-uartdm-v1.4" },
    230 	{ }
    231 };
    232 
    233 U_BOOT_DRIVER(serial_msm) = {
    234 	.name	= "serial_msm",
    235 	.id	= UCLASS_SERIAL,
    236 	.of_match = msm_serial_ids,
    237 	.ofdata_to_platdata = msm_serial_ofdata_to_platdata,
    238 	.priv_auto_alloc_size = sizeof(struct msm_serial_data),
    239 	.probe = msm_serial_probe,
    240 	.ops	= &msm_serial_ops,
    241 };
    242