From ad1b6662eb5fe293e8b402497b3835710848c389 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 8 May 2012 17:23:33 -0600 Subject: ARM: OMAP2420: hwmod data: Add MMC hwmod data for 2420 Add MMC for 2420 so we can pass the DMA request lines the same way as we already do on omap2430 and later. Cc: Benoit Cousson Cc: Paul Walmsley Signed-off-by: Tony Lindgren [paul@pwsan.com: updated to apply on top of the 3.5 hwmod cleanup; changed mmc hwmod name/class to "msdi" as documented in the 2420 TRM Rev X; added sysconfig register information; added 16 bit register width flag; added MSDI custom reset code] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/Makefile | 3 + arch/arm/mach-omap2/msdi.c | 88 ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod_2420_data.c | 64 ++++++++++++++++++++++ arch/arm/plat-omap/include/plat/mmc.h | 4 ++ 4 files changed, 159 insertions(+) create mode 100644 arch/arm/mach-omap2/msdi.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index d8604a3e490e..4eee0f139cbd 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -189,6 +189,9 @@ ifneq ($(CONFIG_TIDSPBRIDGE),) obj-y += dsp.o endif +# OMAP2420 MSDI controller integration support ("MMC") +obj-$(CONFIG_SOC_OMAP2420) += msdi.o + # Specific board support obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c new file mode 100644 index 000000000000..ef2a6924731a --- /dev/null +++ b/arch/arm/mach-omap2/msdi.c @@ -0,0 +1,88 @@ +/* + * MSDI IP block reset + * + * Copyright (C) 2012 Texas Instruments, Inc. + * Paul Walmsley + * + * This program 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * XXX What about pad muxing? + */ + +#include + +#include +#include + +#include "common.h" + +/* + * MSDI_CON_OFFSET: offset in bytes of the MSDI IP block's CON register + * from the IP block's base address + */ +#define MSDI_CON_OFFSET 0x0c + +/* Register bitfields in the CON register */ +#define MSDI_CON_POW_MASK BIT(11) +#define MSDI_CON_CLKD_MASK (0x3f << 0) +#define MSDI_CON_CLKD_SHIFT 0 + +/* Maximum microseconds to wait for OMAP module to softreset */ +#define MAX_MODULE_SOFTRESET_WAIT 10000 + +/* MSDI_TARGET_RESET_CLKD: clock divisor to use throughout the reset */ +#define MSDI_TARGET_RESET_CLKD 0x3ff + +/** + * omap_msdi_reset - reset the MSDI IP block + * @oh: struct omap_hwmod * + * + * The MSDI IP block on OMAP2420 has to have both the POW and CLKD + * fields set inside its CON register for a reset to complete + * successfully. This is not documented in the TRM. For CLKD, we use + * the value that results in the lowest possible clock rate, to attempt + * to avoid disturbing any cards. + */ +int omap_msdi_reset(struct omap_hwmod *oh) +{ + u16 v = 0; + int c = 0; + + /* Write to the SOFTRESET bit */ + omap_hwmod_softreset(oh); + + /* Enable the MSDI core and internal clock */ + v |= MSDI_CON_POW_MASK; + v |= MSDI_TARGET_RESET_CLKD << MSDI_CON_CLKD_SHIFT; + omap_hwmod_write(v, oh, MSDI_CON_OFFSET); + + /* Poll on RESETDONE bit */ + omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs) + & SYSS_RESETDONE_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + + if (c == MAX_MODULE_SOFTRESET_WAIT) + pr_warning("%s: %s: softreset failed (waited %d usec)\n", + __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT); + else + pr_debug("%s: %s: softreset in %d usec\n", __func__, + oh->name, c); + + /* Disable the MSDI internal clock */ + v &= ~MSDI_CON_CLKD_MASK; + omap_hwmod_write(v, oh, MSDI_CON_OFFSET); + + return 0; +} diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 2c087ffc6a92..0c08d3f11f69 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "omap_hwmod_common_data.h" @@ -239,6 +240,50 @@ static struct omap_hwmod omap2420_mcbsp2_hwmod = { }, }; +static struct omap_hwmod_class_sysconfig omap2420_msdi_sysc = { + .rev_offs = 0x3c, + .sysc_offs = 0x64, + .syss_offs = 0x68, + .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap2420_msdi_hwmod_class = { + .name = "msdi", + .sysc = &omap2420_msdi_sysc, + .reset = &omap_msdi_reset, +}; + +/* msdi1 */ +static struct omap_hwmod_irq_info omap2420_msdi1_irqs[] = { + { .irq = 83 }, + { .irq = -1 } +}; + +static struct omap_hwmod_dma_info omap2420_msdi1_sdma_reqs[] = { + { .name = "tx", .dma_req = 61 }, /* OMAP24XX_DMA_MMC1_TX */ + { .name = "rx", .dma_req = 62 }, /* OMAP24XX_DMA_MMC1_RX */ + { .dma_req = -1 } +}; + +static struct omap_hwmod omap2420_msdi1_hwmod = { + .name = "msdi1", + .class = &omap2420_msdi_hwmod_class, + .mpu_irqs = omap2420_msdi1_irqs, + .sdma_reqs = omap2420_msdi1_sdma_reqs, + .main_clk = "mmc_fck", + .prcm = { + .omap2 = { + .prcm_reg_id = 1, + .module_bit = OMAP2420_EN_MMC_SHIFT, + .module_offs = CORE_MOD, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP2420_ST_MMC_SHIFT, + }, + }, + .flags = HWMOD_16BIT_REG, +}; + /* * interfaces */ @@ -428,6 +473,24 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp2 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_addr_space omap2420_msdi1_addrs[] = { + { + .pa_start = 0x4809c000, + .pa_end = 0x4809c000 + SZ_128 - 1, + .flags = ADDR_TYPE_RT, + }, + { } +}; + +/* l4_core -> msdi1 */ +static struct omap_hwmod_ocp_if omap2420_l4_core__msdi1 = { + .master = &omap2xxx_l4_core_hwmod, + .slave = &omap2420_msdi1_hwmod, + .clk = "mmc_ick", + .addr = omap2420_msdi1_addrs, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main, @@ -468,6 +531,7 @@ static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2420_l4_core__mailbox, &omap2420_l4_core__mcbsp1, &omap2420_l4_core__mcbsp2, + &omap2420_l4_core__msdi1, NULL, }; diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index 7a38750c0079..3e7ae0f0215f 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -16,6 +16,7 @@ #include #include +#include #define OMAP15XX_NR_MMC 1 #define OMAP16XX_NR_MMC 2 @@ -195,4 +196,7 @@ static inline int omap_mmc_add(const char *name, int id, unsigned long base, } #endif + +extern int omap_msdi_reset(struct omap_hwmod *oh); + #endif -- cgit v1.2.3 From 9e1b7498d79ab9076791807172d4603c7be63c1b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 8 May 2012 11:34:27 -0600 Subject: ARM: OMAP2+: HDQ1W: add custom reset function Implement a custom reset function for the HDQ1W IP block. This is because the HDQ1W IP block, like I2C, has an internal clock gating bit that needs to be toggled after setting the SOFTRESET bit to allow the reset to propagate. Signed-off-by: Paul Walmsley Cc: NeilBrown Cc: Avinash.H.M Tested-by: NeilBrown --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/hdq1w.c | 72 +++++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/hdq1w.h | 36 +++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-omap2/hdq1w.c create mode 100644 arch/arm/plat-omap/include/plat/hdq1w.h diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 4eee0f139cbd..385c083d24b2 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -4,7 +4,7 @@ # Common support obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \ - common.o gpio.o dma.o wd_timer.o display.o i2c.o + common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap-2-3-common = irq.o sdrc.o hwmod-common = omap_hwmod.o \ diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c new file mode 100644 index 000000000000..297ebe03f09c --- /dev/null +++ b/arch/arm/mach-omap2/hdq1w.c @@ -0,0 +1,72 @@ +/* + * IP block integration code for the HDQ1W/1-wire IP block + * + * Copyright (C) 2012 Texas Instruments, Inc. + * Paul Walmsley + * + * Based on the I2C reset code in arch/arm/mach-omap2/i2c.c by + * Avinash.H.M + * + * This program 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include "common.h" + +/* Maximum microseconds to wait for OMAP module to softreset */ +#define MAX_MODULE_SOFTRESET_WAIT 10000 + +/** + * omap_hdq1w_reset - reset the OMAP HDQ1W module + * @oh: struct omap_hwmod * + * + * OCP soft reset the HDQ1W IP block. Section 20.6.1.4 "HDQ1W/1-Wire + * Software Reset" of the OMAP34xx Technical Reference Manual Revision + * ZR (SWPU223R) does not include the rather important fact that, for + * the reset to succeed, the HDQ1W module's internal clock gate must be + * programmed to allow the clock to propagate to the rest of the + * module. In this sense, it's rather similar to the I2C custom reset + * function. Returns 0. + */ +int omap_hdq1w_reset(struct omap_hwmod *oh) +{ + u32 v; + int c = 0; + + /* Write to the SOFTRESET bit */ + omap_hwmod_softreset(oh); + + /* Enable the module's internal clocks */ + v = omap_hwmod_read(oh, HDQ_CTRL_STATUS_OFFSET); + v |= 1 << HDQ_CTRL_STATUS_CLOCKENABLE_SHIFT; + omap_hwmod_write(v, oh, HDQ_CTRL_STATUS_OFFSET); + + /* Poll on RESETDONE bit */ + omap_test_timeout((omap_hwmod_read(oh, + oh->class->sysc->syss_offs) + & SYSS_RESETDONE_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + + if (c == MAX_MODULE_SOFTRESET_WAIT) + pr_warning("%s: %s: softreset failed (waited %d usec)\n", + __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT); + else + pr_debug("%s: %s: softreset in %d usec\n", __func__, + oh->name, c); + + return 0; +} diff --git a/arch/arm/plat-omap/include/plat/hdq1w.h b/arch/arm/plat-omap/include/plat/hdq1w.h new file mode 100644 index 000000000000..0c1efc846d8d --- /dev/null +++ b/arch/arm/plat-omap/include/plat/hdq1w.h @@ -0,0 +1,36 @@ +/* + * Shared macros and function prototypes for the HDQ1W/1-wire IP block + * + * Copyright (C) 2012 Texas Instruments, Inc. + * Paul Walmsley + * + * This program 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef ARCH_ARM_MACH_OMAP2_HDQ1W_H +#define ARCH_ARM_MACH_OMAP2_HDQ1W_H + +#include + +/* + * XXX A future cleanup patch should modify + * drivers/w1/masters/omap_hdq.c to use these macros + */ +#define HDQ_CTRL_STATUS_OFFSET 0x0c +#define HDQ_CTRL_STATUS_CLOCKENABLE_SHIFT 5 + + +extern int omap_hdq1w_reset(struct omap_hwmod *oh); + +#endif -- cgit v1.2.3 From 03d830e8dcbe4e8168a85252fcb639b48342ed3c Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 8 May 2012 11:34:27 -0600 Subject: ARM: OMAP2+: hwmod data: add HDQ/1-wire hwmod shared data Much of the HDQ1W integration data is common between multiple generations of OMAP SoCs, so rather than make several copies, we add it once into files which are compiled for multiple SoCs. Signed-off-by: Paul Walmsley Cc: NeilBrown Tested-by: NeilBrown --- .../omap_hwmod_2xxx_3xxx_interconnect_data.c | 9 +++++++++ .../mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c | 22 ++++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod_common_data.h | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c index 04637fabadd2..cbb4ef6544ad 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c @@ -171,3 +171,12 @@ struct omap_hwmod_addr_space omap2_mcbsp1_addrs[] = { }, { } }; + +struct omap_hwmod_addr_space omap2_hdq1w_addr_space[] = { + { + .pa_start = 0x480b2000, + .pa_end = 0x480b2fff, + .flags = ADDR_TYPE_RT, + }, + { } +}; diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c index f08e442af397..102d76e9e9ea 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c @@ -2,6 +2,7 @@ * omap_hwmod_2xxx_3xxx_ipblock_data.c - common IP block data for OMAP2/3 * * Copyright (C) 2011 Nokia Corporation + * Copyright (C) 2012 Texas Instruments, Inc. * Paul Walmsley * * This program is free software; you can redistribute it and/or modify @@ -12,6 +13,7 @@ #include #include #include +#include #include @@ -302,3 +304,23 @@ struct omap_hwmod_irq_info omap2_mcspi2_mpu_irqs[] = { { .irq = -1 } }; +struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc = { + .rev_offs = 0x0, + .sysc_offs = 0x14, + .syss_offs = 0x18, + .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE | + SYSS_HAS_RESET_STATUS), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +struct omap_hwmod_class omap2_hdq1w_class = { + .name = "hdq1w", + .sysc = &omap2_hdq1w_sysc, + .reset = &omap_hdq1w_reset, +}; + +struct omap_hwmod_irq_info omap2_hdq1w_mpu_irqs[] = { + { .irq = 58, }, + { .irq = -1 } +}; + diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.h b/arch/arm/mach-omap2/omap_hwmod_common_data.h index 7aa9156d50ab..e244829308bd 100644 --- a/arch/arm/mach-omap2/omap_hwmod_common_data.h +++ b/arch/arm/mach-omap2/omap_hwmod_common_data.h @@ -38,6 +38,7 @@ extern struct omap_hwmod_addr_space omap2430_mcspi3_addr_space[]; extern struct omap_hwmod_addr_space omap2_dma_system_addrs[]; extern struct omap_hwmod_addr_space omap2_mailbox_addrs[]; extern struct omap_hwmod_addr_space omap2_mcbsp1_addrs[]; +extern struct omap_hwmod_addr_space omap2_hdq1w_addr_space[]; /* Common IP block data across OMAP2xxx */ extern struct omap_hwmod_irq_info omap2xxx_timer12_mpu_irqs[]; @@ -141,6 +142,7 @@ extern struct omap_hwmod_irq_info omap2_dma_system_irqs[]; extern struct omap_hwmod_irq_info omap2_mcspi1_mpu_irqs[]; extern struct omap_hwmod_irq_info omap2_mcspi2_mpu_irqs[]; extern struct omap_hwmod_addr_space omap2xxx_timer12_addrs[]; +extern struct omap_hwmod_irq_info omap2_hdq1w_mpu_irqs[]; /* OMAP hwmod classes - forward declarations */ extern struct omap_hwmod_class l3_hwmod_class; @@ -152,6 +154,8 @@ extern struct omap_hwmod_class omap2_dss_hwmod_class; extern struct omap_hwmod_class omap2_dispc_hwmod_class; extern struct omap_hwmod_class omap2_rfbi_hwmod_class; extern struct omap_hwmod_class omap2_venc_hwmod_class; +extern struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc; +extern struct omap_hwmod_class omap2_hdq1w_class; extern struct omap_hwmod_class omap2xxx_timer_hwmod_class; extern struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class; -- cgit v1.2.3 From 45a4bb067c25355b5d362eb09fa97e51a2a519c8 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 8 May 2012 11:34:28 -0600 Subject: ARM: OMAP3: hwmod data: add HDQ/1-wire hwmod Add the HDQ1W hwmod for OMAP34xx, OMAP36xx, and AM3505/3517 devices. According to the respective TRMs, it doesn't appear to be available for the 816x/814x or the AM335x. The OCPIF_SWSUP_IDLE flag is added to work around an apparent hardware bug: the hardware is not taking the CM_FCLKEN*_CORE.EN_HDQ bit into account when considering whether to go idle: http://www.spinics.net/lists/linux-omap/msg63576.html This causes HDQ transfers to fail or become corrupt. Thanks to NeilBrown for his help diagnosing and testing fixes for this problem. Signed-off-by: Paul Walmsley Cc: NeilBrown Tested-by: NeilBrown --- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 0c65079c2b69..97c65973ae7f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1980,6 +1980,22 @@ static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = { }, }; +static struct omap_hwmod omap3xxx_hdq1w_hwmod = { + .name = "hdq1w", + .mpu_irqs = omap2_hdq1w_mpu_irqs, + .main_clk = "hdq_fck", + .prcm = { + .omap2 = { + .module_offs = CORE_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP3430_EN_HDQ_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP3430_ST_HDQ_SHIFT, + }, + }, + .class = &omap2_hdq1w_class, +}; + /* * interfaces */ @@ -3059,6 +3075,16 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_tll_hs = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_core -> hdq1w interface */ +static struct omap_hwmod_ocp_if omap3xxx_l4_core__hdq1w = { + .master = &omap3xxx_l4_core_hwmod, + .slave = &omap3xxx_hdq1w_hwmod, + .clk = "hdq_ick", + .addr = omap2_hdq1w_addr_space, + .user = OCP_USER_MPU | OCP_USER_SDMA, + .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE, +}; + static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = { &omap3xxx_l3_main__l4_core, &omap3xxx_l3_main__l4_per, @@ -3151,6 +3177,7 @@ static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = { &omap34xx_l4_core__sr1, &omap34xx_l4_core__sr2, &omap3xxx_l4_core__mailbox, + &omap3xxx_l4_core__hdq1w, NULL }; @@ -3170,6 +3197,7 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = { &omap3xxx_l4_core__usb_tll_hs, &omap3xxx_l4_core__es3plus_mmc1, &omap3xxx_l4_core__es3plus_mmc2, + &omap3xxx_l4_core__hdq1w, NULL }; -- cgit v1.2.3 From f32bd7787561ceb887e45d81ca41d6c7a903751f Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 8 May 2012 11:34:28 -0600 Subject: ARM: OMAP2xxx: hwmod data: add HDQ/1-wire hwmod Add the HDQ1W hwmod for all OMAP2xxx devices. Assume that OMAP2xxx chips have the same HDQ idle handling bug as OMAP3: http://www.spinics.net/lists/linux-omap/msg63576.html and set the OCPIF_SWSUP_IDLE flag accordingly on the HDQ's OCP interface. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 29 +++++++++++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 0c08d3f11f69..85419f86b280 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -284,6 +284,23 @@ static struct omap_hwmod omap2420_msdi1_hwmod = { .flags = HWMOD_16BIT_REG, }; +/* HDQ1W/1-wire */ +static struct omap_hwmod omap2420_hdq1w_hwmod = { + .name = "hdq1w", + .mpu_irqs = omap2_hdq1w_mpu_irqs, + .main_clk = "hdq_fck", + .prcm = { + .omap2 = { + .module_offs = CORE_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP24XX_EN_HDQ_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP24XX_ST_HDQ_SHIFT, + }, + }, + .class = &omap2_hdq1w_class, +}; + /* * interfaces */ @@ -491,6 +508,17 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__msdi1 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_core -> hdq1w interface */ +static struct omap_hwmod_ocp_if omap2420_l4_core__hdq1w = { + .master = &omap2xxx_l4_core_hwmod, + .slave = &omap2420_hdq1w_hwmod, + .clk = "hdq_ick", + .addr = omap2_hdq1w_addr_space, + .user = OCP_USER_MPU | OCP_USER_SDMA, + .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE, +}; + + static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main, @@ -532,6 +560,7 @@ static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2420_l4_core__mcbsp1, &omap2420_l4_core__mcbsp2, &omap2420_l4_core__msdi1, + &omap2420_l4_core__hdq1w, NULL, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 71d9f8824f9d..ff93a8dbf427 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -528,6 +528,23 @@ static struct omap_hwmod omap2430_mmc2_hwmod = { .class = &omap2430_mmc_class, }; +/* HDQ1W/1-wire */ +static struct omap_hwmod omap2430_hdq1w_hwmod = { + .name = "hdq1w", + .mpu_irqs = omap2_hdq1w_mpu_irqs, + .main_clk = "hdq_fck", + .prcm = { + .omap2 = { + .module_offs = CORE_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP24XX_EN_HDQ_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP24XX_ST_HDQ_SHIFT, + }, + }, + .class = &omap2_hdq1w_class, +}; + /* * interfaces */ @@ -838,6 +855,16 @@ static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_core -> hdq1w */ +static struct omap_hwmod_ocp_if omap2430_l4_core__hdq1w = { + .master = &omap2xxx_l4_core_hwmod, + .slave = &omap2430_hdq1w_hwmod, + .clk = "hdq_ick", + .addr = omap2_hdq1w_addr_space, + .user = OCP_USER_MPU | OCP_USER_SDMA, + .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE, +}; + static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main, @@ -886,6 +913,7 @@ static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = { &omap2430_l4_core__mcbsp3, &omap2430_l4_core__mcbsp4, &omap2430_l4_core__mcbsp5, + &omap2430_l4_core__hdq1w, NULL, }; -- cgit v1.2.3 From 1c2badc1617661632034d8be5d22c8637b626cb7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 8 May 2012 11:34:28 -0600 Subject: ARM: OMAP3: hwmod_data: Rename the common irq for McBSP ports Use 'common' as name for the common irq number in hwmod data for the McBSP ports. The same name already in use for OMAP2430, and the OMAP4 hwmod data will be using the same name. Signed-off-by: Peter Ujfalusi Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 97c65973ae7f..87742e20cd5f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1075,7 +1075,7 @@ static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = { /* mcbsp1 */ static struct omap_hwmod_irq_info omap3xxx_mcbsp1_irqs[] = { - { .name = "irq", .irq = 16 }, + { .name = "common", .irq = 16 }, { .name = "tx", .irq = 59 }, { .name = "rx", .irq = 60 }, { .irq = -1 } @@ -1100,7 +1100,7 @@ static struct omap_hwmod omap3xxx_mcbsp1_hwmod = { /* mcbsp2 */ static struct omap_hwmod_irq_info omap3xxx_mcbsp2_irqs[] = { - { .name = "irq", .irq = 17 }, + { .name = "common", .irq = 17 }, { .name = "tx", .irq = 62 }, { .name = "rx", .irq = 63 }, { .irq = -1 } @@ -1130,7 +1130,7 @@ static struct omap_hwmod omap3xxx_mcbsp2_hwmod = { /* mcbsp3 */ static struct omap_hwmod_irq_info omap3xxx_mcbsp3_irqs[] = { - { .name = "irq", .irq = 22 }, + { .name = "common", .irq = 22 }, { .name = "tx", .irq = 89 }, { .name = "rx", .irq = 90 }, { .irq = -1 } @@ -1160,7 +1160,7 @@ static struct omap_hwmod omap3xxx_mcbsp3_hwmod = { /* mcbsp4 */ static struct omap_hwmod_irq_info omap3xxx_mcbsp4_irqs[] = { - { .name = "irq", .irq = 23 }, + { .name = "common", .irq = 23 }, { .name = "tx", .irq = 54 }, { .name = "rx", .irq = 55 }, { .irq = -1 } @@ -1191,7 +1191,7 @@ static struct omap_hwmod omap3xxx_mcbsp4_hwmod = { /* mcbsp5 */ static struct omap_hwmod_irq_info omap3xxx_mcbsp5_irqs[] = { - { .name = "irq", .irq = 27 }, + { .name = "common", .irq = 27 }, { .name = "tx", .irq = 81 }, { .name = "rx", .irq = 82 }, { .irq = -1 } -- cgit v1.2.3 From aa8f6cefa1e0ba79deaf76c5a790ad167659c311 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 8 May 2012 11:34:29 -0600 Subject: ARM: OMAP4: hwmod data: I2C: add flag for context restore Restore of context is not done for OMAP4. This patch adds the OMAP_I2C_FLAG_RESET_REGS_POSTIDLE in the OMAP4 hwmod data which activates the restore for OMAP4. Currently the OMAP4 does not hit device off still the driver may have support for it. Cc: Benoit Cousson Cc: Paul Wamsley Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 49061295475c..3a67ed014d3d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1487,7 +1487,8 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = { }; static struct omap_i2c_dev_attr i2c_dev_attr = { - .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE | + OMAP_I2C_FLAG_RESET_REGS_POSTIDLE, }; /* i2c1 */ -- cgit v1.2.3 From 437e897083d9e42195c13a96a5bc4d8871649a19 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 8 May 2012 11:34:29 -0600 Subject: ARM: OMAP4: hwmod_data: Name the common irq for McBSP ports Use 'common' as name for the common irq number in hwmod data for the McBSP ports. The same name already in use for OMAP2430, and OMAP3. Signed-off-by: Peter Ujfalusi Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 3a67ed014d3d..c997c97c08b7 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1912,7 +1912,7 @@ static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = { /* mcbsp1 */ static struct omap_hwmod_irq_info omap44xx_mcbsp1_irqs[] = { - { .irq = 17 + OMAP44XX_IRQ_GIC_START }, + { .name = "common", .irq = 17 + OMAP44XX_IRQ_GIC_START }, { .irq = -1 } }; @@ -1947,7 +1947,7 @@ static struct omap_hwmod omap44xx_mcbsp1_hwmod = { /* mcbsp2 */ static struct omap_hwmod_irq_info omap44xx_mcbsp2_irqs[] = { - { .irq = 22 + OMAP44XX_IRQ_GIC_START }, + { .name = "common", .irq = 22 + OMAP44XX_IRQ_GIC_START }, { .irq = -1 } }; @@ -1982,7 +1982,7 @@ static struct omap_hwmod omap44xx_mcbsp2_hwmod = { /* mcbsp3 */ static struct omap_hwmod_irq_info omap44xx_mcbsp3_irqs[] = { - { .irq = 23 + OMAP44XX_IRQ_GIC_START }, + { .name = "common", .irq = 23 + OMAP44XX_IRQ_GIC_START }, { .irq = -1 } }; @@ -2017,7 +2017,7 @@ static struct omap_hwmod omap44xx_mcbsp3_hwmod = { /* mcbsp4 */ static struct omap_hwmod_irq_info omap44xx_mcbsp4_irqs[] = { - { .irq = 16 + OMAP44XX_IRQ_GIC_START }, + { .name = "common", .irq = 16 + OMAP44XX_IRQ_GIC_START }, { .irq = -1 } }; -- cgit v1.2.3 From c8d82ff68fb6873691536cf33021977efbf5593c Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Tue, 8 May 2012 11:34:30 -0600 Subject: ARM: OMAP2/3: hwmod data: Add 32k-sync timer data to hwmod database Add 32k-sync timer hwmod-data and add ocp_if details to omap2 & 3 hwmod table. Signed-off-by: Vaibhav Hiremath Signed-off-by: Felipe Balbi Reviewed-by: Santosh Shilimkar Cc: Benoit Cousson Cc: Tony Lindgren Cc: Paul Walmsley Cc: Kevin Hilman Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 19 ++++++++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 19 ++++++++ arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 20 ++++++++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 53 ++++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod_common_data.h | 1 + 5 files changed, 112 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 85419f86b280..a7640d1b215e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -519,6 +519,24 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__hdq1w = { }; +/* l4_wkup -> 32ksync_counter */ +static struct omap_hwmod_addr_space omap2420_counter_32k_addrs[] = { + { + .pa_start = 0x48004000, + .pa_end = 0x4800401f, + .flags = ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = { + .master = &omap2xxx_l4_wkup_hwmod, + .slave = &omap2xxx_counter_32k_hwmod, + .clk = "sync_32k_ick", + .addr = omap2420_counter_32k_addrs, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main, @@ -561,6 +579,7 @@ static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2420_l4_core__mcbsp2, &omap2420_l4_core__msdi1, &omap2420_l4_core__hdq1w, + &omap2420_l4_wkup__counter_32k, NULL, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index ff93a8dbf427..4d7264981230 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -865,6 +865,24 @@ static struct omap_hwmod_ocp_if omap2430_l4_core__hdq1w = { .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE, }; +/* l4_wkup -> 32ksync_counter */ +static struct omap_hwmod_addr_space omap2430_counter_32k_addrs[] = { + { + .pa_start = 0x49020000, + .pa_end = 0x4902001f, + .flags = ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = { + .master = &omap2xxx_l4_wkup_hwmod, + .slave = &omap2xxx_counter_32k_hwmod, + .clk = "sync_32k_ick", + .addr = omap2430_counter_32k_addrs, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main, @@ -914,6 +932,7 @@ static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = { &omap2430_l4_core__mcbsp4, &omap2430_l4_core__mcbsp5, &omap2430_l4_core__hdq1w, + &omap2430_l4_wkup__counter_32k, NULL, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index 45aaa07e3025..5941f14130a1 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -732,3 +732,23 @@ struct omap_hwmod omap2xxx_mcspi2_hwmod = { .class = &omap2xxx_mcspi_class, .dev_attr = &omap_mcspi2_dev_attr, }; + + +static struct omap_hwmod_class omap2xxx_counter_hwmod_class = { + .name = "counter", +}; + +struct omap_hwmod omap2xxx_counter_32k_hwmod = { + .name = "counter_32k", + .main_clk = "func_32k_ck", + .prcm = { + .omap2 = { + .module_offs = WKUP_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP24XX_ST_32KSYNC_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP24XX_ST_32KSYNC_SHIFT, + }, + }, + .class = &omap2xxx_counter_hwmod_class, +}; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 87742e20cd5f..2432574123c6 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1996,6 +1996,40 @@ static struct omap_hwmod omap3xxx_hdq1w_hwmod = { .class = &omap2_hdq1w_class, }; +/* + * '32K sync counter' class + * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock + */ +static struct omap_hwmod_class_sysconfig omap3xxx_counter_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0004, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap3xxx_counter_hwmod_class = { + .name = "counter", + .sysc = &omap3xxx_counter_sysc, +}; + +static struct omap_hwmod omap3xxx_counter_32k_hwmod = { + .name = "counter_32k", + .class = &omap3xxx_counter_hwmod_class, + .clkdm_name = "wkup_clkdm", + .flags = HWMOD_SWSUP_SIDLE, + .main_clk = "wkup_32k_fck", + .prcm = { + .omap2 = { + .module_offs = WKUP_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP3430_ST_32KSYNC_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP3430_ST_32KSYNC_SHIFT, + }, + }, +}; + /* * interfaces */ @@ -3085,6 +3119,24 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__hdq1w = { .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE, }; +/* l4_wkup -> 32ksync_counter */ +static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = { + { + .pa_start = 0x48320000, + .pa_end = 0x4832001f, + .flags = ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__counter_32k = { + .master = &omap3xxx_l4_wkup_hwmod, + .slave = &omap3xxx_counter_32k_hwmod, + .clk = "omap_32ksync_ick", + .addr = omap3xxx_counter_32k_addrs, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = { &omap3xxx_l3_main__l4_core, &omap3xxx_l3_main__l4_per, @@ -3129,6 +3181,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = { &omap34xx_l4_core__mcspi2, &omap34xx_l4_core__mcspi3, &omap34xx_l4_core__mcspi4, + &omap3xxx_l4_wkup__counter_32k, NULL, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.h b/arch/arm/mach-omap2/omap_hwmod_common_data.h index e244829308bd..e7e8eeae95e5 100644 --- a/arch/arm/mach-omap2/omap_hwmod_common_data.h +++ b/arch/arm/mach-omap2/omap_hwmod_common_data.h @@ -75,6 +75,7 @@ extern struct omap_hwmod omap2xxx_gpio3_hwmod; extern struct omap_hwmod omap2xxx_gpio4_hwmod; extern struct omap_hwmod omap2xxx_mcspi1_hwmod; extern struct omap_hwmod omap2xxx_mcspi2_hwmod; +extern struct omap_hwmod omap2xxx_counter_32k_hwmod; /* Common interface data across OMAP2xxx */ extern struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core; -- cgit v1.2.3 From 414e41286e3aeb87de140ef4c75100f9344c32b2 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 8 May 2012 11:34:30 -0600 Subject: ARM: OMAP2+: WDTIMER integration: fix !PM boot crash, disarm timer after hwmod reset Without runtime PM enabled, hwmod needs to leave all IP blocks in an enabled state by default so any driver access to the HW will succeed. This is accomplished by seting the postsetup_state to enabled for all hwmods during init when runtime PM is disabled. Currently, we have a special case for WDT in that its postsetup_state is always set to disabled. This is done so that the WDT is disabled and the timer is disarmed at boot in case there is no WDT driver. This also means that when runtime PM is disabled, if a WDT driver *is* built in the kernel, the kernel will crash on the first access to the WDT hardware. We can't simply leave the WDT module enabled, because the timer is armed by default after reset. That means that if there is no WDT driver initialzed or loaded before the timer expires, the kernel will reboot. To fix this, a custom reset method is added to the watchdog class of omap_hwmod. This method will *always* disarm the timer after hwmod reset. The WDT timer then will only be rearmed when/if the driver is loaded for the WDT. With the timer disarmed by default, we no longer need a special-case for the postsetup_state of WDT during init, so it is removed. Any platforms wishing to ensure the watchdog remains armed across the entire boot boot can simply disable the reset-on-init feature of the watchdog hwmod using omap_hwmod_no_setup_reset(). Tested on 3530/Overo, 4430/Panda. NOTE: on 4430, the hwmod OCP reset does not seem to rearm the timer as documented in the TRM (and what happens on OMAP3.) I noticed this because testing the HWMOD_INIT_NO_RESET feature with no driver loaded, I expected a reboot part way through the boot, but did not see a reboot. Adding some debug to read the counter, I verified that right after OCP softreset, the counter is not firing. After writing the magic start sequence, the timer starts counting. This means that the timer disarm sequence added here does not seem to be needed for 4430, but is technically the correct way to ensure the timer is disarmed, so it is left in for OMAP4. Special thanks to Paul Walmsley for helping brainstorm ideas to fix this problem. Cc: Paul Walmsley Signed-off-by: Kevin Hilman Cc: Santosh Shilimkar Acked-by: Santosh Shilimkar [paul@pwsan.com: updated the omap2_wd_timer_reset() function in the wake of commit 3c55c1baffa5f719eb2ae9729088bc867f972f53 ("ARM: OMAP2+: hwmod: Revert "ARM: OMAP2+: hwmod: Make omap_hwmod_softreset wait for reset status""); added kerneldoc; rolled in warning fix from Kevin] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/io.c | 18 --------- arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 3 +- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 3 +- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 1 + arch/arm/mach-omap2/wd_timer.c | 45 ++++++++++++++++++++++ arch/arm/mach-omap2/wd_timer.h | 1 + 6 files changed, 51 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 065bd768987c..fafcc35b970c 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -363,24 +363,6 @@ static void __init omap_hwmod_init_postsetup(void) #endif omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state); - /* - * Set the default postsetup state for unusual modules (like - * MPU WDT). - * - * The postsetup_state is not actually used until - * omap_hwmod_late_init(), so boards that desire full watchdog - * coverage of kernel initialization can reprogram the - * postsetup_state between the calls to - * omap2_init_common_infra() and omap_sdrc_init(). - * - * XXX ideally we could detect whether the MPU WDT was currently - * enabled here and make this conditional - */ - postsetup_state = _HWMOD_STATE_DISABLED; - omap_hwmod_for_each_by_class("wd_timer", - _set_hwmod_postsetup_state, - &postsetup_state); - omap_pm_if_early_init(); } diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index 5941f14130a1..83eafd96ecaa 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -89,7 +89,8 @@ static struct omap_hwmod_class_sysconfig omap2xxx_wd_timer_sysc = { struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class = { .name = "wd_timer", .sysc = &omap2xxx_wd_timer_sysc, - .pre_shutdown = &omap2_wd_timer_disable + .pre_shutdown = &omap2_wd_timer_disable, + .reset = &omap2_wd_timer_reset, }; /* diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 2432574123c6..fd48797fa95a 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -418,7 +418,8 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = { static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = { .name = "wd_timer", .sysc = &omap3xxx_wd_timer_sysc, - .pre_shutdown = &omap2_wd_timer_disable + .pre_shutdown = &omap2_wd_timer_disable, + .reset = &omap2_wd_timer_reset, }; static struct omap_hwmod omap3xxx_wd_timer2_hwmod = { diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index c997c97c08b7..950454a3fa31 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -3535,6 +3535,7 @@ static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = { .name = "wd_timer", .sysc = &omap44xx_wd_timer_sysc, .pre_shutdown = &omap2_wd_timer_disable, + .reset = &omap2_wd_timer_reset, }; /* wd_timer2 */ diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c index 4067669d96c4..b2f1c67043a2 100644 --- a/arch/arm/mach-omap2/wd_timer.c +++ b/arch/arm/mach-omap2/wd_timer.c @@ -14,6 +14,7 @@ #include #include "wd_timer.h" +#include "common.h" /* * In order to avoid any assumptions from bootloader regarding WDT @@ -25,6 +26,8 @@ #define OMAP_WDT_WPS 0x34 #define OMAP_WDT_SPR 0x48 +/* Maximum microseconds to wait for OMAP module to softreset */ +#define MAX_MODULE_SOFTRESET_WAIT 10000 int omap2_wd_timer_disable(struct omap_hwmod *oh) { @@ -54,3 +57,45 @@ int omap2_wd_timer_disable(struct omap_hwmod *oh) return 0; } +/** + * omap2_wdtimer_reset - reset and disable the WDTIMER IP block + * @oh: struct omap_hwmod * + * + * After the WDTIMER IP blocks are reset on OMAP2/3, we must also take + * care to execute the special watchdog disable sequence. This is + * because the watchdog is re-armed upon OCP softreset. (On OMAP4, + * this behavior was apparently changed and the watchdog is no longer + * re-armed after an OCP soft-reset.) Returns -ETIMEDOUT if the reset + * did not complete, or 0 upon success. + * + * XXX Most of this code should be moved to the omap_hwmod.c layer + * during a normal merge window. omap_hwmod_softreset() should be + * renamed to omap_hwmod_set_ocp_softreset(), and omap_hwmod_softreset() + * should call the hwmod _ocp_softreset() code. + */ +int omap2_wd_timer_reset(struct omap_hwmod *oh) +{ + int c = 0; + + /* Write to the SOFTRESET bit */ + omap_hwmod_softreset(oh); + + /* Poll on RESETDONE bit */ + omap_test_timeout((omap_hwmod_read(oh, + oh->class->sysc->syss_offs) + & SYSS_RESETDONE_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + + if (oh->class->sysc->srst_udelay) + udelay(oh->class->sysc->srst_udelay); + + if (c == MAX_MODULE_SOFTRESET_WAIT) + pr_warning("%s: %s: softreset failed (waited %d usec)\n", + __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT); + else + pr_debug("%s: %s: softreset in %d usec\n", __func__, + oh->name, c); + + return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : + omap2_wd_timer_disable(oh); +} diff --git a/arch/arm/mach-omap2/wd_timer.h b/arch/arm/mach-omap2/wd_timer.h index e0054a2d5505..f6bbba73b535 100644 --- a/arch/arm/mach-omap2/wd_timer.h +++ b/arch/arm/mach-omap2/wd_timer.h @@ -13,5 +13,6 @@ #include extern int omap2_wd_timer_disable(struct omap_hwmod *oh); +extern int omap2_wd_timer_reset(struct omap_hwmod *oh); #endif -- cgit v1.2.3