mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 07:31:15 +00:00
- StarFive: Add StarFive watchdog driver - VisionFive2: Support device tree overlay for VisionFive2 board - Andes: Fix PLIC-SW setting - RISC-V: Fix NVMe support by implying NVME_PCI for QEMU - RISC-V: Fix binman for 64 bit format load address
This commit is contained in:
commit
8737914336
10 changed files with 382 additions and 29 deletions
|
@ -5,9 +5,6 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#define U64_TO_U32_H(addr) (((addr) >> 32) & 0xffffffff)
|
|
||||||
#define U64_TO_U32_L(addr) ((addr) & 0xffffffff)
|
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
binman: binman {
|
binman: binman {
|
||||||
multiple-images;
|
multiple-images;
|
||||||
|
@ -36,8 +33,7 @@
|
||||||
os = "U-Boot";
|
os = "U-Boot";
|
||||||
arch = "riscv";
|
arch = "riscv";
|
||||||
compression = "none";
|
compression = "none";
|
||||||
load = <U64_TO_U32_H(CONFIG_TEXT_BASE)
|
load = /bits/ 64 <CONFIG_TEXT_BASE>;
|
||||||
U64_TO_U32_L(CONFIG_TEXT_BASE)>;
|
|
||||||
|
|
||||||
uboot_blob: blob-ext {
|
uboot_blob: blob-ext {
|
||||||
filename = "u-boot-nodtb.bin";
|
filename = "u-boot-nodtb.bin";
|
||||||
|
@ -50,7 +46,7 @@
|
||||||
os = "Linux";
|
os = "Linux";
|
||||||
arch = "riscv";
|
arch = "riscv";
|
||||||
compression = "none";
|
compression = "none";
|
||||||
load = <CONFIG_TEXT_BASE>;
|
load = /bits/ 64 <CONFIG_TEXT_BASE>;
|
||||||
|
|
||||||
linux_blob: blob-ext {
|
linux_blob: blob-ext {
|
||||||
filename = "Image";
|
filename = "Image";
|
||||||
|
@ -64,10 +60,8 @@
|
||||||
os = "opensbi";
|
os = "opensbi";
|
||||||
arch = "riscv";
|
arch = "riscv";
|
||||||
compression = "none";
|
compression = "none";
|
||||||
load = <U64_TO_U32_H(CONFIG_SPL_OPENSBI_LOAD_ADDR)
|
load = /bits/ 64 <CONFIG_SPL_OPENSBI_LOAD_ADDR>;
|
||||||
U64_TO_U32_L(CONFIG_SPL_OPENSBI_LOAD_ADDR)>;
|
entry = /bits/ 64 <CONFIG_SPL_OPENSBI_LOAD_ADDR>;
|
||||||
entry = <U64_TO_U32_H(CONFIG_SPL_OPENSBI_LOAD_ADDR)
|
|
||||||
U64_TO_U32_L(CONFIG_SPL_OPENSBI_LOAD_ADDR)>;
|
|
||||||
|
|
||||||
opensbi_blob: opensbi {
|
opensbi_blob: opensbi {
|
||||||
filename = "fw_dynamic.bin";
|
filename = "fw_dynamic.bin";
|
||||||
|
|
|
@ -533,6 +533,16 @@
|
||||||
#gpio-cells = <2>;
|
#gpio-cells = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watchdog@13070000 {
|
||||||
|
compatible = "starfive,jh7110-wdt";
|
||||||
|
reg = <0x0 0x13070000 0x0 0x10000>;
|
||||||
|
clocks = <&syscrg JH7110_SYSCLK_WDT_APB>,
|
||||||
|
<&syscrg JH7110_SYSCLK_WDT_CORE>;
|
||||||
|
clock-names = "apb", "core";
|
||||||
|
resets = <&syscrg JH7110_SYSRST_WDT_APB>,
|
||||||
|
<&syscrg JH7110_SYSRST_WDT_CORE>;
|
||||||
|
};
|
||||||
|
|
||||||
mmc0: mmc@16010000 {
|
mmc0: mmc@16010000 {
|
||||||
compatible = "starfive,jh7110-mmc";
|
compatible = "starfive,jh7110-mmc";
|
||||||
reg = <0x0 0x16010000 0x0 0x10000>;
|
reg = <0x0 0x16010000 0x0 0x10000>;
|
||||||
|
|
|
@ -21,41 +21,36 @@
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
|
||||||
/* pending register */
|
/* pending register */
|
||||||
#define PENDING_REG(base) ((ulong)(base) + 0x1000)
|
#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + 4 * (((hart) + 1) / 32))
|
||||||
/* enable register */
|
/* enable register */
|
||||||
#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80)
|
#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80 + 4 * (((hart) + 1) / 32))
|
||||||
/* claim register */
|
/* claim register */
|
||||||
#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000)
|
#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000)
|
||||||
/* priority register */
|
/* priority register */
|
||||||
#define PRIORITY_REG(base) ((ulong)(base) + PLICSW_PRIORITY_BASE)
|
#define PRIORITY_REG(base) ((ulong)(base) + PLICSW_PRIORITY_BASE)
|
||||||
|
|
||||||
/* Bit 0 of PLIC-SW pending array is hardwired to zero, so we start from bit 1 */
|
/* Bit 0 of PLIC-SW pending array is hardwired to zero, so we start from bit 1 */
|
||||||
#define FIRST_AVAILABLE_BIT 0x2
|
|
||||||
#define SEND_IPI_TO_HART(hart) (FIRST_AVAILABLE_BIT << (hart))
|
|
||||||
#define PLICSW_PRIORITY_BASE 0x4
|
#define PLICSW_PRIORITY_BASE 0x4
|
||||||
#define PLICSW_INTERRUPT_PER_HART 0x1
|
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
static int enable_ipi(int hart)
|
static int enable_ipi(int hart)
|
||||||
{
|
{
|
||||||
unsigned int en;
|
u32 enable_bit = (hart + 1) % 32;
|
||||||
|
|
||||||
en = FIRST_AVAILABLE_BIT << hart;
|
writel(BIT(enable_bit), (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart));
|
||||||
writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_priority_ipi(int hart_num)
|
static void init_priority_ipi(int hart_num)
|
||||||
{
|
{
|
||||||
uint32_t *priority = (void *)PRIORITY_REG(gd->arch.plicsw);
|
u32 *priority = (void *)PRIORITY_REG(gd->arch.plicsw);
|
||||||
|
|
||||||
for (int i = 0; i < hart_num * PLICSW_INTERRUPT_PER_HART; i++) {
|
for (int i = 0; i < hart_num; i++)
|
||||||
writel(1, &priority[i]);
|
writel(1, &priority[i]);
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_init_ipi(void)
|
int riscv_init_ipi(void)
|
||||||
|
@ -104,9 +99,10 @@ int riscv_init_ipi(void)
|
||||||
|
|
||||||
int riscv_send_ipi(int hart)
|
int riscv_send_ipi(int hart)
|
||||||
{
|
{
|
||||||
unsigned int ipi = SEND_IPI_TO_HART(hart);
|
u32 interrupt_id = hart + 1;
|
||||||
|
u32 pending_bit = interrupt_id % 32;
|
||||||
|
|
||||||
writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw));
|
writel(BIT(pending_bit), (void __iomem *)PENDING_REG(gd->arch.plicsw, hart));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -123,10 +119,11 @@ int riscv_clear_ipi(int hart)
|
||||||
|
|
||||||
int riscv_get_ipi(int hart, int *pending)
|
int riscv_get_ipi(int hart, int *pending)
|
||||||
{
|
{
|
||||||
unsigned int ipi = SEND_IPI_TO_HART(hart);
|
u32 interrupt_id = hart + 1;
|
||||||
|
u32 pending_bit = interrupt_id % 32;
|
||||||
|
|
||||||
*pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw));
|
*pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw, hart));
|
||||||
*pending = !!(*pending & ipi);
|
*pending = !!(*pending & BIT(pending_bit));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
|
||||||
imply SCSI_AHCI
|
imply SCSI_AHCI
|
||||||
imply AHCI_PCI
|
imply AHCI_PCI
|
||||||
imply E1000
|
imply E1000
|
||||||
imply NVME
|
|
||||||
imply PCI
|
imply PCI
|
||||||
|
imply NVME_PCI
|
||||||
imply PCIE_ECAM_GENERIC
|
imply PCIE_ECAM_GENERIC
|
||||||
imply DM_RNG
|
imply DM_RNG
|
||||||
imply SCSI
|
imply SCSI
|
||||||
|
|
|
@ -72,6 +72,7 @@ CONFIG_CMD_MEMINFO=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
CONFIG_CMD_PCI=y
|
CONFIG_CMD_PCI=y
|
||||||
CONFIG_CMD_USB=y
|
CONFIG_CMD_USB=y
|
||||||
|
CONFIG_CMD_WDT=y
|
||||||
CONFIG_CMD_TFTPPUT=y
|
CONFIG_CMD_TFTPPUT=y
|
||||||
CONFIG_CMD_BOOTSTAGE=y
|
CONFIG_CMD_BOOTSTAGE=y
|
||||||
CONFIG_OF_BOARD=y
|
CONFIG_OF_BOARD=y
|
||||||
|
@ -133,3 +134,7 @@ CONFIG_USB_EHCI_PCI=y
|
||||||
CONFIG_USB_OHCI_HCD=y
|
CONFIG_USB_OHCI_HCD=y
|
||||||
CONFIG_USB_OHCI_PCI=y
|
CONFIG_USB_OHCI_PCI=y
|
||||||
CONFIG_USB_KEYBOARD=y
|
CONFIG_USB_KEYBOARD=y
|
||||||
|
# CONFIG_WATCHDOG is not set
|
||||||
|
# CONFIG_WATCHDOG_AUTOSTART is not set
|
||||||
|
CONFIG_WDT=y
|
||||||
|
CONFIG_WDT_STARFIVE=y
|
||||||
|
|
|
@ -434,6 +434,15 @@ static int jh7110_syscrg_init(struct udevice *dev)
|
||||||
starfive_clk_gate(priv->reg,
|
starfive_clk_gate(priv->reg,
|
||||||
"i2c5_apb", "apb0",
|
"i2c5_apb", "apb0",
|
||||||
OFFSET(JH7110_SYSCLK_I2C5_APB)));
|
OFFSET(JH7110_SYSCLK_I2C5_APB)));
|
||||||
|
/* Watchdog clocks */
|
||||||
|
clk_dm(JH7110_SYS_ID_TRANS(JH7110_SYSCLK_WDT_APB),
|
||||||
|
starfive_clk_gate(priv->reg,
|
||||||
|
"wdt_apb", "apb0",
|
||||||
|
OFFSET(JH7110_SYSCLK_WDT_APB)));
|
||||||
|
clk_dm(JH7110_SYS_ID_TRANS(JH7110_SYSCLK_WDT_CORE),
|
||||||
|
starfive_clk_gate(priv->reg,
|
||||||
|
"wdt_core", "oscillator",
|
||||||
|
OFFSET(JH7110_SYSCLK_WDT_CORE)));
|
||||||
|
|
||||||
/* enable noc_bus_stg_axi clock */
|
/* enable noc_bus_stg_axi clock */
|
||||||
if (!clk_get_by_id(JH7110_SYSCLK_NOC_BUS_STG_AXI, &pclk))
|
if (!clk_get_by_id(JH7110_SYSCLK_NOC_BUS_STG_AXI, &pclk))
|
||||||
|
|
|
@ -344,6 +344,13 @@ config WDT_STM32MP
|
||||||
Enable the STM32 watchdog (IWDG) driver. Enable support to
|
Enable the STM32 watchdog (IWDG) driver. Enable support to
|
||||||
configure STM32's on-SoC watchdog.
|
configure STM32's on-SoC watchdog.
|
||||||
|
|
||||||
|
config WDT_STARFIVE
|
||||||
|
bool "StarFive watchdog timer support"
|
||||||
|
depends on WDT
|
||||||
|
imply WATCHDOG
|
||||||
|
help
|
||||||
|
Enable support for the watchdog timer of StarFive JH7110 SoC.
|
||||||
|
|
||||||
config WDT_SUNXI
|
config WDT_SUNXI
|
||||||
bool "Allwinner sunxi watchdog timer support"
|
bool "Allwinner sunxi watchdog timer support"
|
||||||
depends on WDT && ARCH_SUNXI
|
depends on WDT && ARCH_SUNXI
|
||||||
|
|
|
@ -44,6 +44,7 @@ obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
|
||||||
obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
|
obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
|
||||||
obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o
|
obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o
|
||||||
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
|
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
|
||||||
|
obj-$(CONFIG_WDT_STARFIVE) += starfive_wdt.o
|
||||||
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
|
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
|
||||||
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
|
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
|
||||||
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
|
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
|
||||||
|
|
329
drivers/watchdog/starfive_wdt.c
Normal file
329
drivers/watchdog/starfive_wdt.c
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Starfive Watchdog driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <clk.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <reset.h>
|
||||||
|
#include <wdt.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
|
||||||
|
/* JH7110 Watchdog register define */
|
||||||
|
#define STARFIVE_WDT_JH7110_LOAD 0x000
|
||||||
|
#define STARFIVE_WDT_JH7110_VALUE 0x004
|
||||||
|
#define STARFIVE_WDT_JH7110_CONTROL 0x008 /*
|
||||||
|
* [0]: reset enable;
|
||||||
|
* [1]: interrupt enable && watchdog enable
|
||||||
|
* [31:2]: reserved.
|
||||||
|
*/
|
||||||
|
#define STARFIVE_WDT_JH7110_INTCLR 0x00c /* clear intterupt and reload the counter */
|
||||||
|
#define STARFIVE_WDT_JH7110_IMS 0x014
|
||||||
|
#define STARFIVE_WDT_JH7110_LOCK 0xc00 /* write 0x1ACCE551 to unlock */
|
||||||
|
|
||||||
|
/* WDOGCONTROL */
|
||||||
|
#define STARFIVE_WDT_ENABLE 0x1
|
||||||
|
#define STARFIVE_WDT_EN_SHIFT 0
|
||||||
|
#define STARFIVE_WDT_RESET_EN 0x1
|
||||||
|
#define STARFIVE_WDT_JH7110_RST_EN_SHIFT 1
|
||||||
|
|
||||||
|
/* WDOGLOCK */
|
||||||
|
#define STARFIVE_WDT_JH7110_UNLOCK_KEY 0x1acce551
|
||||||
|
|
||||||
|
/* WDOGINTCLR */
|
||||||
|
#define STARFIVE_WDT_INTCLR 0x1
|
||||||
|
#define STARFIVE_WDT_JH7100_INTCLR_AVA_SHIFT 1 /* Watchdog can clear interrupt when 0 */
|
||||||
|
|
||||||
|
#define STARFIVE_WDT_MAXCNT 0xffffffff
|
||||||
|
#define STARFIVE_WDT_DEFAULT_TIME (15)
|
||||||
|
#define STARFIVE_WDT_DELAY_US 0
|
||||||
|
#define STARFIVE_WDT_TIMEOUT_US 10000
|
||||||
|
|
||||||
|
/* module parameter */
|
||||||
|
#define STARFIVE_WDT_EARLY_ENA 0
|
||||||
|
|
||||||
|
struct starfive_wdt_variant {
|
||||||
|
unsigned int control; /* Watchdog Control Resgister for reset enable */
|
||||||
|
unsigned int load; /* Watchdog Load register */
|
||||||
|
unsigned int reload; /* Watchdog Reload Control register */
|
||||||
|
unsigned int enable; /* Watchdog Enable Register */
|
||||||
|
unsigned int value; /* Watchdog Counter Value Register */
|
||||||
|
unsigned int int_clr; /* Watchdog Interrupt Clear Register */
|
||||||
|
unsigned int unlock; /* Watchdog Lock Register */
|
||||||
|
unsigned int int_status; /* Watchdog Interrupt Status Register */
|
||||||
|
|
||||||
|
u32 unlock_key;
|
||||||
|
char enrst_shift;
|
||||||
|
char en_shift;
|
||||||
|
bool intclr_check; /* whether need to check it before clearing interrupt */
|
||||||
|
char intclr_ava_shift;
|
||||||
|
bool double_timeout; /* The watchdog need twice timeout to reboot */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct starfive_wdt_priv {
|
||||||
|
void __iomem *base;
|
||||||
|
struct clk *core_clk;
|
||||||
|
struct clk *apb_clk;
|
||||||
|
struct reset_ctl_bulk *rst;
|
||||||
|
const struct starfive_wdt_variant *variant;
|
||||||
|
unsigned long freq;
|
||||||
|
u32 count; /* count of timeout */
|
||||||
|
u32 reload; /* restore the count */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register layout and configuration for the JH7110 */
|
||||||
|
static const struct starfive_wdt_variant starfive_wdt_jh7110_variant = {
|
||||||
|
.control = STARFIVE_WDT_JH7110_CONTROL,
|
||||||
|
.load = STARFIVE_WDT_JH7110_LOAD,
|
||||||
|
.enable = STARFIVE_WDT_JH7110_CONTROL,
|
||||||
|
.value = STARFIVE_WDT_JH7110_VALUE,
|
||||||
|
.int_clr = STARFIVE_WDT_JH7110_INTCLR,
|
||||||
|
.unlock = STARFIVE_WDT_JH7110_LOCK,
|
||||||
|
.unlock_key = STARFIVE_WDT_JH7110_UNLOCK_KEY,
|
||||||
|
.int_status = STARFIVE_WDT_JH7110_IMS,
|
||||||
|
.enrst_shift = STARFIVE_WDT_JH7110_RST_EN_SHIFT,
|
||||||
|
.en_shift = STARFIVE_WDT_EN_SHIFT,
|
||||||
|
.intclr_check = false,
|
||||||
|
.double_timeout = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int starfive_wdt_enable_clock(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_enable(wdt->apb_clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_enable(wdt->core_clk);
|
||||||
|
if (ret) {
|
||||||
|
clk_disable(wdt->apb_clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void starfive_wdt_disable_clock(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
clk_disable(wdt->core_clk);
|
||||||
|
clk_disable(wdt->apb_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write unlock-key to unlock. Write other value to lock. */
|
||||||
|
static void starfive_wdt_unlock(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
writel(wdt->variant->unlock_key, wdt->base + wdt->variant->unlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void starfive_wdt_lock(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
writel(~wdt->variant->unlock_key, wdt->base + wdt->variant->unlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable watchdog interrupt to reset/reboot */
|
||||||
|
static void starfive_wdt_enable_reset(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(wdt->base + wdt->variant->control);
|
||||||
|
val |= STARFIVE_WDT_RESET_EN << wdt->variant->enrst_shift;
|
||||||
|
writel(val, wdt->base + wdt->variant->control);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* waiting interrupt can be free to clear */
|
||||||
|
static int starfive_wdt_wait_int_free(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
return readl_poll_timeout(wdt->base + wdt->variant->int_clr, value,
|
||||||
|
!(value & BIT(wdt->variant->intclr_ava_shift)),
|
||||||
|
STARFIVE_WDT_TIMEOUT_US);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear interrupt signal before initialization or reload */
|
||||||
|
static int starfive_wdt_int_clr(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (wdt->variant->intclr_check) {
|
||||||
|
ret = starfive_wdt_wait_int_free(wdt);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
writel(STARFIVE_WDT_INTCLR, wdt->base + wdt->variant->int_clr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void starfive_wdt_set_count(struct starfive_wdt_priv *wdt,
|
||||||
|
u32 val)
|
||||||
|
{
|
||||||
|
writel(val, wdt->base + wdt->variant->load);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable watchdog */
|
||||||
|
static inline void starfive_wdt_enable(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(wdt->base + wdt->variant->enable);
|
||||||
|
val |= STARFIVE_WDT_ENABLE << wdt->variant->en_shift;
|
||||||
|
writel(val, wdt->base + wdt->variant->enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disable watchdog */
|
||||||
|
static inline void starfive_wdt_disable(struct starfive_wdt_priv *wdt)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(wdt->base + wdt->variant->enable);
|
||||||
|
val &= ~(STARFIVE_WDT_ENABLE << wdt->variant->en_shift);
|
||||||
|
writel(val, wdt->base + wdt->variant->enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void starfive_wdt_set_reload_count(struct starfive_wdt_priv *wdt,
|
||||||
|
u32 count)
|
||||||
|
{
|
||||||
|
starfive_wdt_set_count(wdt, count);
|
||||||
|
|
||||||
|
/* 7100 need set any value to reload register and could reload value to counter */
|
||||||
|
if (wdt->variant->reload)
|
||||||
|
writel(0x1, wdt->base + wdt->variant->reload);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int starfive_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct starfive_wdt_priv *wdt = dev_get_priv(dev);
|
||||||
|
|
||||||
|
starfive_wdt_unlock(wdt);
|
||||||
|
/* disable watchdog, to be safe */
|
||||||
|
starfive_wdt_disable(wdt);
|
||||||
|
|
||||||
|
starfive_wdt_enable_reset(wdt);
|
||||||
|
ret = starfive_wdt_int_clr(wdt);
|
||||||
|
if (ret)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
wdt->count = (timeout_ms / 1000) * wdt->freq;
|
||||||
|
if (wdt->variant->double_timeout)
|
||||||
|
wdt->count /= 2;
|
||||||
|
|
||||||
|
starfive_wdt_set_count(wdt, wdt->count);
|
||||||
|
starfive_wdt_enable(wdt);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
starfive_wdt_lock(wdt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int starfive_wdt_stop(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct starfive_wdt_priv *wdt = dev_get_priv(dev);
|
||||||
|
|
||||||
|
starfive_wdt_unlock(wdt);
|
||||||
|
starfive_wdt_disable(wdt);
|
||||||
|
starfive_wdt_lock(wdt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int starfive_wdt_reset(struct udevice *dev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct starfive_wdt_priv *wdt = dev_get_priv(dev);
|
||||||
|
|
||||||
|
starfive_wdt_unlock(wdt);
|
||||||
|
ret = starfive_wdt_int_clr(wdt);
|
||||||
|
if (ret)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
starfive_wdt_set_reload_count(wdt, wdt->count);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
starfive_wdt_lock(wdt);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wdt_ops starfive_wdt_ops = {
|
||||||
|
.start = starfive_wdt_start,
|
||||||
|
.stop = starfive_wdt_stop,
|
||||||
|
.reset = starfive_wdt_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int starfive_wdt_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct starfive_wdt_priv *wdt = dev_get_priv(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = starfive_wdt_enable_clock(wdt);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = reset_deassert_bulk(wdt->rst);
|
||||||
|
if (ret)
|
||||||
|
goto err_reset;
|
||||||
|
|
||||||
|
wdt->variant = (const struct starfive_wdt_variant *)dev_get_driver_data(dev);
|
||||||
|
|
||||||
|
wdt->freq = clk_get_rate(wdt->core_clk);
|
||||||
|
if (!wdt->freq) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err_get_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_get_freq:
|
||||||
|
reset_assert_bulk(wdt->rst);
|
||||||
|
err_reset:
|
||||||
|
starfive_wdt_disable_clock(wdt);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int starfive_wdt_of_to_plat(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct starfive_wdt_priv *wdt = dev_get_priv(dev);
|
||||||
|
|
||||||
|
wdt->base = (void *)dev_read_addr(dev);
|
||||||
|
if (!wdt->base)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
wdt->apb_clk = devm_clk_get(dev, "apb");
|
||||||
|
if (IS_ERR(wdt->apb_clk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
wdt->core_clk = devm_clk_get(dev, "core");
|
||||||
|
if (IS_ERR(wdt->core_clk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
wdt->rst = devm_reset_bulk_get(dev);
|
||||||
|
if (IS_ERR(wdt->rst))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id starfive_wdt_ids[] = {
|
||||||
|
{
|
||||||
|
.compatible = "starfive,jh7110-wdt",
|
||||||
|
.data = (ulong)&starfive_wdt_jh7110_variant
|
||||||
|
}, {
|
||||||
|
/* sentinel */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(starfive_wdt) = {
|
||||||
|
.name = "starfive_wdt",
|
||||||
|
.id = UCLASS_WDT,
|
||||||
|
.of_match = starfive_wdt_ids,
|
||||||
|
.priv_auto = sizeof(struct starfive_wdt_priv),
|
||||||
|
.probe = starfive_wdt_probe,
|
||||||
|
.of_to_plat = starfive_wdt_of_to_plat,
|
||||||
|
.ops = &starfive_wdt_ops,
|
||||||
|
};
|
|
@ -40,6 +40,7 @@
|
||||||
"kernel_comp_addr_r=0x88000000\0" \
|
"kernel_comp_addr_r=0x88000000\0" \
|
||||||
"kernel_comp_size=0x4000000\0" \
|
"kernel_comp_size=0x4000000\0" \
|
||||||
"fdt_addr_r=0x46000000\0" \
|
"fdt_addr_r=0x46000000\0" \
|
||||||
|
"fdtoverlay_addr_r=0x45800000\0" \
|
||||||
"scriptaddr=0x43900000\0" \
|
"scriptaddr=0x43900000\0" \
|
||||||
"pxefile_addr_r=0x45900000\0" \
|
"pxefile_addr_r=0x45900000\0" \
|
||||||
"ramdisk_addr_r=0x46100000\0" \
|
"ramdisk_addr_r=0x46100000\0" \
|
||||||
|
|
Loading…
Reference in a new issue