diff options
author | Tom Rini <trini@konsulko.com> | 2017-04-13 17:31:06 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-04-13 17:31:06 -0400 |
commit | b7b24a7a3cd74bb165d28a2959ed9143e3648fbf (patch) | |
tree | 062fd13092cee10dc8746a1339ecea18f08d21d6 /drivers | |
parent | 1622559066d890f1b7622be0ede8a5d64de66ef3 (diff) | |
parent | 22e10be456014400788f80d45fc5f5c0b9d4a81d (diff) | |
download | u-boot-b7b24a7a3cd74bb165d28a2959ed9143e3648fbf.tar.gz |
Merge git://git.denx.de/u-boot-dm
Here with some DM changes as well as the long-standing AT91 DM/DT
conversion patches which I have picked up via dm.
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/device.c | 30 | ||||
-rw-r--r-- | drivers/core/uclass.c | 2 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 13 | ||||
-rw-r--r-- | drivers/gpio/at91_gpio.c | 170 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 5 | ||||
-rw-r--r-- | drivers/net/at91_emac.c | 4 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 14 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-at91.c | 453 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 13 |
10 files changed, 649 insertions, 56 deletions
diff --git a/drivers/core/device.c b/drivers/core/device.c index e1b0ebffc5..09a115f753 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -255,8 +255,36 @@ static void *alloc_priv(int size, uint flags) if (flags & DM_FLAG_ALLOC_PRIV_DMA) { priv = memalign(ARCH_DMA_MINALIGN, size); - if (priv) + if (priv) { memset(priv, '\0', size); + + /* + * Ensure that the zero bytes are flushed to memory. + * This prevents problems if the driver uses this as + * both an input and an output buffer: + * + * 1. Zeroes written to buffer (here) and sit in the + * cache + * 2. Driver issues a read command to DMA + * 3. CPU runs out of cache space and evicts some cache + * data in the buffer, writing zeroes to RAM from + * the memset() above + * 4. DMA completes + * 5. Buffer now has some DMA data and some zeroes + * 6. Data being read is now incorrect + * + * To prevent this, ensure that the cache is clean + * within this range at the start. The driver can then + * use normal flush-after-write, invalidate-before-read + * procedures. + * + * TODO(sjg@chromium.org): Drop this microblaze + * exception. + */ +#ifndef CONFIG_MICROBLAZE + flush_dcache_range((ulong)priv, (ulong)priv + size); +#endif + } } else { priv = calloc(1, size); } diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index d94d43a98d..04fb45b01a 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -250,7 +250,7 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, return ret; list_for_each_entry(dev, &uc->dev_head, uclass_node) { - debug(" - %d %d\n", dev->req_seq, dev->seq); + debug(" - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name); if ((find_req_seq ? dev->req_seq : dev->seq) == seq_or_req_seq) { *devp = dev; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dc4108f378..c95e9acd5f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -28,6 +28,19 @@ config DWAPB_GPIO help Support for the Designware APB GPIO driver. +config AT91_GPIO + bool "AT91 PIO GPIO driver" + depends on DM_GPIO + default n + help + Say yes here to select AT91 PIO GPIO driver. AT91 PIO + controller manages up to 32 fully programmable input/output + lines. Each I/O line may be dedicated as a general-purpose + I/O or be assigned to a function of an embedded peripheral. + The assignment to a function of an embedded peripheral is + the responsibility of AT91 Pinctrl driver. This driver is + responsible for the general-purpose I/O. + config ATMEL_PIO4 bool "ATMEL PIO4 driver" depends on DM_GPIO diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c index 8e52e3dad0..98dbd8210e 100644 --- a/drivers/gpio/at91_gpio.c +++ b/drivers/gpio/at91_gpio.c @@ -10,6 +10,7 @@ #include <config.h> #include <common.h> +#include <clk.h> #include <dm.h> #include <asm/io.h> #include <linux/sizes.h> @@ -59,11 +60,6 @@ int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); -#if defined(CPU_HAS_PIO3) - if (use_pullup) - at91_set_pio_pulldown(port, pin, 0); -#endif - if (at91_port && (pin < GPIO_PER_BANK)) at91_set_port_pullup(at91_port, pin, use_pullup); @@ -100,14 +96,7 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup) mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); -#if defined(CPU_HAS_PIO3) - writel(readl(&at91_port->abcdsr1) & ~mask, - &at91_port->abcdsr1); - writel(readl(&at91_port->abcdsr2) & ~mask, - &at91_port->abcdsr2); -#else - writel(mask, &at91_port->asr); -#endif + writel(mask, &at91_port->mux.pio2.asr); writel(mask, &at91_port->pdr); } @@ -126,25 +115,62 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup) mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); -#if defined(CPU_HAS_PIO3) - writel(readl(&at91_port->abcdsr1) | mask, - &at91_port->abcdsr1); - writel(readl(&at91_port->abcdsr2) & ~mask, - &at91_port->abcdsr2); -#else - writel(mask, &at91_port->bsr); -#endif + writel(mask, &at91_port->mux.pio2.bsr); writel(mask, &at91_port->pdr); } return 0; } -#if defined(CPU_HAS_PIO3) +/* + * mux the pin to the "A" internal peripheral role. + */ +int at91_pio3_set_a_periph(unsigned port, unsigned pin, int use_pullup) +{ + struct at91_port *at91_port = at91_pio_get_port(port); + u32 mask; + + if (at91_port && (pin < GPIO_PER_BANK)) { + mask = 1 << pin; + writel(mask, &at91_port->idr); + at91_set_pio_pullup(port, pin, use_pullup); + writel(readl(&at91_port->mux.pio3.abcdsr1) & ~mask, + &at91_port->mux.pio3.abcdsr1); + writel(readl(&at91_port->mux.pio3.abcdsr2) & ~mask, + &at91_port->mux.pio3.abcdsr2); + + writel(mask, &at91_port->pdr); + } + + return 0; +} + +/* + * mux the pin to the "B" internal peripheral role. + */ +int at91_pio3_set_b_periph(unsigned port, unsigned pin, int use_pullup) +{ + struct at91_port *at91_port = at91_pio_get_port(port); + u32 mask; + + if (at91_port && (pin < GPIO_PER_BANK)) { + mask = 1 << pin; + writel(mask, &at91_port->idr); + at91_set_pio_pullup(port, pin, use_pullup); + writel(readl(&at91_port->mux.pio3.abcdsr1) | mask, + &at91_port->mux.pio3.abcdsr1); + writel(readl(&at91_port->mux.pio3.abcdsr2) & ~mask, + &at91_port->mux.pio3.abcdsr2); + + writel(mask, &at91_port->pdr); + } + + return 0; +} /* * mux the pin to the "C" internal peripheral role. */ -int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) +int at91_pio3_set_c_periph(unsigned port, unsigned pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; @@ -153,10 +179,10 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); - writel(readl(&at91_port->abcdsr1) & ~mask, - &at91_port->abcdsr1); - writel(readl(&at91_port->abcdsr2) | mask, - &at91_port->abcdsr2); + writel(readl(&at91_port->mux.pio3.abcdsr1) & ~mask, + &at91_port->mux.pio3.abcdsr1); + writel(readl(&at91_port->mux.pio3.abcdsr2) | mask, + &at91_port->mux.pio3.abcdsr2); writel(mask, &at91_port->pdr); } @@ -166,7 +192,7 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) /* * mux the pin to the "D" internal peripheral role. */ -int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) +int at91_pio3_set_d_periph(unsigned port, unsigned pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; @@ -175,16 +201,15 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); - writel(readl(&at91_port->abcdsr1) | mask, - &at91_port->abcdsr1); - writel(readl(&at91_port->abcdsr2) | mask, - &at91_port->abcdsr2); + writel(readl(&at91_port->mux.pio3.abcdsr1) | mask, + &at91_port->mux.pio3.abcdsr1); + writel(readl(&at91_port->mux.pio3.abcdsr2) | mask, + &at91_port->mux.pio3.abcdsr2); writel(mask, &at91_port->pdr); } return 0; } -#endif #ifdef CONFIG_DM_GPIO static bool at91_get_port_output(struct at91_port *at91_port, int offset) @@ -263,10 +288,27 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on) if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; + if (is_on) + writel(mask, &at91_port->ifer); + else + writel(mask, &at91_port->ifdr); + } + + return 0; +} + +/* + * enable/disable the glitch filter. mostly used with IRQ handling. + */ +int at91_pio3_set_pio_deglitch(unsigned port, unsigned pin, int is_on) +{ + struct at91_port *at91_port = at91_pio_get_port(port); + u32 mask; + + if (at91_port && (pin < GPIO_PER_BANK)) { + mask = 1 << pin; if (is_on) { -#if defined(CPU_HAS_PIO3) - writel(mask, &at91_port->ifscdr); -#endif + writel(mask, &at91_port->mux.pio3.ifscdr); writel(mask, &at91_port->ifer); } else { writel(mask, &at91_port->ifdr); @@ -276,11 +318,10 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on) return 0; } -#if defined(CPU_HAS_PIO3) /* * enable/disable the debounce filter. */ -int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) +int at91_pio3_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) { struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; @@ -288,8 +329,8 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { - writel(mask, &at91_port->ifscer); - writel(div & PIO_SCDR_DIV, &at91_port->scdr); + writel(mask, &at91_port->mux.pio3.ifscer); + writel(div & PIO_SCDR_DIV, &at91_port->mux.pio3.scdr); writel(mask, &at91_port->ifer); } else { writel(mask, &at91_port->ifdr); @@ -303,7 +344,7 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) * enable/disable the pull-down. * If pull-up already enabled while calling the function, we disable it. */ -int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on) +int at91_pio3_set_pio_pulldown(unsigned port, unsigned pin, int is_on) { struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; @@ -312,18 +353,31 @@ int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on) mask = 1 << pin; if (is_on) { at91_set_pio_pullup(port, pin, 0); - writel(mask, &at91_port->ppder); + writel(mask, &at91_port->mux.pio3.ppder); } else - writel(mask, &at91_port->ppddr); + writel(mask, &at91_port->mux.pio3.ppddr); } return 0; } +int at91_pio3_set_pio_pullup(unsigned port, unsigned pin, int use_pullup) +{ + struct at91_port *at91_port = at91_pio_get_port(port); + + if (use_pullup) + at91_pio3_set_pio_pulldown(port, pin, 0); + + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_pullup(at91_port, pin, use_pullup); + + return 0; +} + /* * disable Schmitt trigger */ -int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) +int at91_pio3_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) { struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; @@ -336,7 +390,6 @@ int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) return 0; } -#endif /* * enable/disable the multi-driver. This is only valid for output and @@ -517,17 +570,44 @@ static int at91_gpio_probe(struct udevice *dev) struct at91_port_priv *port = dev_get_priv(dev); struct at91_port_platdata *plat = dev_get_platdata(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct clk clk; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + clk_free(&clk); uc_priv->bank_name = plat->bank_name; uc_priv->gpio_count = GPIO_PER_BANK; + +#if CONFIG_IS_ENABLED(OF_CONTROL) + plat->base_addr = (uint32_t)dev_get_addr_ptr(dev); +#endif port->regs = (struct at91_port *)plat->base_addr; return 0; } +#if CONFIG_IS_ENABLED(OF_CONTROL) +static const struct udevice_id at91_gpio_ids[] = { + { .compatible = "atmel,at91rm9200-gpio" }, + { } +}; +#endif + U_BOOT_DRIVER(gpio_at91) = { .name = "gpio_at91", .id = UCLASS_GPIO, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .of_match = at91_gpio_ids, + .platdata_auto_alloc_size = sizeof(struct at91_port_platdata), +#endif .ops = &gpio_at91_ops, .probe = at91_gpio_probe, .priv_auto_alloc_size = sizeof(struct at91_port_priv), diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 8669432deb..21d5d0e70d 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1222,7 +1222,8 @@ static void at91_nand_hwcontrol(struct mtd_info *mtd, IO_ADDR_W |= CONFIG_SYS_NAND_MASK_ALE; #ifdef CONFIG_SYS_NAND_ENABLE_PIN - gpio_set_value(CONFIG_SYS_NAND_ENABLE_PIN, !(ctrl & NAND_NCE)); + at91_set_gpio_value(CONFIG_SYS_NAND_ENABLE_PIN, + !(ctrl & NAND_NCE)); #endif this->IO_ADDR_W = (void *) IO_ADDR_W; } @@ -1234,7 +1235,7 @@ static void at91_nand_hwcontrol(struct mtd_info *mtd, #ifdef CONFIG_SYS_NAND_READY_PIN static int at91_nand_ready(struct mtd_info *mtd) { - return gpio_get_value(CONFIG_SYS_NAND_READY_PIN); + return at91_get_gpio_value(CONFIG_SYS_NAND_READY_PIN); } #endif diff --git a/drivers/net/at91_emac.c b/drivers/net/at91_emac.c index be3d82e67e..eb8d2b31ec 100644 --- a/drivers/net/at91_emac.c +++ b/drivers/net/at91_emac.c @@ -333,7 +333,7 @@ static int at91emac_init(struct eth_device *netdev, bd_t *bd) ATMEL_PMX_AA_ETXEN | ATMEL_PMX_AA_EREFCK; writel(value, &pio->pioa.pdr); - writel(value, &pio->pioa.asr); + writel(value, &pio->pioa.mux.pio2.asr); #ifdef CONFIG_RMII value = ATMEL_PMX_BA_ERXCK; @@ -344,7 +344,7 @@ static int at91emac_init(struct eth_device *netdev, bd_t *bd) ATMEL_PMX_BA_ETX3 | ATMEL_PMX_BA_ETX2; #endif writel(value, &pio->piob.pdr); - writel(value, &pio->piob.bsr); + writel(value, &pio->piob.mux.pio2.bsr); at91_periph_clk_enable(ATMEL_ID_EMAC); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 9d0f5016ca..355aeae854 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -150,6 +150,20 @@ config ROCKCHIP_RK3288_PINCTRL definitions and pin control functions for each available multiplex function. +config PINCTRL_AT91 + bool "AT91 pinctrl driver" + depends on DM + help + This option is to enable the AT91 pinctrl driver for AT91 PIO + controller. AT91 PIO controller is a combined gpio-controller, + pin-mux and pin-config module. Each I/O pin may be dedicated as + a general-purpose I/O or be assigned to a function of an embedded + peripheral. Each I/O pin has a glitch filter providing rejection of + glitches lower than one-half of peripheral clock cycle and + a debouncing filter providing rejection of unwanted pulses from key + or push button operations. You can also control the multi-driver + capability, pull-up and pull-down feature on each I/O pin. + config PINCTRL_AT91PIO4 bool "AT91 PIO4 pinctrl driver" depends on DM diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 2ac9c19734..bbb2480e86 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -5,6 +5,7 @@ obj-y += pinctrl-uclass.o obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o +obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-y += nxp/ obj-$(CONFIG_ARCH_ATH79) += ath79/ diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c new file mode 100644 index 0000000000..904e1bdc68 --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91.c @@ -0,0 +1,453 @@ +/* + * Atmel PIO pinctrl driver + * + * Copyright (C) 2016 Atmel Corporation + * Wenyou.Yang <wenyou.yang@atmel.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm/device.h> +#include <dm/pinctrl.h> +#include <linux/io.h> +#include <linux/err.h> +#include <mach/at91_pio.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define MAX_GPIO_BANKS 5 +#define MAX_NB_GPIO_PER_BANK 32 + +#define MAX_PINMUX_ENTRIES 200 + +struct at91_pinctrl_priv { + struct at91_port *reg_base[MAX_GPIO_BANKS]; + u32 nbanks; +}; + +#define PULL_UP BIT(0) +#define MULTI_DRIVE BIT(1) +#define DEGLITCH BIT(2) +#define PULL_DOWN BIT(3) +#define DIS_SCHMIT BIT(4) +#define DRIVE_STRENGTH_SHIFT 5 +#define DRIVE_STRENGTH_MASK 0x3 +#define DRIVE_STRENGTH (DRIVE_STRENGTH_MASK << DRIVE_STRENGTH_SHIFT) +#define OUTPUT BIT(7) +#define OUTPUT_VAL_SHIFT 8 +#define OUTPUT_VAL (0x1 << OUTPUT_VAL_SHIFT) +#define DEBOUNCE BIT(16) +#define DEBOUNCE_VAL_SHIFT 17 +#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) + +/** + * These defines will translated the dt binding settings to our internal + * settings. They are not necessarily the same value as the register setting. + * The actual drive strength current of low, medium and high must be looked up + * from the corresponding device datasheet. This value is different for pins + * that are even in the same banks. It is also dependent on VCC. + * DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive + * strength when there is no dt config for it. + */ +#define DRIVE_STRENGTH_DEFAULT (0 << DRIVE_STRENGTH_SHIFT) +#define DRIVE_STRENGTH_LOW (1 << DRIVE_STRENGTH_SHIFT) +#define DRIVE_STRENGTH_MED (2 << DRIVE_STRENGTH_SHIFT) +#define DRIVE_STRENGTH_HI (3 << DRIVE_STRENGTH_SHIFT) + +enum at91_mux { + AT91_MUX_GPIO = 0, + AT91_MUX_PERIPH_A = 1, + AT91_MUX_PERIPH_B = 2, + AT91_MUX_PERIPH_C = 3, + AT91_MUX_PERIPH_D = 4, +}; + +/** + * struct at91_pinctrl_mux_ops - describes an AT91 mux ops group + * on new IP with support for periph C and D the way to mux in + * periph A and B has changed + * So provide the right callbacks + * if not present means the IP does not support it + * @mux_A_periph: assign the corresponding pin to the peripheral A function. + * @mux_B_periph: assign the corresponding pin to the peripheral B function. + * @mux_C_periph: assign the corresponding pin to the peripheral C function. + * @mux_D_periph: assign the corresponding pin to the peripheral D function. + * @set_deglitch: enable/disable the deglitch feature. + * @set_debounce: enable/disable the debounce feature. + * @set_pulldown: enable/disable the pulldown feature. + * @disable_schmitt_trig: disable schmitt trigger + */ +struct at91_pinctrl_mux_ops { + void (*mux_A_periph)(struct at91_port *pio, u32 mask); + void (*mux_B_periph)(struct at91_port *pio, u32 mask); + void (*mux_C_periph)(struct at91_port *pio, u32 mask); + void (*mux_D_periph)(struct at91_port *pio, u32 mask); + void (*set_deglitch)(struct at91_port *pio, u32 mask, bool is_on); + void (*set_debounce)(struct at91_port *pio, u32 mask, bool is_on, + u32 div); + void (*set_pulldown)(struct at91_port *pio, u32 mask, bool is_on); + void (*disable_schmitt_trig)(struct at91_port *pio, u32 mask); + void (*set_drivestrength)(struct at91_port *pio, u32 pin, + u32 strength); +}; + +static u32 two_bit_pin_value_shift_amount(u32 pin) +{ + /* return the shift value for a pin for "two bit" per pin registers, + * i.e. drive strength */ + return 2 * ((pin >= MAX_NB_GPIO_PER_BANK/2) + ? pin - MAX_NB_GPIO_PER_BANK/2 : pin); +} + +static void at91_mux_disable_interrupt(struct at91_port *pio, u32 mask) +{ + writel(mask, &pio->idr); +} + +static void at91_mux_set_pullup(struct at91_port *pio, u32 mask, bool on) +{ + if (on) + writel(mask, &pio->mux.pio3.ppddr); + + writel(mask, (on ? &pio->puer : &pio->pudr)); +} + +static void at91_mux_set_output(struct at91_port *pio, unsigned mask, + bool is_on, bool val) +{ + writel(mask, (val ? &pio->sodr : &pio->codr)); + writel(mask, (is_on ? &pio->oer : &pio->odr)); +} + +static void at91_mux_set_multidrive(struct at91_port *pio, u32 mask, bool on) +{ + writel(mask, (on ? &pio->mder : &pio->mddr)); +} + +static void at91_mux_set_A_periph(struct at91_port *pio, u32 mask) +{ + writel(mask, &pio->mux.pio2.asr); +} + +static void at91_mux_set_B_periph(struct at91_port *pio, u32 mask) +{ + writel(mask, &pio->mux.pio2.bsr); +} + +static void at91_mux_pio3_set_A_periph(struct at91_port *pio, u32 mask) +{ + writel(readl(&pio->mux.pio3.abcdsr1) & ~mask, &pio->mux.pio3.abcdsr1); + writel(readl(&pio->mux.pio3.abcdsr2) & ~mask, &pio->mux.pio3.abcdsr2); +} + +static void at91_mux_pio3_set_B_periph(struct at91_port *pio, u32 mask) +{ + writel(readl(&pio->mux.pio3.abcdsr1) | mask, &pio->mux.pio3.abcdsr1); + writel(readl(&pio->mux.pio3.abcdsr2) & ~mask, &pio->mux.pio3.abcdsr2); +} + +static void at91_mux_pio3_set_C_periph(struct at91_port *pio, u32 mask) +{ + writel(readl(&pio->mux.pio3.abcdsr1) & ~mask, &pio->mux.pio3.abcdsr1); + writel(readl(&pio->mux.pio3.abcdsr2) | mask, &pio->mux.pio3.abcdsr2); +} + +static void at91_mux_pio3_set_D_periph(struct at91_port *pio, u32 mask) +{ + writel(readl(&pio->mux.pio3.abcdsr1) | mask, &pio->mux.pio3.abcdsr1); + writel(readl(&pio->mux.pio3.abcdsr2) | mask, &pio->mux.pio3.abcdsr2); +} + +static void at91_mux_set_deglitch(struct at91_port *pio, u32 mask, bool is_on) +{ + writel(mask, (is_on ? &pio->ifer : &pio->ifdr)); +} + +static void at91_mux_pio3_set_deglitch(struct at91_port *pio, + u32 mask, bool is_on) +{ + if (is_on) + writel(mask, &pio->mux.pio3.ifscdr); + at91_mux_set_deglitch(pio, mask, is_on); +} + +static void at91_mux_pio3_set_debounce(struct at91_port *pio, u32 mask, + bool is_on, u32 div) +{ + if (is_on) { + writel(mask, &pio->mux.pio3.ifscer); + writel(div & PIO_SCDR_DIV, &pio->mux.pio3.scdr); + writel(mask, &pio->ifer); + } else { + writel(mask, &pio->mux.pio3.ifscdr); + } +} + +static void at91_mux_pio3_set_pulldown(struct at91_port *pio, + u32 mask, bool is_on) +{ + if (is_on) + writel(mask, &pio->pudr); + + writel(mask, (is_on ? &pio->mux.pio3.ppder : &pio->mux.pio3.ppddr)); +} + +static void at91_mux_pio3_disable_schmitt_trig(struct at91_port *pio, + u32 mask) +{ + writel(readl(&pio->schmitt) | mask, &pio->schmitt); +} + +static void set_drive_strength(void *reg, u32 pin, u32 strength) +{ + u32 shift = two_bit_pin_value_shift_amount(pin); + + clrsetbits_le32(reg, DRIVE_STRENGTH_MASK << shift, strength << shift); +} + +static void at91_mux_sama5d3_set_drivestrength(struct at91_port *pio, + u32 pin, u32 setting) +{ + void *reg; + + reg = &pio->driver12; + if (pin >= MAX_NB_GPIO_PER_BANK / 2) + reg = &pio->driver2; + + /* do nothing if setting is zero */ + if (!setting) + return; + + /* strength is 1 to 1 with setting for SAMA5 */ + set_drive_strength(reg, pin, setting); +} + +static void at91_mux_sam9x5_set_drivestrength(struct at91_port *pio, + u32 pin, u32 setting) +{ + void *reg; + + reg = &pio->driver1; + if (pin >= MAX_NB_GPIO_PER_BANK / 2) + reg = &pio->driver12; + + /* do nothing if setting is zero */ + if (!setting) + return; + + /* strength is inverse on SAM9x5s with our defines + * 0 = hi, 1 = med, 2 = low, 3 = rsvd */ + setting = DRIVE_STRENGTH_HI - setting; + + set_drive_strength(reg, pin, setting); +} + +static struct at91_pinctrl_mux_ops at91rm9200_ops = { + .mux_A_periph = at91_mux_set_A_periph, + .mux_B_periph = at91_mux_set_B_periph, + .set_deglitch = at91_mux_set_deglitch, +}; + +static struct at91_pinctrl_mux_ops at91sam9x5_ops = { + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .set_deglitch = at91_mux_pio3_set_deglitch, + .set_debounce = at91_mux_pio3_set_debounce, + .set_pulldown = at91_mux_pio3_set_pulldown, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .set_drivestrength = at91_mux_sam9x5_set_drivestrength, +}; + +static struct at91_pinctrl_mux_ops sama5d3_ops = { + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .set_deglitch = at91_mux_pio3_set_deglitch, + .set_debounce = at91_mux_pio3_set_debounce, + .set_pulldown = at91_mux_pio3_set_pulldown, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .set_drivestrength = at91_mux_sama5d3_set_drivestrength, +}; + +static void at91_mux_gpio_disable(struct at91_port *pio, u32 mask) +{ + writel(mask, &pio->pdr); +} + +static void at91_mux_gpio_enable(struct at91_port *pio, u32 mask, bool input) +{ + writel(mask, &pio->per); + writel(mask, (input ? &pio->odr : &pio->oer)); +} + +static int at91_pmx_set(struct at91_pinctrl_mux_ops *ops, + struct at91_port *pio, u32 mask, enum at91_mux mux) +{ + at91_mux_disable_interrupt(pio, mask); + switch (mux) { + case AT91_MUX_GPIO: + at91_mux_gpio_enable(pio, mask, 1); + break; + case AT91_MUX_PERIPH_A: + ops->mux_A_periph(pio, mask); + break; + case AT91_MUX_PERIPH_B: + ops->mux_B_periph(pio, mask); + break; + case AT91_MUX_PERIPH_C: + if (!ops->mux_C_periph) + return -EINVAL; + ops->mux_C_periph(pio, mask); + break; + case AT91_MUX_PERIPH_D: + if (!ops->mux_D_periph) + return -EINVAL; + ops->mux_D_periph(pio, mask); + break; + } + if (mux) + at91_mux_gpio_disable(pio, mask); + + return 0; +} + +static int at91_pinconf_set(struct at91_pinctrl_mux_ops *ops, + struct at91_port *pio, u32 pin, u32 config) +{ + u32 mask = BIT(pin); + + if ((config & PULL_UP) && (config & PULL_DOWN)) + return -EINVAL; + + at91_mux_set_output(pio, mask, config & OUTPUT, + (config & OUTPUT_VAL) >> OUTPUT_VAL_SHIFT); + at91_mux_set_pullup(pio, mask, config & PULL_UP); + at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); + if (ops->set_deglitch) + ops->set_deglitch(pio, mask, config & DEGLITCH); + if (ops->set_debounce) + ops->set_debounce(pio, mask, config & DEBOUNCE, + (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); + if (ops->set_pulldown) + ops->set_pulldown(pio, mask, config & PULL_DOWN); + if (ops->disable_schmitt_trig && config & DIS_SCHMIT) + ops->disable_schmitt_trig(pio, mask); + if (ops->set_drivestrength) + ops->set_drivestrength(pio, pin, + (config & DRIVE_STRENGTH) >> DRIVE_STRENGTH_SHIFT); + + return 0; +} + +static int at91_pin_check_config(struct udevice *dev, u32 bank, u32 pin) +{ + struct at91_pinctrl_priv *priv = dev_get_priv(dev); + + if (bank >= priv->nbanks) { + debug("pin conf bank %d >= nbanks %d\n", bank, priv->nbanks); + return -EINVAL; + } + + if (pin >= MAX_NB_GPIO_PER_BANK) { + debug("pin conf pin %d >= %d\n", pin, MAX_NB_GPIO_PER_BANK); + return -EINVAL; + } + + return 0; +} + +static int at91_pinctrl_set_state(struct udevice *dev, struct udevice *config) +{ + struct at91_pinctrl_priv *priv = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int node = config->of_offset; + u32 cells[MAX_PINMUX_ENTRIES]; + const u32 *list = cells; + u32 bank, pin; + u32 conf, mask, count, i; + int size; + int ret; + enum at91_mux mux; + struct at91_port *pio; + struct at91_pinctrl_mux_ops *ops = + (struct at91_pinctrl_mux_ops *)dev_get_driver_data(dev); + + /* + * the binding format is atmel,pins = <bank pin mux CONFIG ...>, + * do sanity check and calculate pins number + */ + size = fdtdec_get_int_array_count(blob, node, "atmel,pins", + cells, ARRAY_SIZE(cells)); + + /* we do not check return since it's safe node passed down */ + count = size >> 2; + if (!count) + return -EINVAL; + + for (i = 0; i < count; i++) { + bank = *list++; + pin = *list++; + mux = *list++; + conf = *list++; + + ret = at91_pin_check_config(dev, bank, pin); + if (ret) + return ret; + + pio = priv->reg_base[bank]; + mask = BIT(pin); + + ret = at91_pmx_set(ops, pio, mask, mux); + if (ret) + return ret; + + ret = at91_pinconf_set(ops, pio, pin, conf); + if (ret) + return ret; + } + + return 0; +} + +const struct pinctrl_ops at91_pinctrl_ops = { + .set_state = at91_pinctrl_set_state, +}; + +static int at91_pinctrl_probe(struct udevice *dev) +{ + struct at91_pinctrl_priv *priv = dev_get_priv(dev); + fdt_addr_t addr_base; + int index; + + for (index = 0; index < MAX_GPIO_BANKS; index++) { + addr_base = dev_get_addr_index(dev, index); + if (addr_base == FDT_ADDR_T_NONE) + break; + + priv->reg_base[index] = (struct at91_port *)addr_base; + } + + priv->nbanks = index; + + return 0; +} + +static const struct udevice_id at91_pinctrl_match[] = { + { .compatible = "atmel,sama5d3-pinctrl", .data = (ulong)&sama5d3_ops }, + { .compatible = "atmel,at91sam9x5-pinctrl", .data = (ulong)&at91sam9x5_ops }, + { .compatible = "atmel,at91rm9200-pinctrl", .data = (ulong)&at91rm9200_ops }, + {} +}; + +U_BOOT_DRIVER(at91_pinctrl) = { + .name = "pinctrl_at91", + .id = UCLASS_PINCTRL, + .of_match = at91_pinctrl_match, + .probe = at91_pinctrl_probe, + .priv_auto_alloc_size = sizeof(struct at91_pinctrl_priv), + .ops = &at91_pinctrl_ops, +}; diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 1f819d487b..4f86780cb1 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -452,8 +452,7 @@ const struct dm_serial_ops ns16550_serial_ops = { .setbrg = ns16550_serial_setbrg, }; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) -#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /* * Please consider existing compatible strings before adding a new * one to keep this table compact. Or you may add a generic "ns16550" @@ -473,13 +472,16 @@ static const struct udevice_id ns16550_serial_ids[] = { { .compatible = "ti,dra742-uart", .data = PORT_NS16550 }, {} }; -#endif +#endif /* OF_CONTROL && !OF_PLATDATA */ #if CONFIG_IS_ENABLED(SERIAL_PRESENT) + +/* TODO(sjg@chromium.org): Integrate this into a macro like CONFIG_IS_ENABLED */ +#if !defined(CONFIG_TPL_BUILD) || defined(CONFIG_TPL_DM_SERIAL) U_BOOT_DRIVER(ns16550_serial) = { .name = "ns16550_serial", .id = UCLASS_SERIAL, -#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) .of_match = ns16550_serial_ids, .ofdata_to_platdata = ns16550_serial_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), @@ -490,5 +492,6 @@ U_BOOT_DRIVER(ns16550_serial) = { .flags = DM_FLAG_PRE_RELOC, }; #endif -#endif /* !OF_PLATDATA */ +#endif /* SERIAL_PRESENT */ + #endif /* CONFIG_DM_SERIAL */ |