[U-Boot] [PATCH v6 0/2] Introduce driver model serial uclass (exynos only)

Now that the serial uclass has been applied, this series includes only the exynos serial driver patches. It enables serial using driver model for all board that use the serial_s5p driver.
To see the current state of driver model, look at u-boot-dm.git branch 'working'.
Changes in v6: - Drop already-applied tegra patches - Rebase on top of master
Changes in v3: - Avoid reordering functions - Change pre-reloc fdt property to 'u-boot,dm-pre-reloc'
Simon Glass (2): dm: exynos: Mark exynos5 console as pre-reloc dm: exynos: Move serial to driver model
arch/arm/dts/exynos5.dtsi | 1 + drivers/serial/serial_s5p.c | 255 ++++++++++++---------------------------- include/configs/exynos-common.h | 1 + include/configs/s5p_goni.h | 1 + include/configs/smdkc100.h | 1 + 5 files changed, 76 insertions(+), 183 deletions(-)

We will need the console before relocation, so mark it that way.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v6: None Changes in v3: - Change pre-reloc fdt property to 'u-boot,dm-pre-reloc'
arch/arm/dts/exynos5.dtsi | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/exynos5.dtsi b/arch/arm/dts/exynos5.dtsi index dc5405b..e539068 100644 --- a/arch/arm/dts/exynos5.dtsi +++ b/arch/arm/dts/exynos5.dtsi @@ -244,6 +244,7 @@ compatible = "samsung,exynos4210-uart"; reg = <0x12C30000 0x100>; interrupts = <0 54 0>; + u-boot,dm-pre-reloc; id = <3>; };

