1 /* 2 * OMAP2+ MPU WD_TIMER-specific code 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/io.h> 12 #include <linux/err.h> 13 14 #include <plat/omap_hwmod.h> 15 16 #include "wd_timer.h" 17 #include "common.h" 18 19 /* 20 * In order to avoid any assumptions from bootloader regarding WDT 21 * settings, WDT module is reset during init. This enables the watchdog 22 * timer. Hence it is required to disable the watchdog after the WDT reset 23 * during init. Otherwise the system would reboot as per the default 24 * watchdog timer registers settings. 25 */ 26 #define OMAP_WDT_WPS 0x34 27 #define OMAP_WDT_SPR 0x48 28 29 /* Maximum microseconds to wait for OMAP module to softreset */ 30 #define MAX_MODULE_SOFTRESET_WAIT 10000 31 32 int omap2_wd_timer_disable(struct omap_hwmod *oh) 33 { 34 void __iomem *base; 35 36 if (!oh) { 37 pr_err("%s: Could not look up wdtimer_hwmod\n", __func__); 38 return -EINVAL; 39 } 40 41 base = omap_hwmod_get_mpu_rt_va(oh); 42 if (!base) { 43 pr_err("%s: Could not get the base address for %s\n", 44 oh->name, __func__); 45 return -EINVAL; 46 } 47 48 /* sequence required to disable watchdog */ 49 __raw_writel(0xAAAA, base + OMAP_WDT_SPR); 50 while (__raw_readl(base + OMAP_WDT_WPS) & 0x10) 51 cpu_relax(); 52 53 __raw_writel(0x5555, base + OMAP_WDT_SPR); 54 while (__raw_readl(base + OMAP_WDT_WPS) & 0x10) 55 cpu_relax(); 56 57 return 0; 58 } 59 60 /** 61 * omap2_wdtimer_reset - reset and disable the WDTIMER IP block 62 * @oh: struct omap_hwmod * 63 * 64 * After the WDTIMER IP blocks are reset on OMAP2/3, we must also take 65 * care to execute the special watchdog disable sequence. This is 66 * because the watchdog is re-armed upon OCP softreset. (On OMAP4, 67 * this behavior was apparently changed and the watchdog is no longer 68 * re-armed after an OCP soft-reset.) Returns -ETIMEDOUT if the reset 69 * did not complete, or 0 upon success. 70 * 71 * XXX Most of this code should be moved to the omap_hwmod.c layer 72 * during a normal merge window. omap_hwmod_softreset() should be 73 * renamed to omap_hwmod_set_ocp_softreset(), and omap_hwmod_softreset() 74 * should call the hwmod _ocp_softreset() code. 75 */ 76 int omap2_wd_timer_reset(struct omap_hwmod *oh) 77 { 78 int c = 0; 79 80 /* Write to the SOFTRESET bit */ 81 omap_hwmod_softreset(oh); 82 83 /* Poll on RESETDONE bit */ 84 omap_test_timeout((omap_hwmod_read(oh, 85 oh->class->sysc->syss_offs) 86 & SYSS_RESETDONE_MASK), 87 MAX_MODULE_SOFTRESET_WAIT, c); 88 89 if (oh->class->sysc->srst_udelay) 90 udelay(oh->class->sysc->srst_udelay); 91 92 if (c == MAX_MODULE_SOFTRESET_WAIT) 93 pr_warning("%s: %s: softreset failed (waited %d usec)\n", 94 __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT); 95 else 96 pr_debug("%s: %s: softreset in %d usec\n", __func__, 97 oh->name, c); 98 99 return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 100 omap2_wd_timer_disable(oh); 101 } 102