summaryrefslogtreecommitdiff
path: root/drivers/watchdog/sprd_wdt_sys.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/sprd_wdt_sys.h')
-rw-r--r--drivers/watchdog/sprd_wdt_sys.h149
1 files changed, 149 insertions, 0 deletions
diff --git a/drivers/watchdog/sprd_wdt_sys.h b/drivers/watchdog/sprd_wdt_sys.h
new file mode 100644
index 00000000..ec45766a
--- /dev/null
+++ b/drivers/watchdog/sprd_wdt_sys.h
@@ -0,0 +1,149 @@
+
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SPRD_WDT_SYS_H_
+#define _SPRD_WDT_SYS_H_
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <soc/sprd/adi.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/hardware.h>
+
+unsigned long ap_wdt_addr;
+unsigned long a7_wdt_addr;
+
+#define AP_WDG_LOAD_LOW (ap_wdt_addr + 0x00)
+#define AP_WDG_LOAD_HIGH (ap_wdt_addr + 0x04)
+#define AP_WDG_CTRL (ap_wdt_addr + 0x08)
+#define AP_WDG_INT_CLR (ap_wdt_addr + 0x0C)
+#define AP_WDG_INT_RAW (ap_wdt_addr + 0x10)
+#define AP_WDG_INT_MSK (ap_wdt_addr + 0x14)
+#define AP_WDG_CNT_LOW (ap_wdt_addr + 0x18)
+#define AP_WDG_CNT_HIGH (ap_wdt_addr + 0x1C)
+#define AP_WDG_LOCK (ap_wdt_addr + 0x20)
+
+#define CA7_WDG_LOAD_LOW (a7_wdt_addr + 0x00)
+#define CA7_WDG_LOAD_HIGH (a7_wdt_addr + 0x04)
+#define CA7_WDG_CTRL (a7_wdt_addr + 0x08)
+#define CA7_WDG_INT_CLR (a7_wdt_addr + 0x0C)
+#define CA7_WDG_INT_RAW (a7_wdt_addr + 0x10)
+#define CA7_WDG_INT_MSK (a7_wdt_addr + 0x14)
+#define CA7_WDG_CNT_LOW (a7_wdt_addr + 0x18)
+#define CA7_WDG_CNT_HIGH (a7_wdt_addr + 0x1C)
+#define CA7_WDG_LOCK (a7_wdt_addr + 0x20)
+#define CA7_WDG_IRQ_LOAD_LOW (a7_wdt_addr + 0x2c)
+#define CA7_WDG_IRQ_LOAD_HIGH (a7_wdt_addr + 0x30)
+
+#define AP_WDG_LOAD_TIMER_VALUE(value) \
+ do { \
+ uint32_t cnt = 0;\
+ sci_glb_write( AP_WDG_LOAD_HIGH, (uint16_t)(((value) >> 16 ) & 0xffff), -1UL); \
+ sci_glb_write( AP_WDG_LOAD_LOW , (uint16_t)((value) & 0xffff), -1UL ); \
+ while((sci_glb_read(AP_WDG_INT_RAW, -1UL) & WDG_LD_BUSY_BIT) && ( cnt < ANA_WDG_LOAD_TIMEOUT_NUM )) cnt++; \
+ } while (0)
+
+#define CA7_WDG_LOAD_TIMER_VALUE(margin, irq) \
+ do { \
+ uint32_t cnt = 0; \
+ sci_glb_write( CA7_WDG_LOAD_HIGH, (uint16_t)(((margin) >> 16 ) & 0xffff), -1UL); \
+ sci_glb_write( CA7_WDG_LOAD_LOW , (uint16_t)((margin) & 0xffff), -1UL ); \
+ sci_glb_write( CA7_WDG_IRQ_LOAD_HIGH, (uint16_t)(((irq) >> 16 ) & 0xffff), -1UL); \
+ sci_glb_write( CA7_WDG_IRQ_LOAD_LOW , (uint16_t)((irq) & 0xffff), -1UL ); \
+ while((sci_glb_read(CA7_WDG_INT_RAW, -1UL) & WDG_LD_BUSY_BIT) && ( cnt < ANA_WDG_LOAD_TIMEOUT_NUM )) cnt++; \
+ } while (0)
+
+
+#ifdef CONFIG_SC_INTERNAL_WATCHDOG
+static inline void FEED_ALL_WDG(int chip_margin, int ap_margin,
+ int ca7_margin, int ca7_irq_margin)
+{
+ AP_WDG_LOAD_TIMER_VALUE(ap_margin * WDG_CLK);
+ WDG_LOAD_TIMER_VALUE(chip_margin * WDG_CLK);
+ CA7_WDG_LOAD_TIMER_VALUE(ca7_margin * WDG_CLK, (ca7_margin - ca7_irq_margin) * WDG_CLK);
+}
+#else
+static inline void FEED_ALL_WDG(int chip_margin, int ap_margin,
+ int ca7_margin, int ca7_irq_margin) { }
+#endif
+
+#define ENABLE_ALL_WDG() \
+ do { \
+ sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
+ sci_glb_set(AP_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
+ sci_glb_set(CA7_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT | WDG_INT_EN_BIT); \
+ } while (0)
+
+#define DISABLE_ALL_WDG() \
+ do { \
+ sci_adi_clr(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
+ sci_glb_clr(AP_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
+ sci_glb_clr(CA7_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT | WDG_INT_EN_BIT); \
+ } while (0)
+
+#define WATCHDOG_THREAD_USER_BIT 0
+#define WATCHDOG_THREAD_KERNEL_BIT 1
+
+#define WATCHDOG_FEED_BY_USER_ST_BIT (0)
+#define WATCHDOG_FEED_BY_USER_BIT (1)
+#define WATCHDOG_FEED_BY_KERNEL_BIT (2)
+#define WATCHDOG_FEED_ENABLE_BIT (30)
+#define WATCHDOG_FEED_START_BIT (31)
+
+#define WATCHDOG_FEED_BY_KERNEL_THREAD ( \
+ (1 << WATCHDOG_FEED_BY_USER_BIT) | \
+ (1 << WATCHDOG_FEED_BY_KERNEL_BIT) \
+ )
+
+#define WATCHDOG_FEED_BY_USER_THREAD ( \
+ (1 << WATCHDOG_FEED_BY_USER_ST_BIT) \
+ )
+
+#define WATCHDOG_FEED_BY_THREAD \
+ (WATCHDOG_FEED_BY_KERNEL_THREAD | WATCHDOG_FEED_BY_USER_THREAD)
+
+#ifdef CONFIG_SC_INTERNAL_WATCHDOG
+static inline void watchdog_start(int chip_margin, int ap_margin,
+ int ca7_margin, int ca7_irq_margin)
+{
+ /* start the chip watchdog */
+ sci_adi_set(ANA_AGEN, AGEN_WDG_EN);
+ sci_adi_set(ANA_RTC_CLK_EN, AGEN_RTC_WDG_EN);
+ sci_adi_raw_write(WDG_LOCK, WDG_UNLOCK_KEY);
+ sci_adi_set(WDG_CTRL, WDG_NEW_VER_EN);
+ WDG_LOAD_TIMER_VALUE(chip_margin * WDG_CLK);
+ sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT);
+
+ /* start ap watchdog */
+ sci_glb_set(REG_AON_APB_APB_EB0, BIT_AP_WDG_EB);
+ sci_glb_set(REG_AON_APB_APB_RTC_EB, BIT_AP_WDG_RTC_EB);
+ sci_glb_write(AP_WDG_LOCK, WDG_UNLOCK_KEY, -1UL);
+ sci_glb_set(AP_WDG_CTRL, WDG_NEW_VER_EN);
+ AP_WDG_LOAD_TIMER_VALUE(ap_margin * WDG_CLK);
+ sci_glb_set(AP_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT);
+
+ /* start ca7 watchdog */
+ sci_glb_set(REG_AON_APB_APB_EB1, BIT_CA7_WDG_EB);
+ sci_glb_set(REG_AON_APB_APB_RTC_EB, BIT_CA7_WDG_RTC_EB);
+ sci_glb_write(CA7_WDG_LOCK, WDG_UNLOCK_KEY, -1UL);
+ sci_glb_set(CA7_WDG_CTRL, WDG_NEW_VER_EN);
+ CA7_WDG_LOAD_TIMER_VALUE(ca7_margin * WDG_CLK, (ca7_margin - ca7_irq_margin) * WDG_CLK);
+ sci_glb_set(CA7_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT | WDG_INT_EN_BIT);
+}
+
+#else
+static inline void watchdog_start(int chip_margin, int ap_margin,
+ int ca7_margin, int ca7_irq_margin) { }
+#endif
+#endif