@@ -26,6 +26,7 @@
#define TNETV107X_TPCC_BASE 0x01c00000
#define TNETV107X_TPTC0_BASE 0x01c10000
#define TNETV107X_TPTC1_BASE 0x01c10400
+#define TNETV107X_WDOG_BASE 0x08086700
/* TNETV107X specific EDMA3 information */
#define EDMA_TNETV107X_NUM_DMACH 64
@@ -103,11 +104,31 @@ static struct platform_device edma_device = {
.dev.platform_data = edma_info,
};
+static struct resource wdt_resources[] = {
+ {
+ .start = TNETV107X_WDOG_BASE,
+ .end = TNETV107X_WDOG_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device tnetv107x_wdt_device = {
+ .name = "watchdog",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(wdt_resources),
+ .resource = wdt_resources,
+};
+
void __init tnetv107x_edma_init(void)
{
platform_device_register(&edma_device);
}
+void __init tnetv107x_watchdog_init(void)
+{
+ platform_device_register(&tnetv107x_wdt_device);
+}
+
void __init tnetv107x_serial_init(struct plat_serial8250_port* ports)
{
int i;
@@ -16,8 +16,10 @@
extern struct platform_device davinci_wdt_device;
extern struct platform_device da8xx_wdt_device;
+extern struct platform_device tnetv107x_wdt_device;
extern void davinci_watchdog_reset(struct platform_device *);
+extern void tnetv107x_watchdog_reset(struct platform_device *);
static inline void arch_idle(void)
{
@@ -31,6 +33,9 @@ static inline void arch_reset(char mode, const char *cmd)
if (cpu_class_is_da8xx())
davinci_watchdog_reset(&da8xx_wdt_device);
+
+ if (cpu_class_is_tnetv107x())
+ tnetv107x_watchdog_reset(&tnetv107x_wdt_device);
}
#endif /* __ASM_ARCH_SYSTEM_H */
@@ -59,6 +59,7 @@
extern void __init tnetv107x_init(void);
extern void __init tnetv107x_gpio_init(void);
extern void __init tnetv107x_edma_init(void);
+extern void __init tnetv107x_watchdog_init(void);
extern void __init tnetv107x_irq_init(void);
extern void __init tnetv107x_serial_init(struct plat_serial8250_port* ports);
#endif
@@ -81,6 +81,18 @@ struct sspll_regs {
u32 diag;
};
+/* Watchdog Timer Registers */
+struct wdt_regs {
+ u32 kick_lock;
+ u32 kick;
+ u32 change_lock;
+ u32 change ;
+ u32 disable_lock;
+ u32 disable;
+ u32 prescale_lock;
+ u32 prescale;
+};
+
static struct clk_ctrl_regs __iomem *clk_ctrl_regs;
static struct sspll_regs __iomem *sspll_regs[N_PLLS];
@@ -1173,3 +1185,98 @@ static unsigned long clk_sspll_recalc(struct clk *clk)
return ret;
}
+
+static int tnetv107x_wdt_set_period(struct wdt_regs __iomem *regs,
+ unsigned long msec, unsigned long refclk)
+{
+ unsigned long change;
+ unsigned long count;
+ unsigned long prescale = 1;
+
+ refclk /= 1000;
+
+ /* compute prescale and change reg values */
+ count = refclk * msec;
+
+ if (count > 0xffff) {
+ change = count / 0xffff + 1;
+ prescale = count / change;
+ } else {
+ change = count;
+ }
+
+ __raw_writel(0x5a5a, ®s->prescale_lock);
+ if ((__raw_readl(®s->prescale_lock) & 0x3) != 1)
+ return -EIO;
+
+ __raw_writel(0xa5a5, ®s->prescale_lock);
+ if ((__raw_readl(®s->prescale_lock) & 0x3) != 3)
+ return -EIO;
+
+ __raw_writel(prescale - 1, ®s->prescale);
+
+ __raw_writel(0x6666, ®s->change_lock);
+ if ((__raw_readl(®s->change_lock) & 0x3) != 1)
+ return -EIO;
+
+ __raw_writel(0xbbbb, ®s->change_lock);
+ if ((__raw_readl(®s->change_lock) & 0x3) != 3)
+ return -EIO;
+
+ __raw_writel(change, ®s->change);
+ return 0;
+}
+
+static int tnetv107x_wdt_ctrl(struct wdt_regs __iomem *regs, int enable)
+{
+
+ enable = enable ? 1 : 0;
+
+ __raw_writel(0x7777, ®s->disable_lock);
+ if ((__raw_readl(®s->disable_lock) & 0x3) != 1)
+ return -EIO;
+
+ __raw_writel(0xcccc, ®s->disable_lock);
+ if ((__raw_readl(®s->disable_lock) & 0x3) != 2)
+ return -EIO;
+
+ __raw_writel(0xdddd, ®s->disable_lock);
+ if ((__raw_readl(®s->disable_lock) & 0x3) != 3)
+ return -EIO;
+
+ __raw_writel(enable, ®s->disable);
+ return 0;
+}
+
+static int tnetv107x_wdt_kick(struct wdt_regs __iomem *regs)
+{
+ __raw_writel(0x5555, ®s->kick_lock);
+ if ((__raw_readl(®s->kick_lock) & 0x3) != 1)
+ return -EIO;
+
+ __raw_writel(0xaaaa, ®s->kick_lock);
+ if ((__raw_readl(®s->kick_lock) & 0x3) != 3)
+ return -EIO;
+
+ __raw_writel(1, ®s->kick);
+ return 0;
+}
+
+void tnetv107x_watchdog_reset(struct platform_device *pdev)
+{
+ struct wdt_regs __iomem *regs;
+ struct clk *wdt_clk;
+ unsigned long wdt_clk_rate;
+
+ regs = ioremap(pdev->resource[0].start, SZ_4K);
+ wdt_clk = clk_get(&pdev->dev, NULL);
+ if (WARN_ON(IS_ERR(wdt_clk)))
+ return;
+ clk_enable(wdt_clk);
+ wdt_clk_rate = clk_get_rate(wdt_clk);
+
+ tnetv107x_wdt_ctrl(regs, 0);
+ tnetv107x_wdt_set_period(regs, 1, wdt_clk_rate);
+ tnetv107x_wdt_ctrl(regs, 1);
+ tnetv107x_wdt_kick(regs);
+}