summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-07-11 11:50:49 -0400
committerTom Rini <trini@konsulko.com>2020-07-11 11:50:49 -0400
commit610e1487c8921d266f5cb304bfb66eb71f1dc7dc (patch)
tree68991565dbed957030795ef3229020e1207709d3 /drivers
parent4a9146c29573dbfa661918280d9522a01f6ca919 (diff)
parent5785950369cd68d4409bf4d0e34d4b1894e5d0e9 (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/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/bus/Kconfig16
-rw-r--r--drivers/bus/Makefile6
-rw-r--r--drivers/bus/uniphier-system-bus.c100
-rw-r--r--drivers/mtd/nand/raw/denali.c11
-rw-r--r--drivers/mtd/nand/raw/denali.h1
-rw-r--r--drivers/mtd/nand/raw/denali_dt.c8
-rw-r--r--drivers/serial/serial_uniphier.c90
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;
}