From patchwork Wed Mar 31 03:44:20 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Guzman Lugo, Fernando" X-Patchwork-Id: 89877 X-Patchwork-Delegate: omar.ramirez@ti.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2V3ia1P011087 for ; Wed, 31 Mar 2010 03:44:36 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756233Ab0CaDo3 (ORCPT ); Tue, 30 Mar 2010 23:44:29 -0400 Received: from comal.ext.ti.com ([198.47.26.152]:50800 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932100Ab0CaDo2 convert rfc822-to-8bit (ORCPT ); Tue, 30 Mar 2010 23:44:28 -0400 Received: from dlep34.itg.ti.com ([157.170.170.115]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id o2V3iMC1025842 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 30 Mar 2010 22:44:22 -0500 Received: from dlep26.itg.ti.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id o2V3iM3o018739; Tue, 30 Mar 2010 22:44:22 -0500 (CDT) Received: from dlee73.ent.ti.com (localhost [127.0.0.1]) by dlep26.itg.ti.com (8.13.8/8.13.8) with ESMTP id o2V3iMwG028030; Tue, 30 Mar 2010 22:44:22 -0500 (CDT) Received: from dlee06.ent.ti.com ([157.170.170.11]) by dlee73.ent.ti.com ([157.170.170.88]) with mapi; Tue, 30 Mar 2010 22:44:22 -0500 From: "Guzman Lugo, Fernando" To: "linux-omap@vger.kernel.org" CC: Hiroshi DOYU , Ameya Palande , "felipe.contreras@nokia.com" Date: Tue, 30 Mar 2010 22:44:20 -0500 Subject: DSPBRIDGE: Implement WDT3 to notify DSP hangs Thread-Topic: DSPBRIDGE: Implement WDT3 to notify DSP hangs Thread-Index: AcrQhHKNGV5Xct27Sb6avtVt6+9fHQ== Message-ID: <496565EC904933469F292DDA3F1663E602CAEAB813@dlee06.ent.ti.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 31 Mar 2010 03:44:36 +0000 (UTC) diff --git a/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h b/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h index f394ba6..f8bdc93 100644 --- a/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h +++ b/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h @@ -99,7 +99,14 @@ struct shm { struct opp_rqst_struct opp_request; /* load monitor information structure */ struct load_mon_struct load_mon_info; +#ifdef CONFIG_BRIDGE_WDT3 + /* Flag for WDT enable/disable F/I clocks */ + u32 wdt_setclocks; + u32 wdt_overflow; /* WDT overflow time */ + char dummy[176]; /* padding to 256 byte boundary */ +#else char dummy[184]; /* padding to 256 byte boundary */ +#endif u32 shm_dbg_var[64]; /* shared memory debug variables */ }; diff --git a/arch/arm/plat-omap/include/dspbridge/cfgdefs.h b/arch/arm/plat-omap/include/dspbridge/cfgdefs.h index bd24611..a71fc7b 100644 --- a/arch/arm/plat-omap/include/dspbridge/cfgdefs.h +++ b/arch/arm/plat-omap/include/dspbridge/cfgdefs.h @@ -70,7 +70,6 @@ struct cfg_hostres { void __iomem *dw_per_base; u32 dw_per_pm_base; u32 dw_core_pm_base; - void __iomem *dw_wd_timer_dsp_base; void __iomem *dw_dmmu_base; void __iomem *dw_sys_ctrl_base; }; diff --git a/arch/arm/plat-omap/include/dspbridge/dbdefs.h b/arch/arm/plat-omap/include/dspbridge/dbdefs.h index 7fcc4aa..b5d3097 100644 --- a/arch/arm/plat-omap/include/dspbridge/dbdefs.h +++ b/arch/arm/plat-omap/include/dspbridge/dbdefs.h @@ -53,6 +53,7 @@ #define DSP_SYSERROR 0x00000020 #define DSP_EXCEPTIONABORT 0x00000300 #define DSP_PWRERROR 0x00000080 +#define DSP_WDTOVERFLOW 0x00000040 /* IVA exception events (IVA MMU fault) */ #define IVA_MMUFAULT 0x00000040 @@ -124,6 +125,7 @@ typedef u32 dsp_status; /* API return code type */ DSP_STREAMIOCOMPLETION | \ DSP_MMUFAULT | \ DSP_SYSERROR | \ + DSP_WDTOVERFLOW | \ DSP_PWRERROR)) && \ !((x) & ~(DSP_PROCESSORSTATECHANGE | \ DSP_PROCESSORATTACH | \ @@ -134,6 +136,7 @@ typedef u32 dsp_status; /* API return code type */ DSP_STREAMIOCOMPLETION | \ DSP_MMUFAULT | \ DSP_SYSERROR | \ + DSP_WDTOVERFLOW | \ DSP_PWRERROR)))) #define IS_VALID_NODE_EVENT(x) (((x) == 0) || \ diff --git a/arch/arm/plat-omap/include/dspbridge/wdt.h b/arch/arm/plat-omap/include/dspbridge/wdt.h new file mode 100644 index 0000000..4c00ba5 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wdt.h @@ -0,0 +1,79 @@ +/* + * wdt.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * IO dispatcher for a shared memory channel driver. + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef __DSP_WDT3_H_ +#define __DSP_WDT3_H_ + +/* WDT defines */ +#define OMAP3_WDT3_ISR_OFFSET 0x0018 + + +/** + * struct dsp_wdt_setting - the basic dsp_wdt_setting structure + * @reg_base: pointer to the base of the wdt registers + * @sm_wdt: pointer to flags in shared memory + * @wdt3_tasklet tasklet to manage wdt event + * @fclk handle to wdt3 functional clock + * @iclk handle to wdt3 interface clock + * + * This struct is used in the function to manage wdt3. + */ + +struct dsp_wdt_setting { + void __iomem *reg_base; + struct shm *sm_wdt; + struct tasklet_struct wdt3_tasklet; + struct clk *fclk; + struct clk *iclk; +}; + +/** + * dsp_wdt_init() - initialize wdt3 module. + * + * This function initilize to wdt3 module, so that + * other wdt3 function can be used. + */ +int dsp_wdt_init(void); + +/** + * dsp_wdt_exit() - initialize wdt3 module. + * + * This function frees all resources allocated for wdt3 module. + */ +void dsp_wdt_exit(void); + +/** + * dsp_wdt_enable() - enable/disable wdt3 + * @enable: bool value to enable/disable wdt3 + * + * This function enables or disables wdt3 base on @enable value. + * + */ +void dsp_wdt_enable(bool enable); + +/** + * dsp_wdt_sm_set() - store pointer to the share memory + * @data: pointer to dspbridge share memory + * + * This function is used to pass a valid pointer to share memory, + * so that the flags can be set in order DSP side can read them. + * + */ +void dsp_wdt_sm_set(void *data); + +#endif + diff --git a/arch/arm/plat-omap/include/plat/omap34xx.h b/arch/arm/plat-omap/include/plat/omap34xx.h index 077f059..dded9cc 100644 --- a/arch/arm/plat-omap/include/plat/omap34xx.h +++ b/arch/arm/plat-omap/include/plat/omap34xx.h @@ -82,5 +82,8 @@ #define OMAP34XX_MAILBOX_BASE (L4_34XX_BASE + 0x94000) +#define OMAP34XX_WDT3_BASE (L4_PER_34XX_BASE + 0x30000) + + #endif /* __ASM_ARCH_OMAP34XX_H */ diff --git a/drivers/dsp/bridge/Kconfig b/drivers/dsp/bridge/Kconfig index 23b2afc..fcd035c 100644 --- a/drivers/dsp/bridge/Kconfig +++ b/drivers/dsp/bridge/Kconfig @@ -45,6 +45,23 @@ config BRIDGE_RECOVERY In case of DSP fatal error, BRIDGE driver will try to recover itself. +config BRIDGE_WDT3 + bool "Enable WDT3 interruptions" + depends on MPU_BRIDGE + default n + help + WTD3 is managed by DSP and once it is enabled, DSP side bridge is in + charge of refreshing the timer before overflow, if the DSP hangs MPU + will caught the interrupt and try to recover DSP. + +config WDT_TIMEOUT + int "DSP watchdog timer timeout (in secs)" + depends on BRIDGE_WDT3 + default 5 + help + Watchdog timer timeout value, after that time if the watchdog timer + counter is not reset the wdt overflow interrupt will be triggered + comment "Bridge Notifications" depends on MPU_BRIDGE diff --git a/drivers/dsp/bridge/Makefile b/drivers/dsp/bridge/Makefile index 2b4f92c..ce85ba6 100644 --- a/drivers/dsp/bridge/Makefile +++ b/drivers/dsp/bridge/Makefile @@ -7,7 +7,7 @@ libservices = services/mem.o services/sync.o \ services/services.o libwmd = wmd/chnl_sm.o wmd/msg_sm.o wmd/io_sm.o wmd/tiomap3430.o \ wmd/tiomap3430_pwr.o wmd/tiomap_io.o \ - wmd/mmu_fault.o wmd/ue_deh.o + wmd/mmu_fault.o wmd/ue_deh.o wmd/wdt.o libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/wcd.o \ pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o librmgr = rmgr/dbdcd.o rmgr/disp.o rmgr/drv.o rmgr/mgr.o rmgr/node.o \ diff --git a/drivers/dsp/bridge/rmgr/drv.c b/drivers/dsp/bridge/rmgr/drv.c index 98f9b78..fe9ae06 100644 --- a/drivers/dsp/bridge/rmgr/drv.c +++ b/drivers/dsp/bridge/rmgr/drv.c @@ -904,8 +904,6 @@ static dsp_status request_bridge_resources(u32 dw_context, s32 bRequest) iounmap((void *)host_res->dw_mem_base[3]); if (host_res->dw_mem_base[4]) iounmap((void *)host_res->dw_mem_base[4]); - if (host_res->dw_wd_timer_dsp_base) - iounmap(host_res->dw_wd_timer_dsp_base); if (host_res->dw_dmmu_base) iounmap(host_res->dw_dmmu_base); if (host_res->dw_per_base) @@ -923,7 +921,6 @@ static dsp_status request_bridge_resources(u32 dw_context, s32 bRequest) host_res->dw_mem_base[2] = (u32) NULL; host_res->dw_mem_base[3] = (u32) NULL; host_res->dw_mem_base[4] = (u32) NULL; - host_res->dw_wd_timer_dsp_base = NULL; host_res->dw_dmmu_base = NULL; host_res->dw_sys_ctrl_base = NULL; @@ -956,8 +953,6 @@ static dsp_status request_bridge_resources(u32 dw_context, s32 bRequest) host_res->dw_mem_base[3]); dev_dbg(bridge, "dw_prm_base %p\n", host_res->dw_prm_base); dev_dbg(bridge, "dw_cm_base %p\n", host_res->dw_cm_base); - dev_dbg(bridge, "dw_wd_timer_dsp_base %p\n", - host_res->dw_wd_timer_dsp_base); dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base); /* for 24xx base port is not mapping the mamory for DSP @@ -1032,7 +1027,6 @@ static dsp_status request_bridge_resources_dsp(u32 dw_context, s32 bRequest) OMAP_CORE_PRM_SIZE); host_res->dw_dmmu_base = ioremap(OMAP_DMMU_BASE, OMAP_DMMU_SIZE); - host_res->dw_wd_timer_dsp_base = NULL; dev_dbg(bridge, "dw_mem_base[0] 0x%x\n", host_res->dw_mem_base[0]); @@ -1046,8 +1040,6 @@ static dsp_status request_bridge_resources_dsp(u32 dw_context, s32 bRequest) host_res->dw_mem_base[4]); dev_dbg(bridge, "dw_prm_base %p\n", host_res->dw_prm_base); dev_dbg(bridge, "dw_cm_base %p\n", host_res->dw_cm_base); - dev_dbg(bridge, "dw_wd_timer_dsp_base %p\n", - host_res->dw_wd_timer_dsp_base); dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base); dw_buff_size = sizeof(shm_size); status = diff --git a/drivers/dsp/bridge/rmgr/proc.c b/drivers/dsp/bridge/rmgr/proc.c index 1556285..2892041 100644 --- a/drivers/dsp/bridge/rmgr/proc.c +++ b/drivers/dsp/bridge/rmgr/proc.c @@ -1149,8 +1149,9 @@ dsp_status proc_register_notify(void *hprocessor, u32 event_mask, } /* Check if event mask is a valid processor related event */ if (event_mask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH | - DSP_PROCESSORDETACH | DSP_PROCESSORRESTART | - DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR)) + DSP_PROCESSORDETACH | DSP_PROCESSORRESTART | + DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR | + DSP_WDTOVERFLOW)) status = DSP_EVALUE; /* Check if notify type is valid */ @@ -1161,7 +1162,8 @@ dsp_status proc_register_notify(void *hprocessor, u32 event_mask, /* If event mask is not DSP_SYSERROR, DSP_MMUFAULT, * or DSP_PWRERROR then register event immediately. */ if (event_mask & - ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR)) { + ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR | + DSP_WDTOVERFLOW)) { status = ntfy_register(p_proc_object->ntfy_obj, hnotification, event_mask, notify_type); diff --git a/drivers/dsp/bridge/wmd/io_sm.c b/drivers/dsp/bridge/wmd/io_sm.c index 1b5d977..545cca0 100644 --- a/drivers/dsp/bridge/wmd/io_sm.c +++ b/drivers/dsp/bridge/wmd/io_sm.c @@ -51,6 +51,7 @@ #include #include #include +#include #include <_tiomap.h> #include #include <_tiomap_pwr.h> @@ -244,6 +245,8 @@ dsp_status bridge_io_create(OUT struct io_mgr **phIOMgr, if (DSP_SUCCEEDED(status)) { pio_mgr->hwmd_context = hwmd_context; pio_mgr->shared_irq = pMgrAttrs->irq_shared; + if (dsp_wdt_init()) + status = DSP_EFAIL; } else { status = CHNL_E_ISR; } @@ -279,6 +282,7 @@ dsp_status bridge_io_destroy(struct io_mgr *hio_mgr) #ifndef DSP_TRACEBUF_DISABLED kfree(hio_mgr->pmsg); #endif + dsp_wdt_exit(); /* Free this IO manager object */ MEM_FREE_OBJECT(hio_mgr); } else { diff --git a/drivers/dsp/bridge/wmd/tiomap3430.c b/drivers/dsp/bridge/wmd/tiomap3430.c index ed51875..7a1093c 100644 --- a/drivers/dsp/bridge/wmd/tiomap3430.c +++ b/drivers/dsp/bridge/wmd/tiomap3430.c @@ -60,6 +60,7 @@ #include #include #include +#include /* ----------------------------------- Local */ #include "_tiomap.h" @@ -724,6 +725,10 @@ static dsp_status bridge_brd_start(struct wmd_dev_context *hDevContext, if (!wait_for_start(dev_context, dw_sync_addr)) status = WMD_E_TIMEOUT; + /* Start wdt */ + dsp_wdt_sm_set((void *)ul_shm_base); + dsp_wdt_enable(true); + status = dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr); if (DSP_SUCCEEDED(status)) { io_sh_msetting(hio_mgr, SHM_OPPINFO, NULL); @@ -799,6 +804,8 @@ static dsp_status bridge_brd_stop(struct wmd_dev_context *hDevContext) dev_context->dw_brd_state = BRD_STOPPED; /* update board state */ + dsp_wdt_enable(false); + /* This is a good place to clear the MMU page tables as well */ if (dev_context->pt_attrs) { pt_attrs = dev_context->pt_attrs; diff --git a/drivers/dsp/bridge/wmd/tiomap3430_pwr.c b/drivers/dsp/bridge/wmd/tiomap3430_pwr.c index 9174a80..f21be4b 100644 --- a/drivers/dsp/bridge/wmd/tiomap3430_pwr.c +++ b/drivers/dsp/bridge/wmd/tiomap3430_pwr.c @@ -41,6 +41,7 @@ /* ----------------------------------- Mini Driver */ #include +#include /* ----------------------------------- specific to this file */ #include "_tiomap.h" @@ -125,6 +126,9 @@ dsp_status handle_hibernation_from_dsp(struct wmd_dev_context *dev_context) /* Turn off DSP Peripheral clocks and DSP Load monitor timer */ status = dsp_peripheral_clocks_disable(dev_context, NULL); + /* Disable wdt on hibernation. */ + dsp_wdt_enable(false); + if (DSP_SUCCEEDED(status)) { /* Update the Bridger Driver state */ dev_context->dw_brd_state = BRD_DSP_HIBERNATION; @@ -239,6 +243,9 @@ dsp_status sleep_dsp(struct wmd_dev_context *dev_context, IN u32 dw_cmd, else dev_context->dw_brd_state = BRD_RETENTION; + /* Disable wdt on hibernation. */ + dsp_wdt_enable(false); + /* Turn off DSP Peripheral clocks */ status = dsp_peripheral_clocks_disable(dev_context, NULL); if (DSP_FAILED(status)) { diff --git a/drivers/dsp/bridge/wmd/tiomap_io.c b/drivers/dsp/bridge/wmd/tiomap_io.c index b5504a9..728db33 100644 --- a/drivers/dsp/bridge/wmd/tiomap_io.c +++ b/drivers/dsp/bridge/wmd/tiomap_io.c @@ -30,6 +30,7 @@ /* ----------------------------------- OS Adaptation Layer */ #include #include +#include /* ----------------------------------- specific to this file */ #include "_tiomap.h" @@ -426,6 +427,7 @@ dsp_status sm_interrupt_dsp(struct wmd_dev_context *dev_context, u16 mb_val) #endif /* Restart the peripheral clocks */ dsp_peripheral_clocks_enable(dev_context, NULL); + dsp_wdt_enable(true); /* * 2:0 AUTO_IVA2_DPLL - Enabling IVA2 DPLL auto control diff --git a/drivers/dsp/bridge/wmd/ue_deh.c b/drivers/dsp/bridge/wmd/ue_deh.c index 14dd8ae..75a62b0 100644 --- a/drivers/dsp/bridge/wmd/ue_deh.c +++ b/drivers/dsp/bridge/wmd/ue_deh.c @@ -39,6 +39,7 @@ /* ----------------------------------- Platform Manager */ #include #include +#include /* ------------------------------------ Hardware Abstraction Layer */ #include @@ -281,6 +282,13 @@ void bridge_deh_notify(struct deh_mgr *hdeh_mgr, u32 ulEventMask, u32 dwErrInfo) "= 0x%x\n", dwErrInfo); break; #endif /* CONFIG_BRIDGE_NTFY_PWRERR */ + case DSP_WDTOVERFLOW: + deh_mgr_obj->err_info.dw_err_mask = DSP_WDTOVERFLOW; + deh_mgr_obj->err_info.dw_val1 = 0L; + deh_mgr_obj->err_info.dw_val2 = 0L; + deh_mgr_obj->err_info.dw_val3 = 0L; + pr_err("bridge_deh_notify: DSP_WDTOVERFLOW \n "); + break; default: dev_dbg(bridge, "%s: Unknown Error, err_info = 0x%x\n", __func__, dwErrInfo); @@ -301,6 +309,11 @@ void bridge_deh_notify(struct deh_mgr *hdeh_mgr, u32 ulEventMask, u32 dwErrInfo) (void)dsp_peripheral_clocks_disable(dev_context, NULL); /* Call DSP Trace Buffer */ print_dsp_trace_buffer(hdeh_mgr->hwmd_context); + /* + * Avoid the subsequent WDT if it happens once, + * also If fatal error occurs + */ + dsp_wdt_enable(false); } } diff --git a/drivers/dsp/bridge/wmd/wdt.c b/drivers/dsp/bridge/wmd/wdt.c new file mode 100644 index 0000000..7a007f2 --- /dev/null +++ b/drivers/dsp/bridge/wmd/wdt.c @@ -0,0 +1,148 @@ +/* + * wdt.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * IO dispatcher for a shared memory channel driver. + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_BRIDGE_WDT3 +static struct dsp_wdt_setting dsp_wdt; + +void dsp_wdt_dpc(unsigned long data) +{ + struct deh_mgr *deh_mgr; + dev_get_deh_mgr(dev_get_first(), &deh_mgr); + if (deh_mgr) + bridge_deh_notify(deh_mgr, DSP_WDTOVERFLOW, 0); +} + +irqreturn_t dsp_wdt_isr(int irq, void *data) +{ + u32 value; + /* ack wdt3 interrupt */ + value = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET); + __raw_writel(value, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET); + + tasklet_schedule(&dsp_wdt.wdt3_tasklet); + return IRQ_HANDLED; +} + +int dsp_wdt_init(void) +{ + int ret = 0; + + dsp_wdt.sm_wdt = NULL; + dsp_wdt.reg_base = OMAP2_L4_IO_ADDRESS(OMAP34XX_WDT3_BASE); + tasklet_init(&dsp_wdt.wdt3_tasklet, dsp_wdt_dpc, 0); + + dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); + + if (dsp_wdt.fclk) { + dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); + if (!dsp_wdt.iclk) { + clk_put(dsp_wdt.fclk); + dsp_wdt.fclk = NULL; + ret = -EFAULT; + } + } else + ret = -EFAULT; + + if (!ret) + ret = request_irq(INT_34XX_WDT3_IRQ, dsp_wdt_isr, 0, + "dsp_wdt", &dsp_wdt); + + /* Disable at this moment, it will be enabled when DSP starts */ + if (!ret) + disable_irq(INT_34XX_WDT3_IRQ); + + return ret; +} + +void dsp_wdt_sm_set(void *data) +{ + dsp_wdt.sm_wdt = data; + dsp_wdt.sm_wdt->wdt_overflow = CONFIG_WDT_TIMEOUT; +} + + +void dsp_wdt_exit(void) +{ + free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); + tasklet_kill(&dsp_wdt.wdt3_tasklet); + + if (dsp_wdt.fclk) + clk_put(dsp_wdt.fclk); + if (dsp_wdt.iclk) + clk_put(dsp_wdt.iclk); + + dsp_wdt.fclk = NULL; + dsp_wdt.iclk = NULL; + dsp_wdt.sm_wdt = NULL; + dsp_wdt.reg_base = NULL; +} + +void dsp_wdt_enable(bool enable) +{ + u32 tmp; + static bool wdt_enable; + + if (wdt_enable == enable || !dsp_wdt.fclk || !dsp_wdt.iclk) + return; + + wdt_enable = enable; + + if (enable) { + clk_enable(dsp_wdt.fclk); + clk_enable(dsp_wdt.iclk); + dsp_wdt.sm_wdt->wdt_setclocks = 1; + tmp = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET); + __raw_writel(tmp, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET); + enable_irq(INT_34XX_WDT3_IRQ); + } else { + disable_irq(INT_34XX_WDT3_IRQ); + dsp_wdt.sm_wdt->wdt_setclocks = 0; + clk_disable(dsp_wdt.iclk); + clk_disable(dsp_wdt.fclk); + } +} + +#else +void dsp_wdt_enable(bool enable) +{ +} + +void dsp_wdt_sm_set(void *data) +{ +} + +int dsp_wdt_init(void) +{ + return 0; +} + +void dsp_wdt_exit(void) +{ +} +#endif +