watchdog: orion: Make RSTOUT register a separate resource
In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration. To prevent a compatibility break, this commit adds a fallback to a hardcoded RSTOUT address. Reviewed-by: Guenter Roeck <linux@roeck-us.net> Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Tested-by: Willy Tarreau <w@1wt.eu> Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Acked-by: Wim Van Sebroeck <wim@iguana.be> Tested-By: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
This commit is contained in:
Родитель
e97662e1e2
Коммит
868eb61602
|
@ -3,7 +3,9 @@
|
|||
Required Properties:
|
||||
|
||||
- Compatibility : "marvell,orion-wdt"
|
||||
- reg : Address of the timer registers
|
||||
- reg : Should contain two entries: first one with the
|
||||
timer control address, second one with the
|
||||
rstout enable address.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
@ -14,7 +16,7 @@ Example:
|
|||
|
||||
wdt@20300 {
|
||||
compatible = "marvell,orion-wdt";
|
||||
reg = <0x20300 0x28>;
|
||||
reg = <0x20300 0x28>, <0x20108 0x4>;
|
||||
interrupts = <3>;
|
||||
timeout-sec = <10>;
|
||||
status = "okay";
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define CPU_CTRL_PCIE1_LINK 0x00000008
|
||||
|
||||
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
||||
#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
|
||||
#define SOFT_RESET_OUT_EN 0x00000004
|
||||
|
||||
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define CPU_RESET 0x00000002
|
||||
|
||||
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
||||
#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
|
||||
#define SOFT_RESET_OUT_EN 0x00000004
|
||||
|
||||
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define L2_WRITETHROUGH 0x00020000
|
||||
|
||||
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
||||
#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
|
||||
#define SOFT_RESET_OUT_EN 0x00000004
|
||||
|
||||
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104)
|
||||
|
||||
#define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108)
|
||||
#define RSTOUTn_MASK_PHYS (ORION5X_BRIDGE_PHYS_BASE + 0x108)
|
||||
|
||||
#define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c)
|
||||
|
||||
|
|
|
@ -595,14 +595,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
|
|||
/*****************************************************************************
|
||||
* Watchdog
|
||||
****************************************************************************/
|
||||
static struct resource orion_wdt_resource =
|
||||
DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
|
||||
static struct resource orion_wdt_resource[] = {
|
||||
DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
|
||||
DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
|
||||
};
|
||||
|
||||
static struct platform_device orion_wdt_device = {
|
||||
.name = "orion_wdt",
|
||||
.id = -1,
|
||||
.num_resources = 1,
|
||||
.resource = &orion_wdt_resource,
|
||||
.num_resources = ARRAY_SIZE(orion_wdt_resource),
|
||||
.resource = orion_wdt_resource,
|
||||
};
|
||||
|
||||
void __init orion_wdt_init(void)
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
#include <linux/of.h>
|
||||
#include <mach/bridge-regs.h>
|
||||
|
||||
/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
|
||||
#define ORION_RSTOUT_MASK_OFFSET 0x20108
|
||||
|
||||
/* Internal registers can be configured at any 1 MiB aligned address */
|
||||
#define INTERNAL_REGS_MASK ~(SZ_1M - 1)
|
||||
|
||||
/*
|
||||
* Watchdog timer block registers.
|
||||
*/
|
||||
|
@ -44,6 +50,7 @@ static unsigned int wdt_max_duration; /* (seconds) */
|
|||
static struct clk *clk;
|
||||
static unsigned int wdt_tclk;
|
||||
static void __iomem *wdt_reg;
|
||||
static void __iomem *wdt_rstout;
|
||||
|
||||
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
|
@ -64,14 +71,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
|
|||
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
|
||||
|
||||
/* Enable reset on watchdog */
|
||||
atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
|
||||
atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
/* Disable reset on watchdog */
|
||||
atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
|
||||
atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
|
||||
|
||||
/* Disable watchdog timer */
|
||||
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
|
||||
|
@ -82,7 +89,7 @@ static int orion_wdt_enabled(void)
|
|||
{
|
||||
bool enabled, running;
|
||||
|
||||
enabled = readl(RSTOUTn_MASK) & WDT_RESET_OUT_EN;
|
||||
enabled = readl(wdt_rstout) & WDT_RESET_OUT_EN;
|
||||
running = readl(wdt_reg + TIMER_CTRL) & WDT_EN;
|
||||
|
||||
return enabled && running;
|
||||
|
@ -126,6 +133,33 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* The original devicetree binding for this driver specified only
|
||||
* one memory resource, so in order to keep DT backwards compatibility
|
||||
* we try to fallback to a hardcoded register address, if the resource
|
||||
* is missing from the devicetree.
|
||||
*/
|
||||
static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
|
||||
phys_addr_t internal_regs)
|
||||
{
|
||||
struct resource *res;
|
||||
phys_addr_t rstout;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (res)
|
||||
return devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
|
||||
/* This workaround works only for "orion-wdt", DT-enabled */
|
||||
if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt"))
|
||||
return NULL;
|
||||
|
||||
rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
|
||||
|
||||
WARN(1, FW_BUG "falling back to harcoded RSTOUT reg 0x%x\n", rstout);
|
||||
return devm_ioremap(&pdev->dev, rstout, 0x4);
|
||||
}
|
||||
|
||||
static int orion_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
@ -153,6 +187,13 @@ static int orion_wdt_probe(struct platform_device *pdev)
|
|||
goto disable_clk;
|
||||
}
|
||||
|
||||
wdt_rstout = orion_wdt_ioremap_rstout(pdev, res->start &
|
||||
INTERNAL_REGS_MASK);
|
||||
if (!wdt_rstout) {
|
||||
ret = -ENODEV;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
|
||||
|
||||
orion_wdt.timeout = wdt_max_duration;
|
||||
|
|
Загрузка…
Ссылка в новой задаче