Commit 73e256c2ac7a67b00be69a397997d80d04ec994d

Authored by Simon Glass
1 parent 9208fffebc

dm: exynos: Move serial to driver model

Change the Exynos serial driver to work with driver model and switch over
all relevant boards to use it.

Signed-off-by: Simon Glass <sjg@chromium.org>

Showing 4 changed files with 75 additions and 183 deletions Side-by-side Diff

drivers/serial/serial_s5p.c
... ... @@ -9,6 +9,8 @@
9 9 */
10 10  
11 11 #include <common.h>
  12 +#include <dm.h>
  13 +#include <errno.h>
12 14 #include <fdtdec.h>
13 15 #include <linux/compiler.h>
14 16 #include <asm/io.h>
15 17  
16 18  
17 19  
... ... @@ -18,27 +20,19 @@
18 20  
19 21 DECLARE_GLOBAL_DATA_PTR;
20 22  
21   -#define RX_FIFO_COUNT_MASK 0xff
22   -#define RX_FIFO_FULL_MASK (1 << 8)
23   -#define TX_FIFO_FULL_MASK (1 << 24)
  23 +#define RX_FIFO_COUNT_SHIFT 0
  24 +#define RX_FIFO_COUNT_MASK (0xff << RX_FIFO_COUNT_SHIFT)
  25 +#define RX_FIFO_FULL (1 << 8)
  26 +#define TX_FIFO_COUNT_SHIFT 16
  27 +#define TX_FIFO_COUNT_MASK (0xff << TX_FIFO_COUNT_SHIFT)
  28 +#define TX_FIFO_FULL (1 << 24)
24 29  
25 30 /* Information about a serial port */
26   -struct fdt_serial {
27   - u32 base_addr; /* address of registers in physical memory */
  31 +struct s5p_serial_platdata {
  32 + struct s5p_uart *reg; /* address of registers in physical memory */
28 33 u8 port_id; /* uart port number */
29   - u8 enabled; /* 1 if enabled, 0 if disabled */
30   -} config __attribute__ ((section(".data")));
  34 +};
31 35  
32   -static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
33   -{
34   -#ifdef CONFIG_OF_CONTROL
35   - return (struct s5p_uart *)(config.base_addr);
36   -#else
37   - u32 offset = dev_index * sizeof(struct s5p_uart);
38   - return (struct s5p_uart *)(samsung_get_base_uart() + offset);
39   -#endif
40   -}
41   -
42 36 /*
43 37 * The coefficient, used to calculate the baudrate on S5P UARTs is
44 38 * calculated as
45 39  
46 40  
... ... @@ -65,23 +59,13 @@
65 59 0xffdf,
66 60 };
67 61  
68   -static void serial_setbrg_dev(const int dev_index)
  62 +int s5p_serial_setbrg(struct udevice *dev, int baudrate)
69 63 {
70   - struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
71   - u32 uclk = get_uart_clk(dev_index);
72   - u32 baudrate = gd->baudrate;
  64 + struct s5p_serial_platdata *plat = dev->platdata;
  65 + struct s5p_uart *const uart = plat->reg;
  66 + u32 uclk = get_uart_clk(plat->port_id);
73 67 u32 val;
74 68  
75   -#if defined(CONFIG_SILENT_CONSOLE) && \
76   - defined(CONFIG_OF_CONTROL) && \
77   - !defined(CONFIG_SPL_BUILD)
78   - if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0))
79   - gd->flags |= GD_FLG_SILENT;
80   -#endif
81   -
82   - if (!config.enabled)
83   - return;
84   -
85 69 val = uclk / baudrate;
86 70  
87 71 writel(val / 16 - 1, &uart->ubrdiv);
88 72  
89 73  
... ... @@ -90,15 +74,14 @@
90 74 writew(udivslot[val % 16], &uart->rest.slot);
91 75 else
92 76 writeb(val % 16, &uart->rest.value);
  77 +
  78 + return 0;
93 79 }
94 80  
95   -/*
96   - * Initialise the serial port with the given baudrate. The settings
97   - * are always 8 data bits, no parity, 1 stop bit, no start bits.
98   - */
99   -static int serial_init_dev(const int dev_index)
  81 +static int s5p_serial_probe(struct udevice *dev)
100 82 {
101   - struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
  83 + struct s5p_serial_platdata *plat = dev->platdata;
  84 + struct s5p_uart *const uart = plat->reg;
102 85  
103 86 /* enable FIFOs, auto clear Rx FIFO */
104 87 writel(0x3, &uart->ufcon);
105 88  
106 89  
... ... @@ -108,14 +91,11 @@
108 91 /* No interrupts, no DMA, pure polling */
109 92 writel(0x245, &uart->ucon);
110 93  
111   - serial_setbrg_dev(dev_index);
112   -
113 94 return 0;
114 95 }
115 96  
116   -static int serial_err_check(const int dev_index, int op)
  97 +static int serial_err_check(const struct s5p_uart *const uart, int op)
