diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/cpu/bmips_cpu.c | 72 | ||||
-rw-r--r-- | drivers/ram/bmips_ram.c | 54 | ||||
-rw-r--r-- | drivers/serial/serial_bcm6345.c | 10 | ||||
-rw-r--r-- | drivers/sysreset/Kconfig | 6 | ||||
-rw-r--r-- | drivers/sysreset/Makefile | 1 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_watchdog.c | 60 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 8 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/bcm6345_wdt.c | 110 |
9 files changed, 303 insertions, 19 deletions
diff --git a/drivers/cpu/bmips_cpu.c b/drivers/cpu/bmips_cpu.c index 379acf2d55..07a873a6c0 100644 --- a/drivers/cpu/bmips_cpu.c +++ b/drivers/cpu/bmips_cpu.c @@ -30,6 +30,14 @@ DECLARE_GLOBAL_DATA_PTR; #define STRAPBUS_6328_FCVO_SHIFT 7 #define STRAPBUS_6328_FCVO_MASK (0x1f << STRAPBUS_6328_FCVO_SHIFT) +#define REG_BCM6348_PERF_MIPSPLLCFG 0x34 +#define MIPSPLLCFG_6348_M1CPU_SHIFT 6 +#define MIPSPLLCFG_6348_M1CPU_MASK (0x7 << MIPSPLLCFG_6348_M1CPU_SHIFT) +#define MIPSPLLCFG_6348_N2_SHIFT 15 +#define MIPSPLLCFG_6348_N2_MASK (0x1F << MIPSPLLCFG_6348_N2_SHIFT) +#define MIPSPLLCFG_6348_N1_SHIFT 20 +#define MIPSPLLCFG_6348_N1_MASK (0x7 << MIPSPLLCFG_6348_N1_SHIFT) + #define REG_BCM6358_DDR_DMIPSPLLCFG 0x12b8 #define DMIPSPLLCFG_6358_M1_SHIFT 0 #define DMIPSPLLCFG_6358_M1_MASK (0xff << DMIPSPLLCFG_6358_M1_SHIFT) @@ -56,7 +64,7 @@ struct bmips_cpu_priv { }; /* Specific CPU Ops */ -static int bcm6358_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf, +static int bmips_short_cpu_desc(struct bmips_cpu_priv *priv, char *buf, int size) { unsigned short cpu_id; @@ -72,7 +80,7 @@ static int bcm6358_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf, return 0; } -static int bcm6328_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf, +static int bmips_long_cpu_desc(struct bmips_cpu_priv *priv, char *buf, int size) { unsigned int cpu_id; @@ -88,6 +96,11 @@ static int bcm6328_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf, return 0; } +static ulong bcm3380_get_cpu_freq(struct bmips_cpu_priv *priv) +{ + return 333000000; +} + static ulong bcm6328_get_cpu_freq(struct bmips_cpu_priv *priv) { unsigned int mips_pll_fcvo; @@ -115,6 +128,23 @@ static ulong bcm6328_get_cpu_freq(struct bmips_cpu_priv *priv) } } +static ulong bcm6338_get_cpu_freq(struct bmips_cpu_priv *priv) +{ + return 240000000; +} + +static ulong bcm6348_get_cpu_freq(struct bmips_cpu_priv *priv) +{ + unsigned int tmp, n1, n2, m1; + + tmp = readl_be(priv->regs + REG_BCM6348_PERF_MIPSPLLCFG); + n1 = (tmp & MIPSPLLCFG_6348_N1_MASK) >> MIPSPLLCFG_6348_N1_SHIFT; + n2 = (tmp & MIPSPLLCFG_6348_N2_MASK) >> MIPSPLLCFG_6348_N2_SHIFT; + m1 = (tmp & MIPSPLLCFG_6348_M1CPU_MASK) >> MIPSPLLCFG_6348_M1CPU_SHIFT; + + return (16 * 1000000 * (n1 + 1) * (n2 + 2)) / (m1 + 1); +} + static ulong bcm6358_get_cpu_freq(struct bmips_cpu_priv *priv) { unsigned int tmp, n1, n2, m1; @@ -160,25 +190,48 @@ static int bcm6328_get_cpu_count(struct bmips_cpu_priv *priv) return 2; } +static int bcm6345_get_cpu_count(struct bmips_cpu_priv *priv) +{ + return 1; +} + static int bcm6358_get_cpu_count(struct bmips_cpu_priv *priv) { return 2; } +static const struct bmips_cpu_hw bmips_cpu_bcm3380 = { + .get_cpu_desc = bmips_short_cpu_desc, + .get_cpu_freq = bcm3380_get_cpu_freq, + .get_cpu_count = bcm6358_get_cpu_count, +}; + static const struct bmips_cpu_hw bmips_cpu_bcm6328 = { - .get_cpu_desc = bcm6328_get_cpu_desc, + .get_cpu_desc = bmips_long_cpu_desc, .get_cpu_freq = bcm6328_get_cpu_freq, .get_cpu_count = bcm6328_get_cpu_count, }; +static const struct bmips_cpu_hw bmips_cpu_bcm6338 = { + .get_cpu_desc = bmips_short_cpu_desc, + .get_cpu_freq = bcm6338_get_cpu_freq, + .get_cpu_count = bcm6345_get_cpu_count, +}; + +static const struct bmips_cpu_hw bmips_cpu_bcm6348 = { + .get_cpu_desc = bmips_short_cpu_desc, + .get_cpu_freq = bcm6348_get_cpu_freq, + .get_cpu_count = bcm6345_get_cpu_count, +}; + static const struct bmips_cpu_hw bmips_cpu_bcm6358 = { - .get_cpu_desc = bcm6358_get_cpu_desc, + .get_cpu_desc = bmips_short_cpu_desc, .get_cpu_freq = bcm6358_get_cpu_freq, .get_cpu_count = bcm6358_get_cpu_count, }; static const struct bmips_cpu_hw bmips_cpu_bcm63268 = { - .get_cpu_desc = bcm6328_get_cpu_desc, + .get_cpu_desc = bmips_long_cpu_desc, .get_cpu_freq = bcm63268_get_cpu_freq, .get_cpu_count = bcm6358_get_cpu_count, }; @@ -259,9 +312,18 @@ int bmips_cpu_probe(struct udevice *dev) static const struct udevice_id bmips_cpu_ids[] = { { + .compatible = "brcm,bcm3380-cpu", + .data = (ulong)&bmips_cpu_bcm3380, + }, { .compatible = "brcm,bcm6328-cpu", .data = (ulong)&bmips_cpu_bcm6328, }, { + .compatible = "brcm,bcm6338-cpu", + .data = (ulong)&bmips_cpu_bcm6338, + }, { + .compatible = "brcm,bcm6348-cpu", + .data = (ulong)&bmips_cpu_bcm6348, + }, { .compatible = "brcm,bcm6358-cpu", .data = (ulong)&bmips_cpu_bcm6358, }, { diff --git a/drivers/ram/bmips_ram.c b/drivers/ram/bmips_ram.c index d0f7cd7376..ac35fbe294 100644 --- a/drivers/ram/bmips_ram.c +++ b/drivers/ram/bmips_ram.c @@ -14,6 +14,16 @@ #include <asm/io.h> #include <dm/device.h> +#define SDRAM_CFG_REG 0x0 +#define SDRAM_CFG_COL_SHIFT 4 +#define SDRAM_CFG_COL_MASK (0x3 << SDRAM_CFG_COL_SHIFT) +#define SDRAM_CFG_ROW_SHIFT 6 +#define SDRAM_CFG_ROW_MASK (0x3 << SDRAM_CFG_ROW_SHIFT) +#define SDRAM_CFG_32B_SHIFT 10 +#define SDRAM_CFG_32B_MASK (1 << SDRAM_CFG_32B_SHIFT) +#define SDRAM_CFG_BANK_SHIFT 13 +#define SDRAM_CFG_BANK_MASK (1 << SDRAM_CFG_BANK_SHIFT) + #define MEMC_CFG_REG 0x4 #define MEMC_CFG_32B_SHIFT 1 #define MEMC_CFG_32B_MASK (1 << MEMC_CFG_32B_SHIFT) @@ -40,24 +50,41 @@ static ulong bcm6328_get_ram_size(struct bmips_ram_priv *priv) return readl_be(priv->regs + DDR_CSEND_REG) << 24; } +static ulong bmips_dram_size(unsigned int cols, unsigned int rows, + unsigned int is_32b, unsigned int banks) +{ + rows += 11; /* 0 => 11 address bits ... 2 => 13 address bits */ + cols += 8; /* 0 => 8 address bits ... 2 => 10 address bits */ + is_32b += 1; + + return 1 << (cols + rows + is_32b + banks); +} + +static ulong bcm6338_get_ram_size(struct bmips_ram_priv *priv) +{ + unsigned int cols = 0, rows = 0, is_32b = 0, banks = 0; + u32 val; + + val = readl_be(priv->regs + SDRAM_CFG_REG); + rows = (val & SDRAM_CFG_ROW_MASK) >> SDRAM_CFG_ROW_SHIFT; + cols = (val & SDRAM_CFG_COL_MASK) >> SDRAM_CFG_COL_SHIFT; + is_32b = (val & SDRAM_CFG_32B_MASK) ? 1 : 0; + banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1; + + return bmips_dram_size(cols, rows, is_32b, banks); +} + static ulong bcm6358_get_ram_size(struct bmips_ram_priv *priv) { - unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0; + unsigned int cols = 0, rows = 0, is_32b = 0; u32 val; val = readl_be(priv->regs + MEMC_CFG_REG); rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT; cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT; - is_32bits = (val & MEMC_CFG_32B_MASK) ? 0 : 1; - banks = 2; - - /* 0 => 11 address bits ... 2 => 13 address bits */ - rows += 11; + is_32b = (val & MEMC_CFG_32B_MASK) ? 0 : 1; - /* 0 => 8 address bits ... 2 => 10 address bits */ - cols += 8; - - return 1 << (cols + rows + (is_32bits + 1) + banks); + return bmips_dram_size(cols, rows, is_32b, 2); } static int bmips_ram_get_info(struct udevice *dev, struct ram_info *info) @@ -79,6 +106,10 @@ static const struct bmips_ram_hw bmips_ram_bcm6328 = { .get_ram_size = bcm6328_get_ram_size, }; +static const struct bmips_ram_hw bmips_ram_bcm6338 = { + .get_ram_size = bcm6338_get_ram_size, +}; + static const struct bmips_ram_hw bmips_ram_bcm6358 = { .get_ram_size = bcm6358_get_ram_size, }; @@ -88,6 +119,9 @@ static const struct udevice_id bmips_ram_ids[] = { .compatible = "brcm,bcm6328-mc", .data = (ulong)&bmips_ram_bcm6328, }, { + .compatible = "brcm,bcm6338-mc", + .data = (ulong)&bmips_ram_bcm6338, + }, { .compatible = "brcm,bcm6358-mc", .data = (ulong)&bmips_ram_bcm6358, }, { /* sentinel */ } diff --git a/drivers/serial/serial_bcm6345.c b/drivers/serial/serial_bcm6345.c index db270e3b21..0843b48bea 100644 --- a/drivers/serial/serial_bcm6345.c +++ b/drivers/serial/serial_bcm6345.c @@ -141,6 +141,8 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) UART_CTL_RXTIMEOUT_5 | /* set 8 bits/symbol */ UART_CTL_BITSPERSYM_8 | + /* set 1 stop bit */ + UART_CTL_STOPBITS_1 | /* set parity to even */ UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK); @@ -155,11 +157,11 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) UART_FIFO_CFG_TX_4); /* set baud rate */ - val = (clk / baudrate) / 16; + val = ((clk / baudrate) >> 4); if (val & 0x1) - val = val; + val = (val >> 1); else - val = val / 2 - 1; + val = (val >> 1) - 1; writel_be(val, base + UART_BAUD_REG); /* clear interrupts */ @@ -241,7 +243,7 @@ static int bcm6345_serial_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; - priv->uartclk = clk_get_rate(&clk) / 2; + priv->uartclk = clk_get_rate(&clk); clk_free(&clk); /* initialize serial */ diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index b2f746494d..a6d48e8a66 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -31,4 +31,10 @@ config SYSRESET_SYSCON help Reboot support for generic SYSCON mapped register reset. +config SYSRESET_WATCHDOG + bool "Enable support for watchdog reboot driver" + select WDT + help + Reboot support for generic watchdog reset. + endmenu diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index bd352e7541..b68381148c 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SYSRESET) += sysreset-uclass.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o +obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ROCKCHIP_RK3036) += sysreset_rk3036.o diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c new file mode 100644 index 0000000000..304ed052a2 --- /dev/null +++ b/drivers/sysreset/sysreset_watchdog.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <wdt.h> + +struct wdt_reboot_priv { + struct udevice *wdt; +}; + +static int wdt_reboot_request(struct udevice *dev, enum sysreset_t type) +{ + struct wdt_reboot_priv *priv = dev_get_priv(dev); + int ret; + + ret = wdt_expire_now(priv->wdt, 0); + if (ret) + return ret; + + return -EINPROGRESS; +} + +static struct sysreset_ops wdt_reboot_ops = { + .request = wdt_reboot_request, +}; + +int wdt_reboot_probe(struct udevice *dev) +{ + struct wdt_reboot_priv *priv = dev_get_priv(dev); + int err; + + err = uclass_get_device_by_phandle(UCLASS_WDT, dev, + "wdt", &priv->wdt); + if (err) { + error("unable to find wdt device\n"); + return err; + } + + return 0; +} + +static const struct udevice_id wdt_reboot_ids[] = { + { .compatible = "wdt-reboot" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(wdt_reboot) = { + .name = "wdt_reboot", + .id = UCLASS_SYSRESET, + .of_match = wdt_reboot_ids, + .ops = &wdt_reboot_ops, + .priv_auto_alloc_size = sizeof(struct wdt_reboot_priv), + .probe = wdt_reboot_probe, +}; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 22a7c4f801..b911233db3 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -54,4 +54,12 @@ config WDT_ASPEED It currently does not support Boot Flash Addressing Mode Detection or Second Boot. +config WDT_BCM6345 + bool "BCM6345 watchdog timer support" + depends on WDT && ARCH_BMIPS + help + Select this to enable watchdog timer for BCM6345 SoCs. + The watchdog timer is stopped when initialized. + It performs full SoC reset. + endmenu diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 8378601b33..4b19e4ccf6 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -18,4 +18,5 @@ obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o obj-$(CONFIG_WDT) += wdt-uclass.o obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o +obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o diff --git a/drivers/watchdog/bcm6345_wdt.c b/drivers/watchdog/bcm6345_wdt.c new file mode 100644 index 0000000000..c6b02ec43f --- /dev/null +++ b/drivers/watchdog/bcm6345_wdt.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> + * + * Derived from linux/drivers/watchdog/bcm63xx_wdt.c: + * Copyright (C) 2007 Miguel Gaio <miguel.gaio@efixo.com> + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <asm/io.h> + +/* WDT Value register */ +#define WDT_VAL_REG 0x0 +#define WDT_VAL_MIN 0x00000002 +#define WDT_VAL_MAX 0xfffffffe + +/* WDT Control register */ +#define WDT_CTL_REG 0x4 +#define WDT_CTL_START1_MASK 0x0000ff00 +#define WDT_CTL_START2_MASK 0x000000ff +#define WDT_CTL_STOP1_MASK 0x0000ee00 +#define WDT_CTL_STOP2_MASK 0x000000ee + +struct bcm6345_wdt_priv { + void __iomem *regs; +}; + +static int bcm6345_wdt_reset(struct udevice *dev) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + + writel_be(WDT_CTL_START1_MASK, priv->regs + WDT_CTL_REG); + writel_be(WDT_CTL_START2_MASK, priv->regs + WDT_CTL_REG); + + return 0; +} + +static int bcm6345_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + + if (timeout < WDT_VAL_MIN) { + debug("watchdog won't fire with less than 2 ticks\n"); + timeout = WDT_VAL_MIN; + } else if (timeout > WDT_VAL_MAX) { + debug("maximum watchdog timeout exceeded\n"); + timeout = WDT_VAL_MAX; + } + + writel_be(timeout, priv->regs + WDT_VAL_REG); + + return bcm6345_wdt_reset(dev); +} + +static int bcm6345_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return bcm6345_wdt_start(dev, WDT_VAL_MIN, flags); +} + +static int bcm6345_wdt_stop(struct udevice *dev) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + + writel_be(WDT_CTL_STOP1_MASK, priv->regs + WDT_CTL_REG); + writel_be(WDT_CTL_STOP2_MASK, priv->regs + WDT_CTL_REG); + + return 0; +} + +static const struct wdt_ops bcm6345_wdt_ops = { + .expire_now = bcm6345_wdt_expire_now, + .reset = bcm6345_wdt_reset, + .start = bcm6345_wdt_start, + .stop = bcm6345_wdt_stop, +}; + +static const struct udevice_id bcm6345_wdt_ids[] = { + { .compatible = "brcm,bcm6345-wdt" }, + { /* sentinel */ } +}; + +static int bcm6345_wdt_probe(struct udevice *dev) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = dev_get_addr_size_index(dev, 0, &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = ioremap(addr, size); + + bcm6345_wdt_stop(dev); + + return 0; +} + +U_BOOT_DRIVER(wdt_bcm6345) = { + .name = "wdt_bcm6345", + .id = UCLASS_WDT, + .of_match = bcm6345_wdt_ids, + .ops = &bcm6345_wdt_ops, + .priv_auto_alloc_size = sizeof(struct bcm6345_wdt_priv), + .probe = bcm6345_wdt_probe, +}; |