summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2018-12-21 13:36:08 -0500
committerTom Rini <trini@konsulko.com>2018-12-21 13:36:08 -0500
commit328e3f8a706931e1a8f76adfdc015ad76cbeb83c (patch)
treeb88b5eb9c3135640bc44262229cc70f4a0e6acdc /drivers
parent1f2e948d6d53f77a2ddb2dde3531b0d5bc2815ad (diff)
parent368ff57805b03bebf99e97e703ce07aec721bc71 (diff)
Merge git://git.denx.de/u-boot-riscv
- Add DM drivers to support RISC-V CPU and timer, plus some bug fixes. - Support SiFive UART - Rename ax25-ae350 defconfig
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpu/Kconfig6
-rw-r--r--drivers/cpu/Makefile1
-rw-r--r--drivers/cpu/riscv_cpu.c116
-rw-r--r--drivers/serial/Kconfig13
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_sifive.c215
-rw-r--r--drivers/timer/Kconfig7
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/riscv_timer.c56
9 files changed, 416 insertions, 0 deletions
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
index d4052005e2..3d5729f6dc 100644
--- a/drivers/cpu/Kconfig
+++ b/drivers/cpu/Kconfig
@@ -13,3 +13,9 @@ config CPU_MPC83XX
select CLK_MPC83XX
help
Support CPU cores for SoCs of the MPC83xx series.
+
+config CPU_RISCV
+ bool "Enable RISC-V CPU driver"
+ depends on CPU && RISCV
+ help
+ Support CPU cores for RISC-V architecture.
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index 858b03755f..be0300cd4a 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_CPU) += cpu-uclass.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
+obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
obj-$(CONFIG_SANDBOX) += cpu_sandbox.o
diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c
new file mode 100644
index 0000000000..5e15df590e
--- /dev/null
+++ b/drivers/cpu/riscv_cpu.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+ const char *isa;
+
+ isa = dev_read_string(dev, "riscv,isa");
+ if (size < (strlen(isa) + 1))
+ return -ENOSPC;
+
+ strcpy(buf, isa);
+
+ return 0;
+}
+
+static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info)
+{
+ const char *mmu;
+
+ dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq);
+
+ mmu = dev_read_string(dev, "mmu-type");
+ if (!mmu)
+ info->features |= BIT(CPU_FEAT_MMU);
+
+ return 0;
+}
+
+static int riscv_cpu_get_count(struct udevice *dev)
+{
+ ofnode node;
+ int num = 0;
+
+ ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
+ const char *device_type;
+
+ device_type = ofnode_read_string(node, "device_type");
+ if (!device_type)
+ continue;
+ if (strcmp(device_type, "cpu") == 0)
+ num++;
+ }
+
+ return num;
+}
+
+static int riscv_cpu_bind(struct udevice *dev)
+{
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+ struct driver *drv;
+ int ret;
+
+ /* save the hart id */
+ plat->cpu_id = dev_read_addr(dev);
+
+ /* first examine the property in current cpu node */
+ ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
+ /* if not found, then look at the parent /cpus node */
+ if (ret)
+ dev_read_u32(dev->parent, "timebase-frequency",
+ &plat->timebase_freq);
+
+ /*
+ * Bind riscv-timer driver on hart 0
+ *
+ * We only instantiate one timer device which is enough for U-Boot.
+ * Pass the "timebase-frequency" value as the driver data for the
+ * timer device.
+ *
+ * Return value is not checked since it's possible that the timer
+ * driver is not included.
+ */
+ if (!plat->cpu_id && plat->timebase_freq) {
+ drv = lists_driver_lookup_name("riscv_timer");
+ if (!drv) {
+ debug("Cannot find the timer driver, not included?\n");
+ return 0;
+ }
+
+ device_bind_with_driver_data(dev, drv, "riscv_timer",
+ plat->timebase_freq, ofnode_null(),
+ NULL);
+ }
+
+ return 0;
+}
+
+static const struct cpu_ops riscv_cpu_ops = {
+ .get_desc = riscv_cpu_get_desc,
+ .get_info = riscv_cpu_get_info,
+ .get_count = riscv_cpu_get_count,
+};
+
+static const struct udevice_id riscv_cpu_ids[] = {
+ { .compatible = "riscv" },
+ { }
+};
+
+U_BOOT_DRIVER(riscv_cpu) = {
+ .name = "riscv_cpu",
+ .id = UCLASS_CPU,
+ .of_match = riscv_cpu_ids,
+ .bind = riscv_cpu_bind,
+ .ops = &riscv_cpu_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6252dd8c4b..b7ff2960ab 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -343,6 +343,13 @@ config DEBUG_UART_SANDBOX
start up driver model. The driver will be available until the real
driver model serial is running.
+config DEBUG_UART_SIFIVE
+ bool "SiFive UART"
+ help
+ Select this to enable a debug UART using the serial_sifive driver. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver-model serial is running.
+
config DEBUG_UART_STM32
bool "STMicroelectronics STM32"
depends on STM32_SERIAL
@@ -679,6 +686,12 @@ config PXA_SERIAL
If you have a machine based on a Marvell XScale PXA2xx CPU you
can enable its onboard serial ports by enabling this option.
+config SIFIVE_SERIAL
+ bool "SiFive UART support"
+ depends on DM_SERIAL
+ help
+ This driver supports the SiFive UART. If unsure say N.
+
config STI_ASC_SERIAL
bool "STMicroelectronics on-chip UART"
depends on DM_SERIAL && ARCH_STI
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 2f8d065a4c..06ee30697d 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o
+obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c
new file mode 100644
index 0000000000..341728a690
--- /dev/null
+++ b/drivers/serial/serial_sifive.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <linux/compiler.h>
+#include <serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define UART_TXFIFO_FULL 0x80000000
+#define UART_RXFIFO_EMPTY 0x80000000
+#define UART_RXFIFO_DATA 0x000000ff
+#define UART_TXCTRL_TXEN 0x1
+#define UART_RXCTRL_RXEN 0x1
+
+struct uart_sifive {
+ u32 txfifo;
+ u32 rxfifo;
+ u32 txctrl;
+ u32 rxctrl;
+ u32 ie;
+ u32 ip;
+ u32 div;
+};
+
+struct sifive_uart_platdata {
+ unsigned int clock;
+ int saved_input_char;
+ struct uart_sifive *regs;
+};
+
+/* Set up the baud rate in gd struct */
+static void _sifive_serial_setbrg(struct uart_sifive *regs,
+ unsigned long clock, unsigned long baud)
+{
+ writel((u32)((clock / baud) - 1), &regs->div);
+}
+
+static void _sifive_serial_init(struct uart_sifive *regs)
+{
+ writel(UART_TXCTRL_TXEN, &regs->txctrl);
+ writel(UART_RXCTRL_RXEN, &regs->rxctrl);
+ writel(0, &regs->ie);
+}
+
+static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
+{
+ if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
+ return -EAGAIN;
+
+ writel(c, &regs->txfifo);
+
+ return 0;
+}
+
+static int _sifive_serial_getc(struct uart_sifive *regs)
+{
+ int ch = readl(&regs->rxfifo);
+
+ if (ch & UART_RXFIFO_EMPTY)
+ return -EAGAIN;
+ ch &= UART_RXFIFO_DATA;
+
+ return (!ch) ? -EAGAIN : ch;
+}
+
+static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ int err;
+ struct clk clk;
+ struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+ err = clk_get_by_index(dev, 0, &clk);
+ if (!err) {
+ err = clk_get_rate(&clk);
+ if (!IS_ERR_VALUE(err))
+ platdata->clock = err;
+ } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
+ debug("SiFive UART failed to get clock\n");
+ return err;
+ }
+
+ if (!platdata->clock)
+ platdata->clock = dev_read_u32_default(dev, "clock-frequency", 0);
+ if (!platdata->clock) {
+ debug("SiFive UART clock not defined\n");
+ return -EINVAL;
+ }
+
+ _sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
+
+ return 0;
+}
+
+static int sifive_serial_probe(struct udevice *dev)
+{
+ struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+ /* No need to reinitialize the UART after relocation */
+ if (gd->flags & GD_FLG_RELOC)
+ return 0;
+
+ platdata->saved_input_char = 0;
+ _sifive_serial_init(platdata->regs);
+
+ return 0;
+}
+
+static int sifive_serial_getc(struct udevice *dev)
+{
+ int c;
+ struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+ struct uart_sifive *regs = platdata->regs;
+
+ if (platdata->saved_input_char > 0) {
+ c = platdata->saved_input_char;
+ platdata->saved_input_char = 0;
+ return c;
+ }
+
+ while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
+
+ return c;
+}
+
+static int sifive_serial_putc(struct udevice *dev, const char ch)
+{
+ int rc;
+ struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+ while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
+
+ return rc;
+}
+
+static int sifive_serial_pending(struct udevice *dev, bool input)
+{
+ struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+ struct uart_sifive *regs = platdata->regs;
+
+ if (input) {
+ if (platdata->saved_input_char > 0)
+ return 1;
+ platdata->saved_input_char = _sifive_serial_getc(regs);
+ return (platdata->saved_input_char > 0) ? 1 : 0;
+ } else {
+ return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
+ }
+}
+
+static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+ platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
+ if (IS_ERR(platdata->regs))
+ return PTR_ERR(platdata->regs);
+
+ return 0;
+}
+
+static const struct dm_serial_ops sifive_serial_ops = {
+ .putc = sifive_serial_putc,
+ .getc = sifive_serial_getc,
+ .pending = sifive_serial_pending,
+ .setbrg = sifive_serial_setbrg,
+};
+
+static const struct udevice_id sifive_serial_ids[] = {
+ { .compatible = "sifive,uart0" },
+ { }
+};
+
+U_BOOT_DRIVER(serial_sifive) = {
+ .name = "serial_sifive",
+ .id = UCLASS_SERIAL,
+ .of_match = sifive_serial_ids,
+ .ofdata_to_platdata = sifive_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct sifive_uart_platdata),
+ .probe = sifive_serial_probe,
+ .ops = &sifive_serial_ops,
+};
+
+#ifdef CONFIG_DEBUG_UART_SIFIVE
+static inline void _debug_uart_init(void)
+{
+ struct uart_sifive *regs =
+ (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
+
+ _sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
+ CONFIG_BAUDRATE);
+ _sifive_serial_init(regs);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ struct uart_sifive *regs =
+ (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
+
+ while (_sifive_serial_putc(regs, ch) == -EAGAIN)
+ WATCHDOG_RESET();
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index b0e6f32f0b..df37a798bd 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -126,6 +126,13 @@ config OMAP_TIMER
help
Select this to enable an timer for Omap devices.
+config RISCV_TIMER
+ bool "RISC-V timer support"
+ depends on TIMER && RISCV
+ help
+ Select this to enable support for the timer as defined
+ by the RISC-V privileged architecture spec.
+
config ROCKCHIP_TIMER
bool "Rockchip timer support"
depends on TIMER
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index c4fbab2aac..d0bf218b11 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
+obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
obj-$(CONFIG_STI_TIMER) += sti-timer.o
diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c
new file mode 100644
index 0000000000..9f9f070e0b
--- /dev/null
+++ b/drivers/timer/riscv_timer.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * RISC-V privileged architecture defined generic timer driver
+ *
+ * This driver relies on RISC-V platform codes to provide the essential API
+ * riscv_get_time() which is supposed to return the timer counter as defined
+ * by the RISC-V privileged architecture spec.
+ *
+ * This driver can be used in both M-mode and S-mode U-Boot.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+
+/**
+ * riscv_get_time() - get the timer counter
+ *
+ * Platform codes should provide this API in order to make this driver function.
+ *
+ * @time: the 64-bit timer count as defined by the RISC-V privileged
+ * architecture spec.
+ * @return: 0 on success, -ve on error.
+ */
+extern int riscv_get_time(u64 *time);
+
+static int riscv_timer_get_count(struct udevice *dev, u64 *count)
+{
+ return riscv_get_time(count);
+}
+
+static int riscv_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* clock frequency was passed from the cpu driver as driver data */
+ uc_priv->clock_rate = dev->driver_data;
+
+ return 0;
+}
+
+static const struct timer_ops riscv_timer_ops = {
+ .get_count = riscv_timer_get_count,
+};
+
+U_BOOT_DRIVER(riscv_timer) = {
+ .name = "riscv_timer",
+ .id = UCLASS_TIMER,
+ .probe = riscv_timer_probe,
+ .ops = &riscv_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};