u-boot/drivers/watchdog/orion_wdt.c
Simon Glass 8b85dfc675 dm: Avoid accessing seq directly
At present various drivers etc. access the device's 'seq' member directly.
This makes it harder to change the meaning of that member. Change access
to go through a function instead.

The drivers/i2c/lpc32xx_i2c.c file is left unchanged for now.

Signed-off-by: Simon Glass <sjg@chromium.org>
2020-12-18 20:32:21 -07:00

192 lines
4.2 KiB
C

/*
* drivers/watchdog/orion_wdt.c
*
* Watchdog driver for Orion/Kirkwood processors
*
* Authors: Tomas Hlavacek <tmshlvck@gmail.com>
* Sylver Bruneau <sylver.bruneau@googlemail.com>
* Marek Behun <marek.behun@nic.cz>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <common.h>
#include <dm.h>
#include <clk.h>
#include <log.h>
#include <wdt.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
DECLARE_GLOBAL_DATA_PTR;
struct orion_wdt_priv {
void __iomem *reg;
int wdt_counter_offset;
void __iomem *rstout;
void __iomem *rstout_mask;
u32 timeout;
unsigned long clk_rate;
struct clk clk;
};
#define RSTOUT_ENABLE_BIT BIT(8)
#define RSTOUT_MASK_BIT BIT(10)
#define WDT_ENABLE_BIT BIT(8)
#define TIMER_CTRL 0x0000
#define TIMER_A370_STATUS 0x04
#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
#define WDT_A370_EXPIRED BIT(31)
static int orion_wdt_reset(struct udevice *dev)
{
struct orion_wdt_priv *priv = dev_get_priv(dev);
/* Reload watchdog duration */
writel(priv->clk_rate * priv->timeout,
priv->reg + priv->wdt_counter_offset);
return 0;
}
static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{
struct orion_wdt_priv *priv = dev_get_priv(dev);
u32 reg;
priv->timeout = DIV_ROUND_UP(timeout_ms, 1000);
/* Enable the fixed watchdog clock input */
reg = readl(priv->reg + TIMER_CTRL);
reg |= WDT_AXP_FIXED_ENABLE_BIT;
writel(reg, priv->reg + TIMER_CTRL);
/* Set watchdog duration */
writel(priv->clk_rate * priv->timeout,
priv->reg + priv->wdt_counter_offset);
/* Clear the watchdog expiration bit */
reg = readl(priv->reg + TIMER_A370_STATUS);
reg &= ~WDT_A370_EXPIRED;
writel(reg, priv->reg + TIMER_A370_STATUS);
/* Enable watchdog timer */
reg = readl(priv->reg + TIMER_CTRL);
reg |= WDT_ENABLE_BIT;
writel(reg, priv->reg + TIMER_CTRL);
/* Enable reset on watchdog */
reg = readl(priv->rstout);
reg |= RSTOUT_ENABLE_BIT;
writel(reg, priv->rstout);
reg = readl(priv->rstout_mask);
reg &= ~RSTOUT_MASK_BIT;
writel(reg, priv->rstout_mask);
return 0;
}
static int orion_wdt_stop(struct udevice *dev)
{
struct orion_wdt_priv *priv = dev_get_priv(dev);
u32 reg;
/* Disable reset on watchdog */
reg = readl(priv->rstout_mask);
reg |= RSTOUT_MASK_BIT;
writel(reg, priv->rstout_mask);
reg = readl(priv->rstout);
reg &= ~RSTOUT_ENABLE_BIT;
writel(reg, priv->rstout);
/* Disable watchdog timer */
reg = readl(priv->reg + TIMER_CTRL);
reg &= ~WDT_ENABLE_BIT;
writel(reg, priv->reg + TIMER_CTRL);
return 0;
}
static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
void __iomem **reg, int *offset)
{
fdt_addr_t addr;
fdt_size_t off;
addr = devfdt_get_addr_size_index(dev, index, &off);
if (addr == FDT_ADDR_T_NONE)
return false;
*reg = (void __iomem *) addr;
if (offset)
*offset = off;
return true;
}
static int orion_wdt_of_to_plat(struct udevice *dev)
{
struct orion_wdt_priv *priv = dev_get_priv(dev);
if (!save_reg_from_ofdata(dev, 0, &priv->reg,
&priv->wdt_counter_offset))
goto err;
if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
goto err;
if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
goto err;
return 0;
err:
debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
return -ENXIO;
}
static int orion_wdt_probe(struct udevice *dev)
{
struct orion_wdt_priv *priv = dev_get_priv(dev);
int ret;
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
orion_wdt_stop(dev);
ret = clk_get_by_name(dev, "fixed", &priv->clk);
if (!ret)
priv->clk_rate = clk_get_rate(&priv->clk);
else
priv->clk_rate = 25000000;
return 0;
}
static const struct wdt_ops orion_wdt_ops = {
.start = orion_wdt_start,
.reset = orion_wdt_reset,
.stop = orion_wdt_stop,
};
static const struct udevice_id orion_wdt_ids[] = {
{ .compatible = "marvell,armada-380-wdt" },
{}
};
U_BOOT_DRIVER(orion_wdt) = {
.name = "orion_wdt",
.id = UCLASS_WDT,
.of_match = orion_wdt_ids,
.probe = orion_wdt_probe,
.priv_auto = sizeof(struct orion_wdt_priv),
.of_to_plat = orion_wdt_of_to_plat,
.ops = &orion_wdt_ops,
};