On 14 September 2014 16:36, Simon Glass sjg@chromium.org wrote:
We will need the console before relocation, so mark it that way.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v6: None
Applied to u-boot-dm/master.

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 ---
Changes in v6: - Drop already-applied tegra patches - Rebase on top of master
Changes in v3: - Avoid reordering functions
drivers/serial/serial_s5p.c | 255 ++++++++++++---------------------------- include/configs/exynos-common.h | 1 + include/configs/s5p_goni.h | 1 + include/configs/smdkc100.h | 1 + 4 files changed, 75 insertions(+), 183 deletions(-)
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 98c62b4..8469afd 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -9,6 +9,8 @@ */
#include <common.h> +#include <dm.h> +#include <errno.h> #include <fdtdec.h> #include <linux/compiler.h> #include <asm/io.h> @@ -18,26 +20,18 @@
DECLARE_GLOBAL_DATA_PTR;
-#define RX_FIFO_COUNT_MASK 0xff -#define RX_FIFO_FULL_MASK (1 << 8) -#define TX_FIFO_FULL_MASK (1 << 24) +#define RX_FIFO_COUNT_SHIFT 0 +#define RX_FIFO_COUNT_MASK (0xff << RX_FIFO_COUNT_SHIFT) +#define RX_FIFO_FULL (1 << 8) +#define TX_FIFO_COUNT_SHIFT 16 +#define TX_FIFO_COUNT_MASK (0xff << TX_FIFO_COUNT_SHIFT) +#define TX_FIFO_FULL (1 << 24)
/* Information about a serial port */ -struct fdt_serial { - u32 base_addr; /* address of registers in physical memory */ +struct s5p_serial_platdata { + struct s5p_uart *reg; /* address of registers in physical memory */ u8 port_id; /* uart port number */ - u8 enabled; /* 1 if enabled, 0 if disabled */ -} config __attribute__ ((section(".data"))); - -static inline struct s5p_uart *s5p_get_base_uart(int dev_index) -{ -#ifdef CONFIG_OF_CONTROL - return (struct s5p_uart *)(config.base_addr); -#else - u32 offset = dev_index * sizeof(struct s5p_uart); - return (struct s5p_uart *)(samsung_get_base_uart() + offset); -#endif -} +};
/* * The coefficient, used to calculate the baudrate on S5P UARTs is @@ -65,23 +59,13 @@ static const int udivslot[] = { 0xffdf, };
-static void serial_setbrg_dev(const int dev_index) +int s5p_serial_setbrg(struct udevice *dev, int baudrate) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - u32 uclk = get_uart_clk(dev_index); - u32 baudrate = gd->baudrate; + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; + u32 uclk = get_uart_clk(plat->port_id); u32 val;
-#if defined(CONFIG_SILENT_CONSOLE) && \ - defined(CONFIG_OF_CONTROL) && \ - !defined(CONFIG_SPL_BUILD) - if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0)) - gd->flags |= GD_FLG_SILENT; -#endif - - if (!config.enabled) - return; - val = uclk / baudrate;
writel(val / 16 - 1, &uart->ubrdiv); @@ -90,15 +74,14 @@ static void serial_setbrg_dev(const int dev_index) writew(udivslot[val % 16], &uart->rest.slot); else writeb(val % 16, &uart->rest.value); + + return 0; }
-/* - * Initialise the serial port with the given baudrate. The settings - * are always 8 data bits, no parity, 1 stop bit, no start bits. - */ -static int serial_init_dev(const int dev_index) +static int s5p_serial_probe(struct udevice *dev) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg;
/* enable FIFOs, auto clear Rx FIFO */ writel(0x3, &uart->ufcon); @@ -108,14 +91,11 @@ static int serial_init_dev(const int dev_index) /* No interrupts, no DMA, pure polling */ writel(0x245, &uart->ucon);
- serial_setbrg_dev(dev_index); - return 0; }
-static int serial_err_check(const int dev_index, int op) +static int serial_err_check(const struct s5p_uart *const uart, int op) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); unsigned int mask;
/* @@ -133,169 +113,78 @@ static int serial_err_check(const int dev_index, int op) return readl(&uart->uerstat) & mask; }
-/* - * Read a single byte from the serial port. Returns 1 on success, 0 - * otherwise. When the function is succesfull, the character read is - * written into its argument c. - */ -static int serial_getc_dev(const int dev_index) +static int s5p_serial_getc(struct udevice *dev) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - - if (!config.enabled) - return 0; + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg;
- /* wait for character to arrive */ - while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | - RX_FIFO_FULL_MASK))) { - if (serial_err_check(dev_index, 0)) - return 0; - } + if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK)) + return -EAGAIN;
+ serial_err_check(uart, 0); return (int)(readb(&uart->urxh) & 0xff); }
-/* - * Output a single byte to the serial port. - */ -static void serial_putc_dev(const char c, const int dev_index) +static int s5p_serial_putc(struct udevice *dev, const char ch) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - - if (!config.enabled) - return; - - /* wait for room in the tx FIFO */ - while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) { - if (serial_err_check(dev_index, 1)) - return; - } + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg;
- writeb(c, &uart->utxh); + if (readl(&uart->ufstat) & TX_FIFO_FULL) + return -EAGAIN;
- /* If \n, also do \r */ - if (c == '\n') - serial_putc('\r'); -} - -/* - * Test whether a character is in the RX buffer - */ -static int serial_tstc_dev(const int dev_index) -{ - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + writeb(ch, &uart->utxh); + serial_err_check(uart, 1);
- if (!config.enabled) - return 0; - - return (int)(readl(&uart->utrstat) & 0x1); + return 0; }
-static void serial_puts_dev(const char *s, const int dev_index) +static int s5p_serial_pending(struct udevice *dev, bool input) { - while (*s) - serial_putc_dev(*s++, dev_index); -} + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; + uint32_t ufstat = readl(&uart->ufstat);
-/* Multi serial device functions */ -#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \ -static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \ -static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \ -static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \ -static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ -static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ -static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } - -#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \ - .name = __name, \ - .start = s5p_serial##port##_init, \ - .stop = NULL, \ - .setbrg = s5p_serial##port##_setbrg, \ - .getc = s5p_serial##port##_getc, \ - .tstc = s5p_serial##port##_tstc, \ - .putc = s5p_serial##port##_putc, \ - .puts = s5p_serial##port##_puts, \ + if (input) + return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT; + else + return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT; }
-DECLARE_S5P_SERIAL_FUNCTIONS(0); -struct serial_device s5p_serial0_device = - INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0"); -DECLARE_S5P_SERIAL_FUNCTIONS(1); -struct serial_device s5p_serial1_device = - INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1"); -DECLARE_S5P_SERIAL_FUNCTIONS(2); -struct serial_device s5p_serial2_device = - INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2"); -DECLARE_S5P_SERIAL_FUNCTIONS(3); -struct serial_device s5p_serial3_device = - INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3"); - -#ifdef CONFIG_OF_CONTROL -int fdtdec_decode_console(int *index, struct fdt_serial *uart) +static int s5p_serial_ofdata_to_platdata(struct udevice *dev) { - const void *blob = gd->fdt_blob; - int node; + struct s5p_serial_platdata *plat = dev->platdata; + fdt_addr_t addr;
- node = fdt_path_offset(blob, "console"); - if (node < 0) - return node; + addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL;
- uart->base_addr = fdtdec_get_addr(blob, node, "reg"); - if (uart->base_addr == FDT_ADDR_T_NONE) - return -FDT_ERR_NOTFOUND; - - uart->port_id = fdtdec_get_int(blob, node, "id", -1); - uart->enabled = fdtdec_get_is_enabled(blob, node); + plat->reg = (struct s5p_uart *)addr; + plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1);
return 0; } -#endif
-__weak struct serial_device *default_serial_console(void) -{ -#ifdef CONFIG_OF_CONTROL - int index = 0; - - if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) { - debug("Cannot decode default console node\n"); - return NULL; - } - - switch (config.port_id) { - case 0: - return &s5p_serial0_device; - case 1: - return &s5p_serial1_device; - case 2: - return &s5p_serial2_device; - case 3: - return &s5p_serial3_device; - default: - debug("Unknown config.port_id: %d", config.port_id); - break; - } - - return NULL; -#else - config.enabled = 1; -#if defined(CONFIG_SERIAL0) - return &s5p_serial0_device; -#elif defined(CONFIG_SERIAL1) - return &s5p_serial1_device; -#elif defined(CONFIG_SERIAL2) - return &s5p_serial2_device; -#elif defined(CONFIG_SERIAL3) - return &s5p_serial3_device; -#else -#error "CONFIG_SERIAL? missing." -#endif -#endif -} +static const struct dm_serial_ops s5p_serial_ops = { + .putc = s5p_serial_putc, + .pending = s5p_serial_pending, + .getc = s5p_serial_getc, + .setbrg = s5p_serial_setbrg, +};
-void s5p_serial_initialize(void) -{ - serial_register(&s5p_serial0_device); - serial_register(&s5p_serial1_device); - serial_register(&s5p_serial2_device); - serial_register(&s5p_serial3_device); -} +static const struct udevice_id s5p_serial_ids[] = { + { .compatible = "samsung,exynos4210-uart" }, + { } +}; + +U_BOOT_DRIVER(serial_s5p) = { + .name = "serial_s5p", + .id = UCLASS_SERIAL, + .of_match = s5p_serial_ids, + .ofdata_to_platdata = s5p_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata), + .probe = s5p_serial_probe, + .ops = &s5p_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/configs/exynos-common.h b/include/configs/exynos-common.h index de351b4..2c67e11 100644 --- a/include/configs/exynos-common.h +++ b/include/configs/exynos-common.h @@ -20,6 +20,7 @@ #define CONFIG_DM #define CONFIG_CMD_DM #define CONFIG_DM_GPIO +#define CONFIG_DM_SERIAL
#define CONFIG_ARCH_CPU_INIT #define CONFIG_DISPLAY_CPUINFO diff --git a/include/configs/s5p_goni.h b/include/configs/s5p_goni.h index 74771bf..77469cf 100644 --- a/include/configs/s5p_goni.h +++ b/include/configs/s5p_goni.h @@ -293,5 +293,6 @@ #define CONFIG_DM #define CONFIG_CMD_DM #define CONFIG_DM_GPIO +#define CONFIG_DM_SERIAL
#endif /* __CONFIG_H */ diff --git a/include/configs/smdkc100.h b/include/configs/smdkc100.h index cb73476..3013df1 100644 --- a/include/configs/smdkc100.h +++ b/include/configs/smdkc100.h @@ -230,5 +230,6 @@ #define CONFIG_DM #define CONFIG_CMD_DM #define CONFIG_DM_GPIO +#define CONFIG_DM_SERIAL
#endif /* __CONFIG_H */

On 14 September 2014 16:36, Simon Glass sjg@chromium.org wrote:
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
Changes in v6:
- Drop already-applied tegra patches
- Rebase on top of master
dm: exynos: Move serial to driver model
participants (1)
-
Simon Glass