diff options
author | Tom Rini <trini@konsulko.com> | 2020-07-11 11:50:49 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-07-11 11:50:49 -0400 |
commit | 610e1487c8921d266f5cb304bfb66eb71f1dc7dc (patch) | |
tree | 68991565dbed957030795ef3229020e1207709d3 /drivers | |
parent | 4a9146c29573dbfa661918280d9522a01f6ca919 (diff) | |
parent | 5785950369cd68d4409bf4d0e34d4b1894e5d0e9 (diff) |
Merge tag 'uniphier-v2020.10' of https://gitlab.denx.de/u-boot/custodians/u-boot-uniphier
UniPhier SoC updates for v2020.10
- remove workaround for Cortex-A72
- increase U-Boot proper size to 2MB
- sync DT with Linux
- add system bus controller driver
- improve serial driver
- add reset assertion to Denali NAND driver
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/bus/Kconfig | 16 | ||||
-rw-r--r-- | drivers/bus/Makefile | 6 | ||||
-rw-r--r-- | drivers/bus/uniphier-system-bus.c | 100 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/denali.c | 11 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/denali.h | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/denali_dt.c | 8 | ||||
-rw-r--r-- | drivers/serial/serial_uniphier.c | 90 |
9 files changed, 191 insertions, 44 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index e34a22708c..7a839fa1aa 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -10,6 +10,8 @@ source "drivers/ata/Kconfig" source "drivers/axi/Kconfig" +source "drivers/bus/Kconfig" + source "drivers/block/Kconfig" source "drivers/bootcount/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 94e8c5da17..afd159e903 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -74,6 +74,7 @@ ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) obj-y += adc/ obj-y += ata/ +obj-y += bus/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig new file mode 100644 index 0000000000..07a33c6287 --- /dev/null +++ b/drivers/bus/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Bus Devices +# + +menu "Bus devices" + +config UNIPHIER_SYSTEM_BUS + bool "UniPhier System Bus driver" + depends on ARCH_UNIPHIER + default y + help + Support for UniPhier System Bus, a simple external bus. This is + needed to use on-board devices connected to UniPhier SoCs. + +endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile new file mode 100644 index 0000000000..0b97fc1f8b --- /dev/null +++ b/drivers/bus/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the bus drivers. +# + +obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o diff --git a/drivers/bus/uniphier-system-bus.c b/drivers/bus/uniphier-system-bus.c new file mode 100644 index 0000000000..ea08d66a07 --- /dev/null +++ b/drivers/bus/uniphier-system-bus.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/sizes.h> +#include <linux/types.h> +#include <dm.h> + +/* System Bus Controller registers */ +#define UNIPHIER_SBC_BASE 0x100 /* base address of bank0 space */ +#define UNIPHIER_SBC_BASE_BE BIT(0) /* bank_enable */ +#define UNIPHIER_SBC_CTRL0 0x200 /* timing parameter 0 of bank0 */ +#define UNIPHIER_SBC_CTRL1 0x204 /* timing parameter 1 of bank0 */ +#define UNIPHIER_SBC_CTRL2 0x208 /* timing parameter 2 of bank0 */ +#define UNIPHIER_SBC_CTRL3 0x20c /* timing parameter 3 of bank0 */ +#define UNIPHIER_SBC_CTRL4 0x300 /* timing parameter 4 of bank0 */ + +#define UNIPHIER_SBC_STRIDE 0x10 /* register stride to next bank */ + +#if 1 +/* slower but LED works */ +#define SBCTRL0_VALUE 0x55450000 +#define SBCTRL1_VALUE 0x07168d00 +#define SBCTRL2_VALUE 0x34000009 +#define SBCTRL4_VALUE 0x02110110 + +#else +/* faster but LED does not work */ +#define SBCTRL0_VALUE 0x55450000 +#define SBCTRL1_VALUE 0x06057700 +/* NOR flash needs more wait counts than SRAM */ +#define SBCTRL2_VALUE 0x34000009 +#define SBCTRL4_VALUE 0x02110210 +#endif + +void uniphier_system_bus_set_reg(void __iomem *membase) +{ + void __iomem *bank0_base = membase; + void __iomem *bank1_base = membase + UNIPHIER_SBC_STRIDE; + + /* + * Only CS1 is connected to support card. + * BKSZ[1:0] should be set to "01". + */ + writel(SBCTRL0_VALUE, bank1_base + UNIPHIER_SBC_CTRL0); + writel(SBCTRL1_VALUE, bank1_base + UNIPHIER_SBC_CTRL1); + writel(SBCTRL2_VALUE, bank1_base + UNIPHIER_SBC_CTRL2); + writel(SBCTRL4_VALUE, bank1_base + UNIPHIER_SBC_CTRL4); + + if (readl(bank1_base + UNIPHIER_SBC_BASE) & UNIPHIER_SBC_BASE_BE) { + /* + * Boot Swap On: boot from external NOR/SRAM + * 0x42000000-0x43ffffff is a mirror of 0x40000000-0x41ffffff. + * + * 0x40000000-0x41efffff, 0x42000000-0x43efffff: memory bank + * 0x41f00000-0x41ffffff, 0x43f00000-0x43ffffff: peripherals + */ + writel(0x0000bc01, bank0_base + UNIPHIER_SBC_BASE); + } else { + /* + * Boot Swap Off: boot from mask ROM + * 0x40000000-0x41ffffff: mask ROM + * 0x42000000-0x43efffff: memory bank (31MB) + * 0x43f00000-0x43ffffff: peripherals (1MB) + */ + writel(0x0000be01, bank0_base + UNIPHIER_SBC_BASE); /* dummy */ + writel(0x0200be01, bank0_base + UNIPHIER_SBC_BASE); + } +} + +static int uniphier_system_bus_probe(struct udevice *dev) +{ + fdt_addr_t base; + void __iomem *membase; + + base = dev_read_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + membase = devm_ioremap(dev, base, SZ_1K); + if (!membase) + return -ENOMEM; + + uniphier_system_bus_set_reg(membase); + + return 0; +} + +static const struct udevice_id uniphier_system_bus_match[] = { + { .compatible = "socionext,uniphier-system-bus" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(uniphier_system_bus_driver) = { + .name = "uniphier-system-bus", + .id = UCLASS_SIMPLE_BUS, + .of_match = uniphier_system_bus_match, + .probe = uniphier_system_bus_probe, +}; diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 15e90291de..ab91db8546 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1220,6 +1220,17 @@ static int denali_multidev_fixup(struct denali_nand_info *denali) return 0; } +int denali_wait_reset_complete(struct denali_nand_info *denali) +{ + u32 irq_status; + + irq_status = denali_wait_for_irq(denali, INTR__RST_COMP); + if (!(irq_status & INTR__RST_COMP)) + return -EIO; + + return 0; +} + int denali_init(struct denali_nand_info *denali) { struct nand_chip *chip = &denali->nand; diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index 019deda094..6cd02b2e26 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -321,6 +321,7 @@ struct denali_nand_info { #define DENALI_CAP_DMA_64BIT BIT(1) int denali_calc_ecc_bytes(int step_size, int strength); +int denali_wait_reset_complete(struct denali_nand_info *denali); int denali_init(struct denali_nand_info *denali); #endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 2728e8098f..8318ff507f 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -148,6 +148,8 @@ static int denali_dt_probe(struct udevice *dev) if (ret) { dev_warn(dev, "Can't get reset: %d\n", ret); } else { + reset_assert_bulk(&resets); + udelay(2); reset_deassert_bulk(&resets); /* @@ -155,7 +157,11 @@ static int denali_dt_probe(struct udevice *dev) * kicked (bootstrap process). The driver must wait until it is * finished. Otherwise, it will result in unpredictable behavior. */ - udelay(200); + ret = denali_wait_reset_complete(denali); + if (ret) { + dev_err(denali->dev, "reset not completed.\n"); + return ret; + } } return denali_init(denali); diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index c7f46e5598..ad691b66da 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -7,6 +7,8 @@ #include <common.h> #include <dm.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> #include <linux/bug.h> #include <linux/io.h> #include <linux/serial_reg.h> @@ -15,77 +17,72 @@ #include <serial.h> #include <fdtdec.h> -/* - * Note: Register map is slightly different from that of 16550. - */ -struct uniphier_serial { - u32 rx; /* In: Receive buffer */ -#define tx rx /* Out: Transmit buffer */ - u32 ier; /* Interrupt Enable Register */ - u32 iir; /* In: Interrupt ID Register */ - u32 char_fcr; /* Charactor / FIFO Control Register */ - u32 lcr_mcr; /* Line/Modem Control Register */ -#define LCR_SHIFT 8 -#define LCR_MASK (0xff << (LCR_SHIFT)) - u32 lsr; /* In: Line Status Register */ - u32 msr; /* In: Modem Status Register */ - u32 __rsv0; - u32 __rsv1; - u32 dlr; /* Divisor Latch Register */ -}; +#define UNIPHIER_UART_REGSHIFT 2 + +#define UNIPHIER_UART_RX (0 << (UNIPHIER_UART_REGSHIFT)) +#define UNIPHIER_UART_TX UNIPHIER_UART_RX +/* bit[15:8] = CHAR, bit[7:0] = FCR */ +#define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT)) +#define UNIPHIER_UART_FCR_MASK GENMASK(7, 0) +/* bit[15:8] = LCR, bit[7:0] = MCR */ +#define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT)) +#define UNIPHIER_UART_LCR_MASK GENMASK(15, 8) +#define UNIPHIER_UART_LSR (5 << (UNIPHIER_UART_REGSHIFT)) +/* Divisor Latch Register */ +#define UNIPHIER_UART_DLR (9 << (UNIPHIER_UART_REGSHIFT)) struct uniphier_serial_priv { - struct uniphier_serial __iomem *membase; + void __iomem *membase; unsigned int uartclk; }; -#define uniphier_serial_port(dev) \ - ((struct uniphier_serial_priv *)dev_get_priv(dev))->membase - static int uniphier_serial_setbrg(struct udevice *dev, int baudrate) { struct uniphier_serial_priv *priv = dev_get_priv(dev); - struct uniphier_serial __iomem *port = uniphier_serial_port(dev); - const unsigned int mode_x_div = 16; + static const unsigned int mode_x_div = 16; unsigned int divisor; divisor = DIV_ROUND_CLOSEST(priv->uartclk, mode_x_div * baudrate); - writel(divisor, &port->dlr); + /* flush the trasmitter before changing hw setting */ + while (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_TEMT)) + ; + + writel(divisor, priv->membase + UNIPHIER_UART_DLR); return 0; } static int uniphier_serial_getc(struct udevice *dev) { - struct uniphier_serial __iomem *port = uniphier_serial_port(dev); + struct uniphier_serial_priv *priv = dev_get_priv(dev); - if (!(readl(&port->lsr) & UART_LSR_DR)) + if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR)) return -EAGAIN; - return readl(&port->rx); + return readl(priv->membase + UNIPHIER_UART_RX); } static int uniphier_serial_putc(struct udevice *dev, const char c) { - struct uniphier_serial __iomem *port = uniphier_serial_port(dev); + struct uniphier_serial_priv *priv = dev_get_priv(dev); - if (!(readl(&port->lsr) & UART_LSR_THRE)) + if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE)) return -EAGAIN; - writel(c, &port->tx); + writel(c, priv->membase + UNIPHIER_UART_TX); return 0; } static int uniphier_serial_pending(struct udevice *dev, bool input) { - struct uniphier_serial __iomem *port = uniphier_serial_port(dev); + struct uniphier_serial_priv *priv = dev_get_priv(dev); if (input) - return readl(&port->lsr) & UART_LSR_DR; + return readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR; else - return !(readl(&port->lsr) & UART_LSR_THRE); + return !(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE); } /* @@ -113,7 +110,6 @@ static const struct uniphier_serial_clk_data uniphier_serial_clk_data[] = { static int uniphier_serial_probe(struct udevice *dev) { struct uniphier_serial_priv *priv = dev_get_priv(dev); - struct uniphier_serial __iomem *port; const struct uniphier_serial_clk_data *clk_data; ofnode root_node; fdt_addr_t base; @@ -123,12 +119,10 @@ static int uniphier_serial_probe(struct udevice *dev) if (base == FDT_ADDR_T_NONE) return -EINVAL; - port = devm_ioremap(dev, base, SZ_64); - if (!port) + priv->membase = devm_ioremap(dev, base, SZ_64); + if (!priv->membase) return -ENOMEM; - priv->membase = port; - root_node = ofnode_path("/"); clk_data = uniphier_serial_clk_data; while (clk_data->compatible) { @@ -143,10 +137,20 @@ static int uniphier_serial_probe(struct udevice *dev) priv->uartclk = clk_data->clk_rate; - tmp = readl(&port->lcr_mcr); - tmp &= ~LCR_MASK; - tmp |= UART_LCR_WLEN8 << LCR_SHIFT; - writel(tmp, &port->lcr_mcr); + /* flush the trasmitter empty before changing hw setting */ + while (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_TEMT)) + ; + + /* enable FIFO */ + tmp = readl(priv->membase + UNIPHIER_UART_CHAR_FCR); + tmp &= ~UNIPHIER_UART_FCR_MASK; + tmp |= FIELD_PREP(UNIPHIER_UART_FCR_MASK, UART_FCR_ENABLE_FIFO); + writel(tmp, priv->membase + UNIPHIER_UART_CHAR_FCR); + + tmp = readl(priv->membase + UNIPHIER_UART_LCR_MCR); + tmp &= ~UNIPHIER_UART_LCR_MASK; + tmp |= FIELD_PREP(UNIPHIER_UART_LCR_MASK, UART_LCR_WLEN8); + writel(tmp, priv->membase + UNIPHIER_UART_LCR_MCR); return 0; } |