117 98 {
118   - struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
119 99 unsigned int mask;
120 100  
121 101 /*
122 102  
123 103  
124 104  
125 105  
126 106  
127 107  
128 108  
129 109  
130 110  
131 111  
132 112  
133 113  
134 114  
135 115  
136 116  
137 117  
138 118  
139 119  
140 120  
141 121  
... ... @@ -133,170 +113,79 @@
133 113 return readl(&uart->uerstat) & mask;
134 114 }
135 115  
136   -/*
137   - * Read a single byte from the serial port. Returns 1 on success, 0
138   - * otherwise. When the function is succesfull, the character read is
139   - * written into its argument c.
140   - */
141   -static int serial_getc_dev(const int dev_index)
  116 +static int s5p_serial_getc(struct udevice *dev)
142 117 {
143   - struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
  118 + struct s5p_serial_platdata *plat = dev->platdata;
  119 + struct s5p_uart *const uart = plat->reg;
144 120  
145   - if (!config.enabled)
146   - return 0;
  121 + if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK))
  122 + return -EAGAIN;
147 123  
148   - /* wait for character to arrive */
149   - while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
150   - RX_FIFO_FULL_MASK))) {
151   - if (serial_err_check(dev_index, 0))
152   - return 0;
153   - }
154   -
  124 + serial_err_check(uart, 0);
155 125 return (int)(readb(&uart->urxh) & 0xff);
156 126 }
157 127  
158   -/*
159   - * Output a single byte to the serial port.
160   - */
161   -static void serial_putc_dev(const char c, const int dev_index)
  128 +static int s5p_serial_putc(struct udevice *dev, const char ch)
162 129 {
163   - struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
  130 + struct s5p_serial_platdata *plat = dev->platdata;
  131 + struct s5p_uart *const uart = plat->reg;
164 132  
165   - if (!config.enabled)
166   - return;
  133 + if (readl(&uart->ufstat) & TX_FIFO_FULL)
  134 + return -EAGAIN;
167 135  
168   - /* wait for room in the tx FIFO */
169   - while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
170   - if (serial_err_check(dev_index, 1))
171   - return;
172   - }
  136 + writeb(ch, &uart->utxh);
  137 + serial_err_check(uart, 1);
173 138  
174   - writeb(c, &uart->utxh);
175   -
176   - /* If \n, also do \r */
177   - if (c == '\n')
178   - serial_putc('\r');
  139 + return 0;
179 140 }
180 141  
181   -/*
182   - * Test whether a character is in the RX buffer
183   - */
184   -static int serial_tstc_dev(const int dev_index)
  142 +static int s5p_serial_pending(struct udevice *dev, bool input)
185 143 {
186   - struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
  144 + struct s5p_serial_platdata *plat = dev->platdata;
  145 + struct s5p_uart *const uart = plat->reg;
  146 + uint32_t ufstat = readl(&uart->ufstat);
187 147  
188   - if (!config.enabled)
189   - return 0;
190   -
191   - return (int)(readl(&uart->utrstat) & 0x1);
  148 + if (input)
  149 + return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT;
  150 + else
  151 + return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT;
192 152 }
193 153  
194   -static void serial_puts_dev(const char *s, const int dev_index)
  154 +static int s5p_serial_ofdata_to_platdata(struct udevice *dev)
195 155 {
196   - while (*s)
197   - serial_putc_dev(*s++, dev_index);
198   -}
  156 + struct s5p_serial_platdata *plat = dev->platdata;
  157 + fdt_addr_t addr;
199 158  
200   -/* Multi serial device functions */
201   -#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \
202   -static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \
203   -static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \
204   -static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \
205   -static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \
206   -static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \
207   -static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); }
  159 + addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
  160 + if (addr == FDT_ADDR_T_NONE)
  161 + return -EINVAL;
208 162  
209   -#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \
210   - .name = __name, \
211   - .start = s5p_serial##port##_init, \
212   - .stop = NULL, \
213   - .setbrg = s5p_serial##port##_setbrg, \
214   - .getc = s5p_serial##port##_getc, \
215   - .tstc = s5p_serial##port##_tstc, \
216   - .putc = s5p_serial##port##_putc, \
217   - .puts = s5p_serial##port##_puts, \
218   -}
  163 + plat->reg = (struct s5p_uart *)addr;
  164 + plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1);
