1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2012-2015 Panasonic Corporation
4 * Copyright (C) 2015-2016 Socionext Inc.
5 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
6 */
7
8 #include <dm.h>
9 #include <linux/bitfield.h>
10 #include <linux/bitops.h>
11 #include <linux/bug.h>
12 #include <linux/io.h>
13 #include <linux/serial_reg.h>
14 #include <linux/sizes.h>
15 #include <linux/errno.h>
16 #include <serial.h>
17 #include <fdtdec.h>
18
19 #define UNIPHIER_UART_REGSHIFT 2
20
21 #define UNIPHIER_UART_RX (0 << (UNIPHIER_UART_REGSHIFT))
22 #define UNIPHIER_UART_TX UNIPHIER_UART_RX
23 /* bit[15:8] = CHAR, bit[7:0] = FCR */
24 #define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT))
25 #define UNIPHIER_UART_FCR_MASK GENMASK(7, 0)
26 /* bit[15:8] = LCR, bit[7:0] = MCR */
27 #define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT))
28 #define UNIPHIER_UART_LCR_MASK GENMASK(15, 8)
29 #define UNIPHIER_UART_LSR (5 << (UNIPHIER_UART_REGSHIFT))
30 /* Divisor Latch Register */
31 #define UNIPHIER_UART_DLR (9 << (UNIPHIER_UART_REGSHIFT))
32
33 struct uniphier_serial_priv {
34 void __iomem *membase;
35 unsigned int uartclk;
36 };
37
uniphier_serial_setbrg(struct udevice * dev,int baudrate)38 static int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
39 {
40 struct uniphier_serial_priv *priv = dev_get_priv(dev);
41 static const unsigned int mode_x_div = 16;
42 unsigned int divisor;
43
44 divisor = DIV_ROUND_CLOSEST(priv->uartclk, mode_x_div * baudrate);
45
46 /* flush the trasmitter before changing hw setting */
47 while (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_TEMT))
48 ;
49
50 writel(divisor, priv->membase + UNIPHIER_UART_DLR);
51
52 return 0;
53 }
54
uniphier_serial_getc(struct udevice * dev)55 static int uniphier_serial_getc(struct udevice *dev)
56 {
57 struct uniphier_serial_priv *priv = dev_get_priv(dev);
58
59 if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR))
60 return -EAGAIN;
61
62 return readl(priv->membase + UNIPHIER_UART_RX);
63 }
64
uniphier_serial_putc(struct udevice * dev,const char c)65 static int uniphier_serial_putc(struct udevice *dev, const char c)
66 {
67 struct uniphier_serial_priv *priv = dev_get_priv(dev);
68
69 if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE))
70 return -EAGAIN;
71
72 writel(c, priv->membase + UNIPHIER_UART_TX);
73
74 return 0;
75 }
76
uniphier_serial_pending(struct udevice * dev,bool input)77 static int uniphier_serial_pending(struct udevice *dev, bool input)
78 {
79 struct uniphier_serial_priv *priv = dev_get_priv(dev);
80
81 if (input)
82 return readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR;
83 else
84 return !(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE);
85 }
86
87 /*
88 * SPL does not have enough memory footprint for the clock driver.
89 * Hardcode clock frequency for each SoC.
90 */
91 struct uniphier_serial_clk_data {
92 const char *compatible;
93 unsigned int clk_rate;
94 };
95
96 static const struct uniphier_serial_clk_data uniphier_serial_clk_data[] = {
97 { .compatible = "socionext,uniphier-ld4", .clk_rate = 36864000 },
98 { .compatible = "socionext,uniphier-pro4", .clk_rate = 73728000 },
99 { .compatible = "socionext,uniphier-sld8", .clk_rate = 80000000 },
100 { .compatible = "socionext,uniphier-pro5", .clk_rate = 73728000 },
101 { .compatible = "socionext,uniphier-pxs2", .clk_rate = 88888888 },
102 { .compatible = "socionext,uniphier-ld6b", .clk_rate = 88888888 },
103 { .compatible = "socionext,uniphier-ld11", .clk_rate = 58823529 },
104 { .compatible = "socionext,uniphier-ld20", .clk_rate = 58823529 },
105 { .compatible = "socionext,uniphier-pxs3", .clk_rate = 58823529 },
106 { /* sentinel */ },
107 };
108
uniphier_serial_probe(struct udevice * dev)109 static int uniphier_serial_probe(struct udevice *dev)
110 {
111 struct uniphier_serial_priv *priv = dev_get_priv(dev);
112 const struct uniphier_serial_clk_data *clk_data;
113 ofnode root_node;
114 fdt_addr_t base;
115 u32 tmp;
116
117 base = dev_read_addr(dev);
118 if (base == FDT_ADDR_T_NONE)
119 return -EINVAL;
120
121 priv->membase = devm_ioremap(dev, base, SZ_64);
122 if (!priv->membase)
123 return -ENOMEM;
124
125 root_node = ofnode_path("/");
126 clk_data = uniphier_serial_clk_data;
127 while (clk_data->compatible) {
128 if (ofnode_device_is_compatible(root_node,
129 clk_data->compatible))
130 break;
131 clk_data++;
132 }
133
134 if (WARN_ON(!clk_data->compatible))
135 return -ENOTSUPP;
136
137 priv->uartclk = clk_data->clk_rate;
138
139 /* flush the trasmitter before changing hw setting */
140 while (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_TEMT))
141 ;
142
143 /* enable FIFO */
144 tmp = readl(priv->membase + UNIPHIER_UART_CHAR_FCR);
145 tmp &= ~UNIPHIER_UART_FCR_MASK;
146 tmp |= FIELD_PREP(UNIPHIER_UART_FCR_MASK, UART_FCR_ENABLE_FIFO);
147 writel(tmp, priv->membase + UNIPHIER_UART_CHAR_FCR);
148
149 tmp = readl(priv->membase + UNIPHIER_UART_LCR_MCR);
150 tmp &= ~UNIPHIER_UART_LCR_MASK;
151 tmp |= FIELD_PREP(UNIPHIER_UART_LCR_MASK, UART_LCR_WLEN8);
152 writel(tmp, priv->membase + UNIPHIER_UART_LCR_MCR);
153
154 return 0;
155 }
156
157 static const struct udevice_id uniphier_uart_of_match[] = {
158 { .compatible = "socionext,uniphier-uart" },
159 { /* sentinel */ }
160 };
161
162 static const struct dm_serial_ops uniphier_serial_ops = {
163 .setbrg = uniphier_serial_setbrg,
164 .getc = uniphier_serial_getc,
165 .putc = uniphier_serial_putc,
166 .pending = uniphier_serial_pending,
167 };
168
169 U_BOOT_DRIVER(uniphier_serial) = {
170 .name = "uniphier-uart",
171 .id = UCLASS_SERIAL,
172 .of_match = uniphier_uart_of_match,
173 .probe = uniphier_serial_probe,
174 .priv_auto = sizeof(struct uniphier_serial_priv),
175 .ops = &uniphier_serial_ops,
176 };
177