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:

committed by
Jason Cooper

parent
e97662e1e2
commit
868eb61602
@@ -3,7 +3,9 @@
|
|||||||
Required Properties:
|
Required Properties:
|
||||||
|
|
||||||
- Compatibility : "marvell,orion-wdt"
|
- 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:
|
Optional properties:
|
||||||
|
|
||||||
@@ -14,7 +16,7 @@ Example:
|
|||||||
|
|
||||||
wdt@20300 {
|
wdt@20300 {
|
||||||
compatible = "marvell,orion-wdt";
|
compatible = "marvell,orion-wdt";
|
||||||
reg = <0x20300 0x28>;
|
reg = <0x20300 0x28>, <0x20108 0x4>;
|
||||||
interrupts = <3>;
|
interrupts = <3>;
|
||||||
timeout-sec = <10>;
|
timeout-sec = <10>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#define CPU_CTRL_PCIE1_LINK 0x00000008
|
#define CPU_CTRL_PCIE1_LINK 0x00000008
|
||||||
|
|
||||||
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
||||||
|
#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
|
||||||
#define SOFT_RESET_OUT_EN 0x00000004
|
#define SOFT_RESET_OUT_EN 0x00000004
|
||||||
|
|
||||||
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#define CPU_RESET 0x00000002
|
#define CPU_RESET 0x00000002
|
||||||
|
|
||||||
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
||||||
|
#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
|
||||||
#define SOFT_RESET_OUT_EN 0x00000004
|
#define SOFT_RESET_OUT_EN 0x00000004
|
||||||
|
|
||||||
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#define L2_WRITETHROUGH 0x00020000
|
#define L2_WRITETHROUGH 0x00020000
|
||||||
|
|
||||||
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
|
||||||
|
#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
|
||||||
#define SOFT_RESET_OUT_EN 0x00000004
|
#define SOFT_RESET_OUT_EN 0x00000004
|
||||||
|
|
||||||
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104)
|
#define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104)
|
||||||
|
|
||||||
#define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108)
|
#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)
|
#define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c)
|
||||||
|
|
||||||
|
@@ -595,14 +595,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Watchdog
|
* Watchdog
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
static struct resource orion_wdt_resource =
|
static struct resource orion_wdt_resource[] = {
|
||||||
DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
|
DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
|
||||||
|
DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_device orion_wdt_device = {
|
static struct platform_device orion_wdt_device = {
|
||||||
.name = "orion_wdt",
|
.name = "orion_wdt",
|
||||||
.id = -1,
|
.id = -1,
|
||||||
.num_resources = 1,
|
.num_resources = ARRAY_SIZE(orion_wdt_resource),
|
||||||
.resource = &orion_wdt_resource,
|
.resource = orion_wdt_resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
void __init orion_wdt_init(void)
|
void __init orion_wdt_init(void)
|
||||||
|
@@ -26,6 +26,12 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <mach/bridge-regs.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.
|
* Watchdog timer block registers.
|
||||||
*/
|
*/
|
||||||
@@ -44,6 +50,7 @@ static unsigned int wdt_max_duration; /* (seconds) */
|
|||||||
static struct clk *clk;
|
static struct clk *clk;
|
||||||
static unsigned int wdt_tclk;
|
static unsigned int wdt_tclk;
|
||||||
static void __iomem *wdt_reg;
|
static void __iomem *wdt_reg;
|
||||||
|
static void __iomem *wdt_rstout;
|
||||||
|
|
||||||
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
|
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);
|
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
|
||||||
|
|
||||||
/* Enable reset on watchdog */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
|
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
|
||||||
{
|
{
|
||||||
/* Disable reset on watchdog */
|
/* 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 */
|
/* Disable watchdog timer */
|
||||||
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
|
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
|
||||||
@@ -82,7 +89,7 @@ static int orion_wdt_enabled(void)
|
|||||||
{
|
{
|
||||||
bool enabled, running;
|
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;
|
running = readl(wdt_reg + TIMER_CTRL) & WDT_EN;
|
||||||
|
|
||||||
return enabled && running;
|
return enabled && running;
|
||||||
@@ -126,6 +133,33 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
|
|||||||
return IRQ_HANDLED;
|
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)
|
static int orion_wdt_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
@@ -153,6 +187,13 @@ static int orion_wdt_probe(struct platform_device *pdev)
|
|||||||
goto disable_clk;
|
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;
|
wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
|
||||||
|
|
||||||
orion_wdt.timeout = wdt_max_duration;
|
orion_wdt.timeout = wdt_max_duration;
|
||||||
|
Reference in New Issue
Block a user