219 165  
220   -DECLARE_S5P_SERIAL_FUNCTIONS(0);
221   -struct serial_device s5p_serial0_device =
222   - INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");
223   -DECLARE_S5P_SERIAL_FUNCTIONS(1);
224   -struct serial_device s5p_serial1_device =
225   - INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1");
226   -DECLARE_S5P_SERIAL_FUNCTIONS(2);
227   -struct serial_device s5p_serial2_device =
228   - INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2");
229   -DECLARE_S5P_SERIAL_FUNCTIONS(3);
230   -struct serial_device s5p_serial3_device =
231   - INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3");
232   -
233   -#ifdef CONFIG_OF_CONTROL
234   -int fdtdec_decode_console(int *index, struct fdt_serial *uart)
235   -{
236   - const void *blob = gd->fdt_blob;
237   - int node;
238   -
239   - node = fdt_path_offset(blob, "console");
240   - if (node < 0)
241   - return node;
242   -
243   - uart->base_addr = fdtdec_get_addr(blob, node, "reg");
244   - if (uart->base_addr == FDT_ADDR_T_NONE)
245   - return -FDT_ERR_NOTFOUND;
246   -
247   - uart->port_id = fdtdec_get_int(blob, node, "id", -1);
248   - uart->enabled = fdtdec_get_is_enabled(blob, node);
249   -
250 166 return 0;
251 167 }
252   -#endif
253 168  
254   -__weak struct serial_device *default_serial_console(void)
255   -{
256   -#ifdef CONFIG_OF_CONTROL
257   - int index = 0;
  169 +static const struct dm_serial_ops s5p_serial_ops = {
  170 + .putc = s5p_serial_putc,
  171 + .pending = s5p_serial_pending,
  172 + .getc = s5p_serial_getc,
  173 + .setbrg = s5p_serial_setbrg,
  174 +};
258 175  
259   - if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) {
260   - debug("Cannot decode default console node\n");
261   - return NULL;
262   - }
  176 +static const struct udevice_id s5p_serial_ids[] = {
  177 + { .compatible = "samsung,exynos4210-uart" },
  178 + { }
  179 +};
263 180  
264   - switch (config.port_id) {
265   - case 0:
266   - return &s5p_serial0_device;
267   - case 1:
268   - return &s5p_serial1_device;
269   - case 2:
270   - return &s5p_serial2_device;
271   - case 3:
272   - return &s5p_serial3_device;
273   - default:
274   - debug("Unknown config.port_id: %d", config.port_id);
275   - break;
276   - }
277   -
278   - return NULL;
279   -#else
280   - config.enabled = 1;
281   -#if defined(CONFIG_SERIAL0)
282   - return &s5p_serial0_device;
283   -#elif defined(CONFIG_SERIAL1)
284   - return &s5p_serial1_device;
285   -#elif defined(CONFIG_SERIAL2)
286   - return &s5p_serial2_device;
287   -#elif defined(CONFIG_SERIAL3)
288   - return &s5p_serial3_device;
289   -#else
290   -#error "CONFIG_SERIAL? missing."
291   -#endif
292   -#endif
293   -}
294   -
295   -void s5p_serial_initialize(void)
296   -{
297   - serial_register(&s5p_serial0_device);
298   - serial_register(&s5p_serial1_device);
299   - serial_register(&s5p_serial2_device);
300   - serial_register(&s5p_serial3_device);
301   -}
  181 +U_BOOT_DRIVER(serial_s5p) = {
  182 + .name = "serial_s5p",
  183 + .id = UCLASS_SERIAL,
  184 + .of_match = s5p_serial_ids,
  185 + .ofdata_to_platdata = s5p_serial_ofdata_to_platdata,
  186 + .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
  187 + .probe = s5p_serial_probe,
  188 + .ops = &s5p_serial_ops,
  189 + .flags = DM_FLAG_PRE_RELOC,
  190 +};
include/configs/exynos-common.h
... ... @@ -20,6 +20,7 @@
20 20 #define CONFIG_DM
21 21 #define CONFIG_CMD_DM
22 22 #define CONFIG_DM_GPIO
  23 +#define CONFIG_DM_SERIAL
23 24  
24 25 #define CONFIG_ARCH_CPU_INIT
25 26 #define CONFIG_DISPLAY_CPUINFO
include/configs/s5p_goni.h
... ... @@ -292,6 +292,7 @@
292 292 #define CONFIG_DM
293 293 #define CONFIG_CMD_DM
294 294 #define CONFIG_DM_GPIO
  295 +#define CONFIG_DM_SERIAL
295 296  
296 297 #endif /* __CONFIG_H */
include/configs/smdkc100.h
... ... @@ -227,6 +227,7 @@
227 227 #define CONFIG_DM
228 228 #define CONFIG_CMD_DM
229 229 #define CONFIG_DM_GPIO
  230 +#define CONFIG_DM_SERIAL
230 231  
231 232 #endif /* __CONFIG_H */