From 59b479e0985f0b795d68331d6443a7f89c47768d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 27 Jan 2011 16:39:40 -0800 Subject: omap: Start using CONFIG_SOC_OMAP We want to have just CONFIG_ARCH_OMAP2, 3 and 4. The rest are nowadays just subcategories of these. Search and replace the following: ARCH_OMAP2420 SOC_OMAP2420 ARCH_OMAP2430 SOC_OMAP2430 ARCH_OMAP3430 SOC_OMAP3430 No functional changes. Signed-off-by: Tony Lindgren Signed-off-by: Thomas Weber Acked-by: Sourav Poddar --- arch/arm/mach-omap2/Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1c0c2b02d870..9eeabaf5e11a 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -31,8 +31,8 @@ AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec) AFLAGS_omap44xx-smc.o :=-Wa,-march=armv7-a$(plus_sec) # Functions loaded to SRAM -obj-$(CONFIG_ARCH_OMAP2420) += sram242x.o -obj-$(CONFIG_ARCH_OMAP2430) += sram243x.o +obj-$(CONFIG_SOC_OMAP2420) += sram242x.o +obj-$(CONFIG_SOC_OMAP2430) += sram243x.o obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o AFLAGS_sram242x.o :=-Wa,-march=armv6 @@ -40,8 +40,8 @@ AFLAGS_sram243x.o :=-Wa,-march=armv6 AFLAGS_sram34xx.o :=-Wa,-march=armv7-a # Pin multiplexing -obj-$(CONFIG_ARCH_OMAP2420) += mux2420.o -obj-$(CONFIG_ARCH_OMAP2430) += mux2430.o +obj-$(CONFIG_SOC_OMAP2420) += mux2420.o +obj-$(CONFIG_SOC_OMAP2430) += mux2430.o obj-$(CONFIG_ARCH_OMAP3) += mux34xx.o obj-$(CONFIG_ARCH_OMAP4) += mux44xx.o @@ -113,8 +113,8 @@ obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \ clkt2xxx_dpllcore.o \ clkt2xxx_virt_prcm_set.o \ clkt2xxx_apll.o clkt2xxx_osc.o -obj-$(CONFIG_ARCH_OMAP2420) += clock2420_data.o -obj-$(CONFIG_ARCH_OMAP2430) += clock2430.o clock2430_data.o +obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ clock34xx.o clkt34xx_dpll3m2.o \ clock3517.o clock36xx.o \ @@ -123,12 +123,12 @@ obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \ dpll3xxx.o # OMAP2 clock rate set data (old "OPP" data) -obj-$(CONFIG_ARCH_OMAP2420) += opp2420_data.o -obj-$(CONFIG_ARCH_OMAP2430) += opp2430_data.o +obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += opp2430_data.o # hwmod data -obj-$(CONFIG_ARCH_OMAP2420) += omap_hwmod_2420_data.o -obj-$(CONFIG_ARCH_OMAP2430) += omap_hwmod_2430_data.o +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2430_data.o obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o -- cgit v1.2.3 From 2c87fb2e644d9141c8723a44a320bb5850790b67 Mon Sep 17 00:00:00 2001 From: Hemant Pedanekar Date: Tue, 15 Feb 2011 23:06:08 +0530 Subject: TI816X: Create board support and enable build for TI816X EVM This patch adds minimal support and build configuration for TI816X EVM. Signed-off-by: Hemant Pedanekar Reviewed-by: Kevin Hilman Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 5 +++ arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/board-ti8168evm.c | 57 +++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 arch/arm/mach-omap2/board-ti8168evm.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 23548b60bb1f..7a82a76522af 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -299,6 +299,11 @@ config MACH_OMAP_3630SDP default y select OMAP_PACKAGE_CBP +config MACH_TI8168EVM + bool "TI8168 Evaluation Module" + depends on SOC_OMAPTI816X + default y + config MACH_OMAP_4430SDP bool "OMAP 4430 SDP board" default y diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1c0c2b02d870..b577e001d209 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -224,6 +224,7 @@ obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o obj-$(CONFIG_MACH_SBC3530) += board-omap3stalker.o \ hsmmc.o +obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o # Platform specific device init code usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o obj-y += $(usbfs-m) $(usbfs-y) diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c new file mode 100644 index 000000000000..6282cc4a9772 --- /dev/null +++ b/arch/arm/mach-omap2/board-ti8168evm.c @@ -0,0 +1,57 @@ +/* + * Code for TI8168 EVM. + * + * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +static struct omap_board_config_kernel ti8168_evm_config[] __initdata = { +}; + +static void __init ti8168_evm_init_irq(void) +{ + omap_board_config = ti8168_evm_config; + omap_board_config_size = ARRAY_SIZE(ti8168_evm_config); + omap2_init_common_infrastructure(); + omap2_init_common_devices(NULL, NULL); + omap_init_irq(); +} + +static void __init ti8168_evm_init(void) +{ + omap_serial_init(); +} + +static void __init ti8168_evm_map_io(void) +{ + omap2_set_globals_ti816x(); + omapti816x_map_common_io(); +} + +MACHINE_START(TI8168EVM, "ti8168evm") + /* Maintainer: Texas Instruments */ + .boot_params = 0x80000100, + .map_io = ti8168_evm_map_io, + .init_irq = ti8168_evm_init_irq, + .timer = &omap_timer, + .init_machine = ti8168_evm_init, +MACHINE_END -- cgit v1.2.3 From fe5a4901c20c09b4380b7d4a0197efb6489c4ce8 Mon Sep 17 00:00:00 2001 From: Hema HK Date: Wed, 16 Feb 2011 17:34:40 +0530 Subject: usb: musb: AM35x: moving internal phy functions out of usb_musb.c file Moved all the board specific internal PHY functions out of usb_musb.c file as this file is shared between the OMAP2+ and AM35xx platforms. There exists a file which has the functions specific to internal PHY used for OMAP4 platform. Moved all phy specific functions to this file and passing these functions through board data in the board file. Signed-off-by: Hema HK Cc: Paul Walmsley Cc: Tony Lindgren Signed-off-by: Felipe Balbi --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/board-am3517evm.c | 4 ++ arch/arm/mach-omap2/omap_phy_internal.c | 93 +++++++++++++++++++++++++++++++ arch/arm/mach-omap2/usb-musb.c | 97 --------------------------------- arch/arm/plat-omap/include/plat/usb.h | 4 ++ 5 files changed, 103 insertions(+), 98 deletions(-) (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1c0c2b02d870..43d4e14d0ec9 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -218,7 +218,8 @@ obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \ hsmmc.o \ omap_phy_internal.o -obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o +obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o \ + omap_phy_internal.o \ obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 10d60b7743cf..3413bf993c7d 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -409,6 +409,10 @@ static struct omap_musb_board_data musb_board_data = { .interface_type = MUSB_INTERFACE_ULPI, .mode = MUSB_OTG, .power = 500, + .set_phy_power = am35x_musb_phy_power, + .clear_irq = am35x_musb_clear_irq, + .set_mode = am35x_musb_set_mode, + .reset = am35x_musb_reset, }; static __init void am3517_evm_musb_init(void) diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c index 745252c60e32..f172ec06c06a 100644 --- a/arch/arm/mach-omap2/omap_phy_internal.c +++ b/arch/arm/mach-omap2/omap_phy_internal.c @@ -29,6 +29,7 @@ #include #include +#include "control.h" /* OMAP control module register for UTMI PHY */ #define CONTROL_DEV_CONF 0x300 @@ -147,3 +148,95 @@ int omap4430_phy_exit(struct device *dev) return 0; } + +void am35x_musb_reset(void) +{ + u32 regval; + + /* Reset the musb interface */ + regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); + + regval |= AM35XX_USBOTGSS_SW_RST; + omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); + + regval &= ~AM35XX_USBOTGSS_SW_RST; + omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); + + regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); +} + +void am35x_musb_phy_power(u8 on) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(100); + u32 devconf2; + + if (on) { + /* + * Start the on-chip PHY and its PLL. + */ + devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); + + devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN); + devconf2 |= CONF2_PHY_PLLON; + + omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); + + pr_info(KERN_INFO "Waiting for PHY clock good...\n"); + while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2) + & CONF2_PHYCLKGD)) { + cpu_relax(); + + if (time_after(jiffies, timeout)) { + pr_err(KERN_ERR "musb PHY clock good timed out\n"); + break; + } + } + } else { + /* + * Power down the on-chip PHY. + */ + devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); + + devconf2 &= ~CONF2_PHY_PLLON; + devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN; + omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); + } +} + +void am35x_musb_clear_irq(void) +{ + u32 regval; + + regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); + regval |= AM35XX_USBOTGSS_INT_CLR; + omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR); + regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); +} + +void am35x_musb_set_mode(u8 musb_mode) +{ + u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); + + devconf2 &= ~CONF2_OTGMODE; + switch (musb_mode) { +#ifdef CONFIG_USB_MUSB_HDRC_HCD + case MUSB_HOST: /* Force VBUS valid, ID = 0 */ + devconf2 |= CONF2_FORCE_HOST; + break; +#endif +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */ + devconf2 |= CONF2_FORCE_DEVICE; + break; +#endif +#ifdef CONFIG_USB_MUSB_OTG + case MUSB_OTG: /* Don't override the VBUS/ID comparators */ + devconf2 |= CONF2_NO_OVERRIDE; + break; +#endif + default: + pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode); + } + + omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); +} diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index 5298949d4b11..9107883287f6 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -30,102 +30,9 @@ #include #include #include -#include "control.h" #if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X) -static void am35x_musb_reset(void) -{ - u32 regval; - - /* Reset the musb interface */ - regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); - - regval |= AM35XX_USBOTGSS_SW_RST; - omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); - - regval &= ~AM35XX_USBOTGSS_SW_RST; - omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); - - regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); -} - -static void am35x_musb_phy_power(u8 on) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(100); - u32 devconf2; - - if (on) { - /* - * Start the on-chip PHY and its PLL. - */ - devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); - - devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN); - devconf2 |= CONF2_PHY_PLLON; - - omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); - - pr_info(KERN_INFO "Waiting for PHY clock good...\n"); - while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2) - & CONF2_PHYCLKGD)) { - cpu_relax(); - - if (time_after(jiffies, timeout)) { - pr_err(KERN_ERR "musb PHY clock good timed out\n"); - break; - } - } - } else { - /* - * Power down the on-chip PHY. - */ - devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); - - devconf2 &= ~CONF2_PHY_PLLON; - devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN; - omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); - } -} - -static void am35x_musb_clear_irq(void) -{ - u32 regval; - - regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); - regval |= AM35XX_USBOTGSS_INT_CLR; - omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR); - regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); -} - -static void am35x_musb_set_mode(u8 musb_mode) -{ - u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); - - devconf2 &= ~CONF2_OTGMODE; - switch (musb_mode) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - case MUSB_HOST: /* Force VBUS valid, ID = 0 */ - devconf2 |= CONF2_FORCE_HOST; - break; -#endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */ - devconf2 |= CONF2_FORCE_DEVICE; - break; -#endif -#ifdef CONFIG_USB_MUSB_OTG - case MUSB_OTG: /* Don't override the VBUS/ID comparators */ - devconf2 |= CONF2_NO_OVERRIDE; - break; -#endif - default: - pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode); - } - - omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); -} - static struct resource musb_resources[] = { [0] = { /* start and end set dynamically */ .flags = IORESOURCE_MEM, @@ -189,10 +96,6 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data) musb_device.name = "musb-am35x"; musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE; musb_resources[1].start = INT_35XX_USBOTG_IRQ; - board_data->set_phy_power = am35x_musb_phy_power; - board_data->clear_irq = am35x_musb_clear_irq; - board_data->set_mode = am35x_musb_set_mode; - board_data->reset = am35x_musb_reset; } else if (cpu_is_omap34xx()) { musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE; } else if (cpu_is_omap44xx()) { diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h index 450a332f1009..077192759afc 100644 --- a/arch/arm/plat-omap/include/plat/usb.h +++ b/arch/arm/plat-omap/include/plat/usb.h @@ -91,6 +91,10 @@ extern int omap4430_phy_exit(struct device *dev); #endif +extern void am35x_musb_reset(void); +extern void am35x_musb_phy_power(u8 on); +extern void am35x_musb_clear_irq(void); +extern void am35x_musb_set_mode(u8 musb_mode); /* * FIXME correct answer depends on hmc_mode, -- cgit v1.2.3 From 7bb412a64281c599dcf00af2eed61ea997b282c2 Mon Sep 17 00:00:00 2001 From: Simon Que Date: Thu, 17 Feb 2011 09:52:03 -0800 Subject: omap: add hwspinlock device Build and register an hwspinlock platform device. Although only OMAP4 supports the hardware spinlock module (for now), it is still safe to run this initcall on all omaps, because hwmod lookup will simply fail on hwspinlock-less platforms. Signed-off-by: Simon Que Signed-off-by: Hari Kanigeri Signed-off-by: Ohad Ben-Cohen Cc: Benoit Cousson Cc: Kevin Hilman Cc: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/hwspinlock.c | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 arch/arm/mach-omap2/hwspinlock.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index a9e3974d015f..ec24999eefea 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -243,3 +243,4 @@ obj-y += $(smc91x-m) $(smc91x-y) smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o obj-y += $(smsc911x-m) $(smsc911x-y) +obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c new file mode 100644 index 000000000000..06d4a80660a5 --- /dev/null +++ b/arch/arm/mach-omap2/hwspinlock.c @@ -0,0 +1,63 @@ +/* + * OMAP hardware spinlock device initialization + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com + * + * Contact: Simon Que + * Hari Kanigeri + * + * 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. + */ + +#include +#include +#include + +#include +#include + +struct omap_device_pm_latency omap_spinlock_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + } +}; + +int __init hwspinlocks_init(void) +{ + int retval = 0; + struct omap_hwmod *oh; + struct omap_device *od; + const char *oh_name = "spinlock"; + const char *dev_name = "omap_hwspinlock"; + + /* + * Hwmod lookup will fail in case our platform doesn't support the + * hardware spinlock module, so it is safe to run this initcall + * on all omaps + */ + oh = omap_hwmod_lookup(oh_name); + if (oh == NULL) + return -EINVAL; + + od = omap_device_build(dev_name, 0, oh, NULL, 0, + omap_spinlock_latency, + ARRAY_SIZE(omap_spinlock_latency), false); + if (IS_ERR(od)) { + pr_err("Can't build omap_device for %s:%s\n", dev_name, + oh_name); + retval = PTR_ERR(od); + } + + return retval; +} +/* early board code might need to reserve specific hwspinlock instances */ +postcore_initcall(hwspinlocks_init); -- cgit v1.2.3 From b7ee79abcc1bd549eadf5a9852657058e6ecca47 Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Mon, 24 Jan 2011 06:21:54 +0000 Subject: OMAP2, 3: DSS2: Create new file display.c for central dss driver registration. A new file display.c is introduced for display driver init, which adds a function omap_display_init to do the DSS driver registration. This is the first step in moving away registration of DSS from board files into a common place. Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- arch/arm/mach-omap2/Makefile | 3 +++ arch/arm/mach-omap2/display.c | 45 +++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/display.h | 11 ++++++++ 3 files changed, 59 insertions(+) create mode 100644 arch/arm/mach-omap2/display.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ee72a9787bf1..1c3635d7f4cf 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -245,3 +245,6 @@ obj-y += $(smc91x-m) $(smc91x-y) smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o obj-y += $(smsc911x-m) $(smsc911x-y) obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o + +disp-$(CONFIG_OMAP2_DSS) := display.o +obj-y += $(disp-m) $(disp-y) diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c new file mode 100644 index 000000000000..b18db84b0349 --- /dev/null +++ b/arch/arm/mach-omap2/display.c @@ -0,0 +1,45 @@ +/* + * OMAP2plus display device setup / initialization. + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * Senthilvadivu Guruswamy + * Sumit Semwal + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include + +static struct platform_device omap_display_device = { + .name = "omapdss", + .id = -1, + .dev = { + .platform_data = NULL, + }, +}; + +int __init omap_display_init(struct omap_dss_board_info *board_data) +{ + int r = 0; + omap_display_device.dev.platform_data = board_data; + + r = platform_device_register(&omap_display_device); + if (r < 0) + printk(KERN_ERR "Unable to register OMAP-Display device\n"); + + return r; +} diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 537f4e449f50..0f140ecedb01 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #define DISPC_IRQ_FRAMEDONE (1 << 0) @@ -226,6 +227,16 @@ struct omap_dss_board_info { struct omap_dss_device *default_device; }; +#if defined(CONFIG_OMAP2_DSS_MODULE) || defined(CONFIG_OMAP2_DSS) +/* Init with the board info */ +extern int omap_display_init(struct omap_dss_board_info *board_data); +#else +static inline int omap_display_init(struct omap_dss_board_info *board_data) +{ + return 0; +} +#endif + struct omap_video_timings { /* Unit: pixels */ u16 x_res; -- cgit v1.2.3 From 4aef7a2a5aad52b60ac1a2f3cee055b8271b70d5 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 25 Feb 2011 16:06:47 -0700 Subject: OMAP: clockdomain: Arch specific funcs to handle deps Define the following architecture specific funtions for omap2/3 .clkdm_add_wkdep .clkdm_del_wkdep .clkdm_read_wkdep .clkdm_clear_all_wkdeps .clkdm_add_sleepdep .clkdm_del_sleepdep .clkdm_read_sleepdep .clkdm_clear_all_sleepdeps Convert the platform-independent framework to call these functions. With this also move the clkdm lookups for all wkdep_srcs and sleepdep_srcs at clkdm_init. Signed-off-by: Rajendra Nayak [paul@pwsan.com: fixed loop termination conditions in omap*_clkdm_clear_all_*(); thanks to Kevin Hilman for finding and helping fix those bugs; also avoid re-resolving clockdomains during init; abstracted out clkdm_dep walk] Cc: Kevin Hilman Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/Makefile | 2 + arch/arm/mach-omap2/clockdomain.c | 177 +++++++++++++---------- arch/arm/mach-omap2/clockdomain.h | 6 +- arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 130 +++++++++++++++++ arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c | 9 +- arch/arm/mach-omap2/io.c | 6 +- 6 files changed, 246 insertions(+), 84 deletions(-) create mode 100644 arch/arm/mach-omap2/clockdomain2xxx_3xxx.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ee72a9787bf1..759d9ebd79c6 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -102,8 +102,10 @@ obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \ # PRCM clockdomain control obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \ + clockdomain2xxx_3xxx.o \ clockdomains2xxx_3xxx_data.o obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \ + clockdomain2xxx_3xxx.o \ clockdomains2xxx_3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \ clockdomains44xx_data.o diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index f70b06ae8664..895c153c18e0 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -287,6 +287,32 @@ static void _disable_hwsup(struct clockdomain *clkdm) BUG(); } +/** + * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms + * @clkdm: clockdomain that we are resolving dependencies for + * @clkdm_deps: ptr to array of struct clkdm_deps to resolve + * + * Iterates through @clkdm_deps, looking up the struct clockdomain named by + * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. + * No return value. + */ +static void _resolve_clkdm_deps(struct clockdomain *clkdm, + struct clkdm_dep *clkdm_deps) +{ + struct clkdm_dep *cd; + + for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + if (cd->clkdm) + continue; + cd->clkdm = _clkdm_lookup(cd->clkdm_name); + + WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", + clkdm->name, cd->clkdm_name); + } +} + /* Public functions */ /** @@ -333,7 +359,10 @@ void clkdm_init(struct clockdomain **clkdms, else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) omap2_clkdm_deny_idle(clkdm); + _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs); clkdm_clear_all_wkdeps(clkdm); + + _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs); clkdm_clear_all_sleepdeps(clkdm); } } @@ -430,6 +459,7 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; + int ret = 0; if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { pr_err("clockdomain: %s/%s: %s: not yet implemented\n", @@ -441,21 +471,26 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) { + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) + ret = -EINVAL; + + if (ret) { pr_debug("clockdomain: hardware cannot set/clear wake up of " "%s when %s wakes up\n", clkdm1->name, clkdm2->name); - return PTR_ERR(cd); + return ret; } if (atomic_inc_return(&cd->wkdep_usecount) == 1) { pr_debug("clockdomain: hardware will wake up %s when %s wakes " "up\n", clkdm1->name, clkdm2->name); - omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); } - return 0; + return ret; } /** @@ -471,6 +506,7 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; + int ret = 0; if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { pr_err("clockdomain: %s/%s: %s: not yet implemented\n", @@ -482,21 +518,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) { + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) + ret = -EINVAL; + + if (ret) { pr_debug("clockdomain: hardware cannot set/clear wake up of " "%s when %s wakes up\n", clkdm1->name, clkdm2->name); - return PTR_ERR(cd); + return ret; } if (atomic_dec_return(&cd->wkdep_usecount) == 0) { pr_debug("clockdomain: hardware will no longer wake up %s " "after %s wakes up\n", clkdm1->name, clkdm2->name); - omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); } - return 0; + return ret; } /** @@ -516,6 +557,7 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; @@ -527,15 +569,20 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) } cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) { + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep) + ret = -EINVAL; + + if (ret) { pr_debug("clockdomain: hardware cannot set/clear wake up of " "%s when %s wakes up\n", clkdm1->name, clkdm2->name); - return PTR_ERR(cd); + return ret; } /* XXX It's faster to return the atomic wkdep_usecount */ - return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, - (1 << clkdm2->dep_bit)); + return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); } /** @@ -550,9 +597,6 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) */ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) { - struct clkdm_dep *cd; - u32 mask = 0; - if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { pr_err("clockdomain: %s: %s: not yet implemented\n", clkdm->name, __func__); @@ -562,21 +606,10 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) if (!clkdm) return -EINVAL; - for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { - if (!omap_chip_is(cd->omap_chip)) - continue; - - if (!cd->clkdm && cd->clkdm_name) - cd->clkdm = _clkdm_lookup(cd->clkdm_name); - - /* PRM accesses are slow, so minimize them */ - mask |= 1 << cd->clkdm->dep_bit; - atomic_set(&cd->wkdep_usecount, 0); - } - - omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP); + if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps) + return -EINVAL; - return 0; + return arch_clkdm->clkdm_clear_all_wkdeps(clkdm); } /** @@ -594,31 +627,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - - if (!cpu_is_omap34xx()) - return -EINVAL; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) { + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) + ret = -EINVAL; + + if (ret) { pr_debug("clockdomain: hardware cannot set/clear sleep " "dependency affecting %s from %s\n", clkdm1->name, clkdm2->name); - return PTR_ERR(cd); + return ret; } if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { pr_debug("clockdomain: will prevent %s from sleeping if %s " "is active\n", clkdm1->name, clkdm2->name); - omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, - OMAP3430_CM_SLEEPDEP); + ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); } - return 0; + return ret; } /** @@ -636,19 +671,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - - if (!cpu_is_omap34xx()) - return -EINVAL; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) { + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) + ret = -EINVAL; + + if (ret) { pr_debug("clockdomain: hardware cannot set/clear sleep " "dependency affecting %s from %s\n", clkdm1->name, clkdm2->name); - return PTR_ERR(cd); + return ret; } if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { @@ -656,12 +695,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) "sleeping if %s is active\n", clkdm1->name, clkdm2->name); - omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, - OMAP3430_CM_SLEEPDEP); + ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); } - return 0; + return ret; } /** @@ -683,25 +720,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - - if (!cpu_is_omap34xx()) - return -EINVAL; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) { + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep) + ret = -EINVAL; + + if (ret) { pr_debug("clockdomain: hardware cannot set/clear sleep " "dependency affecting %s from %s\n", clkdm1->name, clkdm2->name); - return PTR_ERR(cd); + return ret; } /* XXX It's faster to return the atomic sleepdep_usecount */ - return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, - OMAP3430_CM_SLEEPDEP, - (1 << clkdm2->dep_bit)); + return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); } /** @@ -716,31 +755,13 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) */ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) { - struct clkdm_dep *cd; - u32 mask = 0; - - if (!cpu_is_omap34xx()) - return -EINVAL; - if (!clkdm) return -EINVAL; - for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { - if (!omap_chip_is(cd->omap_chip)) - continue; - - if (!cd->clkdm && cd->clkdm_name) - cd->clkdm = _clkdm_lookup(cd->clkdm_name); - - /* PRM accesses are slow, so minimize them */ - mask |= 1 << cd->clkdm->dep_bit; - atomic_set(&cd->sleepdep_usecount, 0); - } - - omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, - OMAP3430_CM_SLEEPDEP); + if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps) + return -EINVAL; - return 0; + return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm); } /** diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index 71ad265cf133..90b6d6a50862 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -176,7 +176,11 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm); int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk); -extern void __init omap2_clockdomains_init(void); +extern void __init omap2xxx_clockdomains_init(void); +extern void __init omap3xxx_clockdomains_init(void); extern void __init omap44xx_clockdomains_init(void); +extern struct clkdm_ops omap2_clkdm_operations; +extern struct clkdm_ops omap3_clkdm_operations; + #endif diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c new file mode 100644 index 000000000000..a1fd6fd5a466 --- /dev/null +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c @@ -0,0 +1,130 @@ +/* + * OMAP2 and OMAP3 clockdomain control + * + * Copyright (C) 2008-2010 Texas Instruments, Inc. + * Copyright (C) 2008-2010 Nokia Corporation + * + * Derived from mach-omap2/clockdomain.c written by Paul Walmsley + * Rajendra Nayak + * + * 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. + */ + +#include +#include +#include "prm.h" +#include "prm2xxx_3xxx.h" +#include "cm.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" +#include "cm-regbits-34xx.h" +#include "clockdomain.h" + +static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + return 0; +} + +static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + return 0; +} + +static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, + PM_WKDEP, (1 << clkdm2->dep_bit)); +} + +static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) +{ + struct clkdm_dep *cd; + u32 mask = 0; + + for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + if (!cd->clkdm) + continue; /* only happens if data is erroneous */ + + /* PRM accesses are slow, so minimize them */ + mask |= 1 << cd->clkdm->dep_bit; + atomic_set(&cd->wkdep_usecount, 0); + } + + omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, + PM_WKDEP); + return 0; +} + +static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + return 0; +} + +static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + return 0; +} + +static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit)); +} + +static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) +{ + struct clkdm_dep *cd; + u32 mask = 0; + + for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + if (!cd->clkdm) + continue; /* only happens if data is erroneous */ + + /* PRM accesses are slow, so minimize them */ + mask |= 1 << cd->clkdm->dep_bit; + atomic_set(&cd->sleepdep_usecount, 0); + } + omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + return 0; +} + +struct clkdm_ops omap2_clkdm_operations = { + .clkdm_add_wkdep = omap2_clkdm_add_wkdep, + .clkdm_del_wkdep = omap2_clkdm_del_wkdep, + .clkdm_read_wkdep = omap2_clkdm_read_wkdep, + .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, +}; + +struct clkdm_ops omap3_clkdm_operations = { + .clkdm_add_wkdep = omap2_clkdm_add_wkdep, + .clkdm_del_wkdep = omap2_clkdm_del_wkdep, + .clkdm_read_wkdep = omap2_clkdm_read_wkdep, + .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, + .clkdm_add_sleepdep = omap3_clkdm_add_sleepdep, + .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep, + .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep, + .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps, +}; diff --git a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c index e2a959eab312..ffdfe54f3264 100644 --- a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c +++ b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c @@ -854,7 +854,12 @@ static struct clockdomain *clockdomains_omap2[] __initdata = { NULL, }; -void __init omap2_clockdomains_init(void) +void __init omap2xxx_clockdomains_init(void) { - clkdm_init(clockdomains_omap2, clkdm_autodeps, NULL); + clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap2_clkdm_operations); +} + +void __init omap3xxx_clockdomains_init(void) +{ + clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap3_clkdm_operations); } diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index b8b49e4ae928..03f71ec3cd82 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -357,15 +357,15 @@ void __init omap2_init_common_infrastructure(void) if (cpu_is_omap242x()) { omap2xxx_powerdomains_init(); - omap2_clockdomains_init(); + omap2xxx_clockdomains_init(); omap2420_hwmod_init(); } else if (cpu_is_omap243x()) { omap2xxx_powerdomains_init(); - omap2_clockdomains_init(); + omap2xxx_clockdomains_init(); omap2430_hwmod_init(); } else if (cpu_is_omap34xx()) { omap3xxx_powerdomains_init(); - omap2_clockdomains_init(); + omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); } else if (cpu_is_omap44xx()) { omap44xx_powerdomains_init(); -- cgit v1.2.3 From 68b921ad7f35e0323ce0d9fe94e5701a112f257c Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 25 Feb 2011 16:06:47 -0700 Subject: OMAP: clockdomain: Arch specific funcs for sleep/wakeup of clkdm Define the following architecture specific funtions for omap2/3/4 .clkdm_sleep .clkdm_wakeup Convert the platform-independent framework to call these functions. Also rename the api's by removing the omap2_ preamble. Hence call omap2_clkdm_wakeup as clkdm_wakeup and omap2_clkdm_sleep as clkdm_sleep. Signed-off-by: Rajendra Nayak [paul@pwsan.com: fixed omap3_clkdm_clear_all_sleepdeps() and omap2_clkdm_clear_all_wkdeps() to test against the correct loop termination condition; thanks to Kevin Hilman for finding and helping fix] Cc: Kevin Hilman Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/clockdomain.c | 64 +++++++---------------------- arch/arm/mach-omap2/clockdomain.h | 5 ++- arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 35 ++++++++++++++++ arch/arm/mach-omap2/clockdomain44xx.c | 35 ++++++++++++++++ arch/arm/mach-omap2/clockdomains44xx_data.c | 2 +- arch/arm/mach-omap2/pm.c | 4 +- arch/arm/mach-omap2/pm24xx.c | 6 +-- arch/arm/mach-omap2/pm34xx.c | 2 +- 9 files changed, 96 insertions(+), 58 deletions(-) create mode 100644 arch/arm/mach-omap2/clockdomain44xx.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 759d9ebd79c6..10c3c8f16eaa 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -108,6 +108,7 @@ obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \ clockdomain2xxx_3xxx.o \ clockdomains2xxx_3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \ + clockdomain44xx.o \ clockdomains44xx_data.o # Clock framework obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \ diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 895c153c18e0..3035eb9eec36 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -355,7 +355,7 @@ void clkdm_init(struct clockdomain **clkdms, */ list_for_each_entry(clkdm, &clkdm_list, node) { if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) - omap2_clkdm_wakeup(clkdm); + clkdm_wakeup(clkdm); else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) omap2_clkdm_deny_idle(clkdm); @@ -765,7 +765,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) } /** - * omap2_clkdm_sleep - force clockdomain sleep transition + * clkdm_sleep - force clockdomain sleep transition * @clkdm: struct clockdomain * * * Instruct the CM to force a sleep transition on the specified @@ -773,7 +773,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) * clockdomain does not support software-initiated sleep; 0 upon * success. */ -int omap2_clkdm_sleep(struct clockdomain *clkdm) +int clkdm_sleep(struct clockdomain *clkdm) { if (!clkdm) return -EINVAL; @@ -784,33 +784,16 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) return -EINVAL; } - pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); - - if (cpu_is_omap24xx()) { - - omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, - clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); - - } else if (cpu_is_omap34xx()) { - - omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - - } else if (cpu_is_omap44xx()) { - - omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition, - clkdm->cm_inst, - clkdm->clkdm_offs); + if (!arch_clkdm || !arch_clkdm->clkdm_sleep) + return -EINVAL; - } else { - BUG(); - }; + pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); - return 0; + return arch_clkdm->clkdm_sleep(clkdm); } /** - * omap2_clkdm_wakeup - force clockdomain wakeup transition + * clkdm_wakeup - force clockdomain wakeup transition * @clkdm: struct clockdomain * * * Instruct the CM to force a wakeup transition on the specified @@ -818,7 +801,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) * clockdomain does not support software-controlled wakeup; 0 upon * success. */ -int omap2_clkdm_wakeup(struct clockdomain *clkdm) +int clkdm_wakeup(struct clockdomain *clkdm) { if (!clkdm) return -EINVAL; @@ -829,29 +812,12 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return -EINVAL; } - pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); - - if (cpu_is_omap24xx()) { - - omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, - clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); - - } else if (cpu_is_omap34xx()) { - - omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - - } else if (cpu_is_omap44xx()) { - - omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition, - clkdm->cm_inst, - clkdm->clkdm_offs); + if (!arch_clkdm || !arch_clkdm->clkdm_wakeup) + return -EINVAL; - } else { - BUG(); - }; + pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); - return 0; + return arch_clkdm->clkdm_wakeup(clkdm); } /** @@ -990,7 +956,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) _clkdm_add_autodeps(clkdm); _enable_hwsup(clkdm); } else { - omap2_clkdm_wakeup(clkdm); + clkdm_wakeup(clkdm); } pwrdm_wait_transition(clkdm->pwrdm.ptr); @@ -1062,7 +1028,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) _clkdm_del_autodeps(clkdm); _enable_hwsup(clkdm); } else { - omap2_clkdm_sleep(clkdm); + clkdm_sleep(clkdm); } pwrdm_clkdm_state_switch(clkdm); diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index 90b6d6a50862..7a5cb5cf9949 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -170,8 +170,8 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); void omap2_clkdm_allow_idle(struct clockdomain *clkdm); void omap2_clkdm_deny_idle(struct clockdomain *clkdm); -int omap2_clkdm_wakeup(struct clockdomain *clkdm); -int omap2_clkdm_sleep(struct clockdomain *clkdm); +int clkdm_wakeup(struct clockdomain *clkdm); +int clkdm_sleep(struct clockdomain *clkdm); int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk); @@ -182,5 +182,6 @@ extern void __init omap44xx_clockdomains_init(void); extern struct clkdm_ops omap2_clkdm_operations; extern struct clkdm_ops omap3_clkdm_operations; +extern struct clkdm_ops omap4_clkdm_operations; #endif diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c index a1fd6fd5a466..08c87fe3da12 100644 --- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c @@ -20,6 +20,7 @@ #include "cm2xxx_3xxx.h" #include "cm-regbits-24xx.h" #include "cm-regbits-34xx.h" +#include "prm-regbits-24xx.h" #include "clockdomain.h" static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1, @@ -111,11 +112,43 @@ static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) return 0; } +static int omap2_clkdm_sleep(struct clockdomain *clkdm) +{ + omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, + clkdm->pwrdm.ptr->prcm_offs, + OMAP2_PM_PWSTCTRL); + return 0; +} + +static int omap2_clkdm_wakeup(struct clockdomain *clkdm) +{ + omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, + clkdm->pwrdm.ptr->prcm_offs, + OMAP2_PM_PWSTCTRL); + return 0; +} + +static int omap3_clkdm_sleep(struct clockdomain *clkdm) +{ + omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + return 0; +} + +static int omap3_clkdm_wakeup(struct clockdomain *clkdm) +{ + omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + return 0; +} + struct clkdm_ops omap2_clkdm_operations = { .clkdm_add_wkdep = omap2_clkdm_add_wkdep, .clkdm_del_wkdep = omap2_clkdm_del_wkdep, .clkdm_read_wkdep = omap2_clkdm_read_wkdep, .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, + .clkdm_sleep = omap2_clkdm_sleep, + .clkdm_wakeup = omap2_clkdm_wakeup, }; struct clkdm_ops omap3_clkdm_operations = { @@ -127,4 +160,6 @@ struct clkdm_ops omap3_clkdm_operations = { .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep, .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep, .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps, + .clkdm_sleep = omap3_clkdm_sleep, + .clkdm_wakeup = omap3_clkdm_wakeup, }; diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c new file mode 100644 index 000000000000..9ccb406cf54f --- /dev/null +++ b/arch/arm/mach-omap2/clockdomain44xx.c @@ -0,0 +1,35 @@ +/* + * OMAP4 clockdomain control + * + * Copyright (C) 2008-2010 Texas Instruments, Inc. + * Copyright (C) 2008-2010 Nokia Corporation + * + * Derived from mach-omap2/clockdomain.c written by Paul Walmsley + * Rajendra Nayak + * + * 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. + */ + +#include "clockdomain.h" +#include "cminst44xx.h" + +static int omap4_clkdm_sleep(struct clockdomain *clkdm) +{ + omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition, + clkdm->cm_inst, clkdm->clkdm_offs); + return 0; +} + +static int omap4_clkdm_wakeup(struct clockdomain *clkdm) +{ + omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition, + clkdm->cm_inst, clkdm->clkdm_offs); + return 0; +} + +struct clkdm_ops omap4_clkdm_operations = { + .clkdm_sleep = omap4_clkdm_sleep, + .clkdm_wakeup = omap4_clkdm_wakeup, +}; diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c index a5000d473d45..eea6f8e40289 100644 --- a/arch/arm/mach-omap2/clockdomains44xx_data.c +++ b/arch/arm/mach-omap2/clockdomains44xx_data.c @@ -305,5 +305,5 @@ static struct clockdomain *clockdomains_omap44xx[] __initdata = { void __init omap44xx_clockdomains_init(void) { - clkdm_init(clockdomains_omap44xx, NULL, NULL); + clkdm_init(clockdomains_omap44xx, NULL, &omap4_clkdm_operations); } diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index d5a102c71989..74c31008079c 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -124,7 +124,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { sleep_switch = LOWPOWERSTATE_SWITCH; } else { - omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); + clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); sleep_switch = FORCEWAKEUP_SWITCH; } @@ -142,7 +142,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO) omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); else - omap2_clkdm_sleep(pwrdm->pwrdm_clkdms[0]); + clkdm_sleep(pwrdm->pwrdm_clkdms[0]); break; case LOWPOWERSTATE_SWITCH: pwrdm_set_lowpwrstchange(pwrdm); diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 97feb3ab6a69..4125621bf591 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -370,7 +370,7 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) omap2_clkdm_allow_idle(clkdm); else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && atomic_read(&clkdm->usecount) == 0) - omap2_clkdm_sleep(clkdm); + clkdm_sleep(clkdm); return 0; } @@ -405,11 +405,11 @@ static void __init prcm_setup_regs(void) pwrdm = clkdm_get_pwrdm(dsp_clkdm); pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); - omap2_clkdm_sleep(dsp_clkdm); + clkdm_sleep(dsp_clkdm); pwrdm = clkdm_get_pwrdm(gfx_clkdm); pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); - omap2_clkdm_sleep(gfx_clkdm); + clkdm_sleep(gfx_clkdm); /* * Clear clockdomain wakeup dependencies and enable diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 2f864e4b085d..81df2b169a56 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -993,7 +993,7 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) omap2_clkdm_allow_idle(clkdm); else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && atomic_read(&clkdm->usecount) == 0) - omap2_clkdm_sleep(clkdm); + clkdm_sleep(clkdm); return 0; } -- cgit v1.2.3 From 97f678989afe5dd1584a0877dfd8b0d2e124b73a Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 25 Feb 2011 15:49:01 -0700 Subject: OMAP4: DPLL: Add dpll api to control GATE_CTRL On OMAP4, the dpll post divider outputs (MX outputs) along with clockout_x2 output provide a way to allow/deny hardware level autogating. Allowing autoidle would mean that the hw would autogate this clock when there is no dependency for it. Denying idle would mean that this clock output will be forced to stay enabled. Add dpll api's to read/allow/deny idle control for these dpll mx postdividers. NOTE: The gatectrl bit set to 0 allows gatectrl, and the bit set to 1 denies gatectrl. Signed-off-by: Rajendra Nayak [paul@pwsan.com: moved OMAP4-specific DPLL control code to mach-omap2/dpll44xx.c; added some documentation for CLOCK_CLKOUTX2] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/clock.h | 3 ++ arch/arm/mach-omap2/dpll44xx.c | 78 +++++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/clock.h | 14 +++++- 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-omap2/dpll44xx.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 10c3c8f16eaa..89274a9f0357 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -123,7 +123,7 @@ obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ clock3517.o clock36xx.o \ dpll3xxx.o clock3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \ - dpll3xxx.o + dpll3xxx.o dpll44xx.o # OMAP2 clock rate set data (old "OPP" data) obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 2a939e5ec6a2..c450d69a0dce 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -65,6 +65,9 @@ u32 omap3_dpll_autoidle_read(struct clk *clk); int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate); int omap3_noncore_dpll_enable(struct clk *clk); void omap3_noncore_dpll_disable(struct clk *clk); +int omap4_dpllmx_gatectrl_read(struct clk *clk); +void omap4_dpllmx_allow_gatectrl(struct clk *clk); +void omap4_dpllmx_deny_gatectrl(struct clk *clk); #ifdef CONFIG_OMAP_RESET_CLOCKS void omap2_clk_disable_unused(struct clk *clk); diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c new file mode 100644 index 000000000000..94a3592cd54c --- /dev/null +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -0,0 +1,78 @@ +/* + * OMAP4-specific DPLL control functions + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Rajendra Nayak + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "clock.h" +#include "cm-regbits-44xx.h" + +/* Supported only on OMAP4 */ +int omap4_dpllmx_gatectrl_read(struct clk *clk) +{ + u32 v; + u32 mask; + + if (!clk || !clk->clksel_reg || !cpu_is_omap44xx()) + return -EINVAL; + + mask = clk->flags & CLOCK_CLKOUTX2 ? + OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : + OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; + + v = __raw_readl(clk->clksel_reg); + v &= mask; + v >>= __ffs(mask); + + return v; +} + +void omap4_dpllmx_allow_gatectrl(struct clk *clk) +{ + u32 v; + u32 mask; + + if (!clk || !clk->clksel_reg || !cpu_is_omap44xx()) + return; + + mask = clk->flags & CLOCK_CLKOUTX2 ? + OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : + OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; + + v = __raw_readl(clk->clksel_reg); + /* Clear the bit to allow gatectrl */ + v &= ~mask; + __raw_writel(v, clk->clksel_reg); +} + +void omap4_dpllmx_deny_gatectrl(struct clk *clk) +{ + u32 v; + u32 mask; + + if (!clk || !clk->clksel_reg || !cpu_is_omap44xx()) + return; + + mask = clk->flags & CLOCK_CLKOUTX2 ? + OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : + OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; + + v = __raw_readl(clk->clksel_reg); + /* Set the bit to deny gatectrl */ + v |= mask; + __raw_writel(v, clk->clksel_reg); +} diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index be69f5cac32d..dcd7bb81420d 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -176,12 +176,24 @@ struct dpll_data { #endif -/* struct clk.flags possibilities */ +/* + * struct clk.flags possibilities + * + * XXX document the rest of the clock flags here + * + * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL + * bits share the same register. This flag allows the + * omap4_dpllmx*() code to determine which GATE_CTRL bit field + * should be used. This is a temporary solution - a better approach + * would be to associate clock type-specific data with the clock, + * similar to the struct dpll_data approach. + */ #define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */ #define CLOCK_IDLE_CONTROL (1 << 1) #define CLOCK_NO_IDLE_PARENT (1 << 2) #define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */ #define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */ +#define CLOCK_CLKOUTX2 (1 << 5) /** * struct clk - OMAP struct clk -- cgit v1.2.3 From 0fd0c21be71293d8a54d9075b18b5a25a1868057 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Fri, 25 Feb 2011 15:49:53 -0700 Subject: OMAP2: clock: add DPLL autoidle support Add the necessary code and data to allow the clock framework to enable and disable the OMAP2 DPLL autoidle state. This is so the direct register access can be moved out of the mach-omap2/pm24xx.c code, and other code that needs to control this (e.g., CPUIdle) can do so via an API. As part of this patch, remove the pm24xx.c code that formerly wrote directly to the autoidle bits. Signed-off-by: Paul Walmsley Cc: Kevin Hilman Tested-by: Rajendra Nayak Reviewed-by: Kevin Hilman --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt2xxx_dpll.c | 63 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock.h | 1 + arch/arm/mach-omap2/clock2420_data.c | 2 +- arch/arm/mach-omap2/clock2430_data.c | 2 +- arch/arm/mach-omap2/cm2xxx_3xxx.c | 27 ++++++++++++++++ arch/arm/mach-omap2/cm2xxx_3xxx.h | 3 ++ arch/arm/mach-omap2/pm24xx.c | 12 ++++--- 8 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt2xxx_dpll.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 89274a9f0357..ae44645551c2 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -115,7 +115,8 @@ obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \ clkt2xxx_sys.o \ clkt2xxx_dpllcore.o \ clkt2xxx_virt_prcm_set.o \ - clkt2xxx_apll.o clkt2xxx_osc.o + clkt2xxx_apll.o clkt2xxx_osc.o \ + clkt2xxx_dpll.o obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ diff --git a/arch/arm/mach-omap2/clkt2xxx_dpll.c b/arch/arm/mach-omap2/clkt2xxx_dpll.c new file mode 100644 index 000000000000..1502a7bc20bb --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_dpll.c @@ -0,0 +1,63 @@ +/* + * OMAP2-specific DPLL control functions + * + * Copyright (C) 2011 Nokia Corporation + * 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. + */ + +#include +#include +#include +#include + +#include + +#include "clock.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +/* Private functions */ + +/** + * _allow_idle - enable DPLL autoidle bits + * @clk: struct clk * of the DPLL to operate on + * + * Enable DPLL automatic idle control. The DPLL will enter low-power + * stop when its downstream clocks are gated. No return value. + * REVISIT: DPLL can optionally enter low-power bypass by writing 0x1 + * instead. Add some mechanism to optionally enter this mode. + */ +static void _allow_idle(struct clk *clk) +{ + if (!clk || !clk->dpll_data) + return; + + omap2xxx_cm_set_dpll_auto_low_power_stop(); +} + +/** + * _deny_idle - prevent DPLL from automatically idling + * @clk: struct clk * of the DPLL to operate on + * + * Disable DPLL automatic idle control. No return value. + */ +static void _deny_idle(struct clk *clk) +{ + if (!clk || !clk->dpll_data) + return; + + omap2xxx_cm_set_dpll_disable_autoidle(); +} + + +/* Public data */ + +const struct clkops clkops_omap2xxx_dpll_ops = { + .allow_idle = _allow_idle, + .deny_idle = _deny_idle, +}; + diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 0725a6ad8b46..9972d892a4af 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -148,6 +148,7 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) #define omap2_clk_exit_cpufreq_table 0 #endif +extern const struct clkops clkops_omap2xxx_dpll_ops; extern const struct clkops clkops_omap3_noncore_dpll_ops; extern const struct clkops clkops_omap3_core_dpll_ops; extern const struct clkops clkops_omap4_dpllmx_ops; diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index ee73e14ac3c8..30fbcbd0ed81 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = { */ static struct clk dpll_ck = { .name = "dpll_ck", - .ops = &clkops_null, + .ops = &clkops_omap2xxx_dpll_ops, .parent = &sys_ck, /* Can be func_32k also */ .dpll_data = &dpll_dd, .clkdm_name = "wkup_clkdm", diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c index a1298e55d915..1ff150a0f304 100644 --- a/arch/arm/mach-omap2/clock2430_data.c +++ b/arch/arm/mach-omap2/clock2430_data.c @@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = { */ static struct clk dpll_ck = { .name = "dpll_ck", - .ops = &clkops_null, + .ops = &clkops_omap2xxx_dpll_ops, .parent = &sys_ck, /* Can be func_32k also */ .dpll_data = &dpll_dd, .clkdm_name = "wkup_clkdm", diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.c b/arch/arm/mach-omap2/cm2xxx_3xxx.c index 96954aa48671..6b0c7c85ef53 100644 --- a/arch/arm/mach-omap2/cm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/cm2xxx_3xxx.c @@ -25,6 +25,10 @@ #include "cm-regbits-24xx.h" #include "cm-regbits-34xx.h" +/* CM_AUTOIDLE_PLL.AUTO_* bit values */ +#define DPLL_AUTOIDLE_DISABLE 0x0 +#define OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP 0x3 + static const u8 cm_idlest_offs[] = { CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3 }; @@ -125,6 +129,29 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask); } +/* + * DPLL autoidle control + */ + +static void _omap2xxx_set_dpll_autoidle(u8 m) +{ + u32 v; + + v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); + v &= ~OMAP24XX_AUTO_DPLL_MASK; + v |= m << OMAP24XX_AUTO_DPLL_SHIFT; + omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE); +} + +void omap2xxx_cm_set_dpll_disable_autoidle(void) +{ + _omap2xxx_set_dpll_autoidle(OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP); +} + +void omap2xxx_cm_set_dpll_auto_low_power_stop(void) +{ + _omap2xxx_set_dpll_autoidle(DPLL_AUTOIDLE_DISABLE); +} /* * diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.h b/arch/arm/mach-omap2/cm2xxx_3xxx.h index 5e9ea5bd60b9..5f4df1ceafad 100644 --- a/arch/arm/mach-omap2/cm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/cm2xxx_3xxx.h @@ -122,6 +122,9 @@ extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask); extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask); +extern void omap2xxx_cm_set_dpll_disable_autoidle(void); +extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void); + #endif /* CM register bits shared between 24XX and 3430 */ diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index e983c8301f55..297bb21061b8 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -378,6 +378,7 @@ static void __init prcm_setup_regs(void) { int i, num_mem_banks; struct powerdomain *pwrdm; + u32 v; /* Enable autoidle */ omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD, @@ -468,11 +469,12 @@ static void __init prcm_setup_regs(void) omap2_cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI_MASK, OMAP24XX_DSP_MOD, CM_AUTOIDLE); - /* Put DPLL and both APLLs into autoidle mode */ - omap2_cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) | - (0x03 << OMAP24XX_AUTO_96M_SHIFT) | - (0x03 << OMAP24XX_AUTO_54M_SHIFT), - PLL_MOD, CM_AUTOIDLE); + /* Put both APLLs into autoidle mode */ + v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); + v &= ~(OMAP24XX_AUTO_96M_MASK | OMAP24XX_AUTO_54M_SHIFT); + v |= (0x03 << OMAP24XX_AUTO_96M_SHIFT) | + (0x03 << OMAP24XX_AUTO_54M_SHIFT); + omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE); omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK | OMAP24XX_AUTO_WDT1_MASK | -- cgit v1.2.3 From 530e544fdadb934470c5c2b0e8d60c3d5386c161 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Fri, 25 Feb 2011 15:39:28 -0700 Subject: OMAP2+: clock: add interface clock type code with autoidle support Add interface clock type code with autoidle enable/disable support. The clkops structures created in this file will be used for all OMAP2/3 interface clocks with autoidle support. They will enable the clock framework to control interface clock autoidle directly. Signed-off-by: Paul Walmsley Tested-by: Rajendra Nayak Reviewed-by: Kevin Hilman --- arch/arm/mach-omap2/Makefile | 6 ++-- arch/arm/mach-omap2/clkt_iclk.c | 73 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock.h | 9 ++++- 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt_iclk.c (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ae44645551c2..c5b1be9b7328 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -110,19 +110,21 @@ obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \ obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \ clockdomain44xx.o \ clockdomains44xx_data.o + # Clock framework obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \ clkt2xxx_sys.o \ clkt2xxx_dpllcore.o \ clkt2xxx_virt_prcm_set.o \ clkt2xxx_apll.o clkt2xxx_osc.o \ - clkt2xxx_dpll.o + clkt2xxx_dpll.o clkt_iclk.o obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ clock34xx.o clkt34xx_dpll3m2.o \ clock3517.o clock36xx.o \ - dpll3xxx.o clock3xxx_data.o + dpll3xxx.o clock3xxx_data.o \ + clkt_iclk.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \ dpll3xxx.o dpll44xx.o diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c new file mode 100644 index 000000000000..dd8a6d3dc011 --- /dev/null +++ b/arch/arm/mach-omap2/clkt_iclk.c @@ -0,0 +1,73 @@ +/* + * OMAP2/3 interface clock control + * + * Copyright (C) 2011 Nokia Corporation + * 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. + */ +#undef DEBUG + +#include +#include +#include + +#include +#include + +#include "clock.h" +#include "clock2xxx.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +/* Private functions */ + +/* XXX */ +void omap2_clkt_iclk_allow_idle(struct clk *clk) +{ + u32 v, r; + + r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = __raw_readl((__force void __iomem *)r); + v |= (1 << clk->enable_bit); + __raw_writel(v, (__force void __iomem *)r); +} + +/* XXX */ +void omap2_clkt_iclk_deny_idle(struct clk *clk) +{ + u32 v, r; + + r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = __raw_readl((__force void __iomem *)r); + v &= ~(1 << clk->enable_bit); + __raw_writel(v, (__force void __iomem *)r); +} + +/* Public data */ + +const struct clkops clkops_omap2_iclk_dflt_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_companion = omap2_clk_dflt_find_companion, + .find_idlest = omap2_clk_dflt_find_idlest, + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clkops clkops_omap2_iclk_dflt = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clkops clkops_omap2_iclk_idle_only = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 9972d892a4af..5008f14448ef 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -2,7 +2,7 @@ * linux/arch/arm/mach-omap2/clock.h * * Copyright (C) 2005-2009 Texas Instruments, Inc. - * Copyright (C) 2004-2009 Nokia Corporation + * Copyright (C) 2004-2011 Nokia Corporation * * Contacts: * Richard Woodruff @@ -86,6 +86,10 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); +/* clkt_iclk.c public functions */ +extern void omap2_clkt_iclk_allow_idle(struct clk *clk); +extern void omap2_clkt_iclk_deny_idle(struct clk *clk); + u32 omap2_get_dpll_rate(struct clk *clk); void omap2_init_dpll_parent(struct clk *clk); @@ -148,6 +152,9 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) #define omap2_clk_exit_cpufreq_table 0 #endif +extern const struct clkops clkops_omap2_iclk_dflt_wait; +extern const struct clkops clkops_omap2_iclk_dflt; +extern const struct clkops clkops_omap2_iclk_idle_only; extern const struct clkops clkops_omap2xxx_dpll_ops; extern const struct clkops clkops_omap3_noncore_dpll_ops; extern const struct clkops clkops_omap3_core_dpll_ops; -- cgit v1.2.3 From e2fa61d409195550b3b05b213d7715bc67b0e855 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 7 Mar 2011 19:35:20 +0530 Subject: OMAP3: l3: Introduce l3-interconnect error handling driver The driver provides the information regarding the ocp errors that gets logged in the interconnect.The error info provides the details regarding the master or the target that generated the error, type of error and the corresponding address. The stack dump is also provided. Signed-off-by: sricharan [r.sricharan@ti.com: Enhacements, major cleanup and made it functional] Signed-off-by: Santosh Shilimkar [santosh.shilimkar@ti.com: Driver design changes as per OMAP4 version] Signed-off-by: Felipe Balbi [balbi@ti.com: Initial version of the driver] Acked-by: Benoit Cousson --- arch/arm/mach-omap2/Makefile | 3 + arch/arm/mach-omap2/omap_l3_smx.c | 314 +++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/omap_l3_smx.h | 338 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 655 insertions(+) create mode 100644 arch/arm/mach-omap2/omap_l3_smx.c create mode 100644 arch/arm/mach-omap2/omap_l3_smx.h (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1c3635d7f4cf..e4c9bb3ad894 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -135,6 +135,9 @@ obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o # EMU peripherals obj-$(CONFIG_OMAP3_EMU) += emu.o +# L3 interconnect +obj-$(CONFIG_ARCH_OMAP3) += omap_l3_smx.o + obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/arch/arm/mach-omap2/omap_l3_smx.c new file mode 100644 index 000000000000..265bff3acb9e --- /dev/null +++ b/arch/arm/mach-omap2/omap_l3_smx.c @@ -0,0 +1,314 @@ + /* + * OMAP3XXX L3 Interconnect Driver + * + * Copyright (C) 2011 Texas Corporation + * Felipe Balbi + * Santosh Shilimkar + * Sricharan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include +#include +#include +#include +#include +#include "omap_l3_smx.h" + +static inline u64 omap3_l3_readll(void __iomem *base, u16 reg) +{ + return __raw_readll(base + reg); +} + +static inline void omap3_l3_writell(void __iomem *base, u16 reg, u64 value) +{ + __raw_writell(value, base + reg); +} + +static inline enum omap3_l3_code omap3_l3_decode_error_code(u64 error) +{ + return (error & 0x0f000000) >> L3_ERROR_LOG_CODE; +} + +static inline u32 omap3_l3_decode_addr(u64 error_addr) +{ + return error_addr & 0xffffffff; +} + +static inline unsigned omap3_l3_decode_cmd(u64 error) +{ + return (error & 0x07) >> L3_ERROR_LOG_CMD; +} + +static inline enum omap3_l3_initiator_id omap3_l3_decode_initid(u64 error) +{ + return (error & 0xff00) >> L3_ERROR_LOG_INITID; +} + +static inline unsigned omap3_l3_decode_req_info(u64 error) +{ + return (error >> 32) & 0xffff; +} + +static char *omap3_l3_code_string(u8 code) +{ + switch (code) { + case OMAP_L3_CODE_NOERROR: + return "No Error"; + case OMAP_L3_CODE_UNSUP_CMD: + return "Unsupported Command"; + case OMAP_L3_CODE_ADDR_HOLE: + return "Address Hole"; + case OMAP_L3_CODE_PROTECT_VIOLATION: + return "Protection Violation"; + case OMAP_L3_CODE_IN_BAND_ERR: + return "In-band Error"; + case OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT: + return "Request Timeout Not Accepted"; + case OMAP_L3_CODE_REQ_TOUT_NO_RESP: + return "Request Timeout, no response"; + default: + return "UNKNOWN error"; + } +} + +static char *omap3_l3_initiator_string(u8 initid) +{ + switch (initid) { + case OMAP_L3_LCD: + return "LCD"; + case OMAP_L3_SAD2D: + return "SAD2D"; + case OMAP_L3_IA_MPU_SS_1: + case OMAP_L3_IA_MPU_SS_2: + case OMAP_L3_IA_MPU_SS_3: + case OMAP_L3_IA_MPU_SS_4: + case OMAP_L3_IA_MPU_SS_5: + return "MPU"; + case OMAP_L3_IA_IVA_SS_1: + case OMAP_L3_IA_IVA_SS_2: + case OMAP_L3_IA_IVA_SS_3: + return "IVA_SS"; + case OMAP_L3_IA_IVA_SS_DMA_1: + case OMAP_L3_IA_IVA_SS_DMA_2: + case OMAP_L3_IA_IVA_SS_DMA_3: + case OMAP_L3_IA_IVA_SS_DMA_4: + case OMAP_L3_IA_IVA_SS_DMA_5: + case OMAP_L3_IA_IVA_SS_DMA_6: + return "IVA_SS_DMA"; + case OMAP_L3_IA_SGX: + return "SGX"; + case OMAP_L3_IA_CAM_1: + case OMAP_L3_IA_CAM_2: + case OMAP_L3_IA_CAM_3: + return "CAM"; + case OMAP_L3_IA_DAP: + return "DAP"; + case OMAP_L3_SDMA_WR_1: + case OMAP_L3_SDMA_WR_2: + return "SDMA_WR"; + case OMAP_L3_SDMA_RD_1: + case OMAP_L3_SDMA_RD_2: + case OMAP_L3_SDMA_RD_3: + case OMAP_L3_SDMA_RD_4: + return "SDMA_RD"; + case OMAP_L3_USBOTG: + return "USB_OTG"; + case OMAP_L3_USBHOST: + return "USB_HOST"; + default: + return "UNKNOWN Initiator"; + } +} + +/** + * omap3_l3_block_irq - handles a register block's irq + * @l3: struct omap3_l3 * + * @base: register block base address + * @error: L3_ERROR_LOG register of our block + * + * Called in hard-irq context. Caller should take care of locking + * + * OMAP36xx TRM gives, on page 2001, Figure 9-10, the Typical Error + * Analysis Sequence, we are following that sequence here, please + * refer to that Figure for more information on the subject. + */ +static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3, + u64 error, int error_addr) +{ + u8 code = omap3_l3_decode_error_code(error); + u8 initid = omap3_l3_decode_initid(error); + u8 multi = error & L3_ERROR_LOG_MULTI; + u32 address = omap3_l3_decode_addr(error_addr); + + WARN(true, "%s Error seen by %s %s at address %x\n", + omap3_l3_code_string(code), + omap3_l3_initiator_string(initid), + multi ? "Multiple Errors" : "", + address); + + return IRQ_HANDLED; +} + +static irqreturn_t omap3_l3_app_irq(int irq, void *_l3) +{ + struct omap3_l3 *l3 = _l3; + + u64 status, clear; + u64 error; + u64 error_addr; + u64 err_source = 0; + void __iomem *base; + int int_type; + + irqreturn_t ret = IRQ_NONE; + + if (irq == l3->app_irq) + int_type = L3_APPLICATION_ERROR; + else + int_type = L3_DEBUG_ERROR; + + if (!int_type) { + status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0); + /* + * if we have a timeout error, there's nothing we can + * do besides rebooting the board. So let's BUG on any + * of such errors and handle the others. timeout error + * is severe and not expected to occur. + */ + BUG_ON(status & L3_STATUS_0_TIMEOUT_MASK); + } else { + status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_1); + /* No timeout error for debug sources */ + } + + base = ((l3->rt) + (*(omap3_l3_bases[int_type] + err_source))); + + /* identify the error source */ + for (err_source = 0; !(status & (1 << err_source)); err_source++) + ; + error = omap3_l3_readll(base, L3_ERROR_LOG); + + if (error) { + error_addr = omap3_l3_readll(base, L3_ERROR_LOG_ADDR); + + ret |= omap3_l3_block_irq(l3, error, error_addr); + } + + /* Clear the status register */ + clear = ((L3_AGENT_STATUS_CLEAR_IA << int_type) | + (L3_AGENT_STATUS_CLEAR_TA)); + + omap3_l3_writell(base, L3_AGENT_STATUS, clear); + + /* clear the error log register */ + omap3_l3_writell(base, L3_ERROR_LOG, error); + + return ret; +} + +static int __init omap3_l3_probe(struct platform_device *pdev) +{ + struct omap3_l3 *l3; + struct resource *res; + int ret; + int irq; + + l3 = kzalloc(sizeof(*l3), GFP_KERNEL); + if (!l3) { + ret = -ENOMEM; + goto err0; + } + + platform_set_drvdata(pdev, l3); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "couldn't find resource\n"); + ret = -ENODEV; + goto err1; + } + l3->rt = ioremap(res->start, resource_size(res)); + if (!(l3->rt)) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + irq = platform_get_irq(pdev, 0); + ret = request_irq(irq, omap3_l3_app_irq, + IRQF_DISABLED | IRQF_TRIGGER_RISING, + "l3-debug-irq", l3); + if (ret) { + dev_err(&pdev->dev, "couldn't request debug irq\n"); + goto err3; + } + l3->debug_irq = irq; + + irq = platform_get_irq(pdev, 1); + ret = request_irq(irq, omap3_l3_app_irq, + IRQF_DISABLED | IRQF_TRIGGER_RISING, + "l3-app-irq", l3); + + if (ret) { + dev_err(&pdev->dev, "couldn't request app irq\n"); + goto err4; + } + + l3->app_irq = irq; + goto err0; + +err4: +err3: + iounmap(l3->rt); +err2: +err1: + kfree(l3); +err0: + return ret; +} + +static int __exit omap3_l3_remove(struct platform_device *pdev) +{ + struct omap3_l3 *l3 = platform_get_drvdata(pdev); + + free_irq(l3->app_irq, l3); + free_irq(l3->debug_irq, l3); + iounmap(l3->rt); + kfree(l3); + + return 0; +} + +static struct platform_driver omap3_l3_driver = { + .remove = __exit_p(omap3_l3_remove), + .driver = { + .name = "omap_l3_smx", + }, +}; + +static int __init omap3_l3_init(void) +{ + return platform_driver_probe(&omap3_l3_driver, omap3_l3_probe); +} +postcore_initcall_sync(omap3_l3_init); + +static void __exit omap3_l3_exit(void) +{ + platform_driver_unregister(&omap3_l3_driver); +} +module_exit(omap3_l3_exit); diff --git a/arch/arm/mach-omap2/omap_l3_smx.h b/arch/arm/mach-omap2/omap_l3_smx.h new file mode 100644 index 000000000000..ba2ed9a850cc --- /dev/null +++ b/arch/arm/mach-omap2/omap_l3_smx.h @@ -0,0 +1,338 @@ + /* + * OMAP3XXX L3 Interconnect Driver header + * + * Copyright (C) 2011 Texas Corporation + * Felipe Balbi + * Santosh Shilimkar + * sricharan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H +#define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H + +/* Register definitions. All 64-bit wide */ +#define L3_COMPONENT 0x000 +#define L3_CORE 0x018 +#define L3_AGENT_CONTROL 0x020 +#define L3_AGENT_STATUS 0x028 +#define L3_ERROR_LOG 0x058 + +#define L3_ERROR_LOG_MULTI (1 << 31) +#define L3_ERROR_LOG_SECONDARY (1 << 30) + +#define L3_ERROR_LOG_ADDR 0x060 + +/* Register definitions for Sideband Interconnect */ +#define L3_SI_CONTROL 0x020 +#define L3_SI_FLAG_STATUS_0 0x510 + +const u64 shift = 1; + +#define L3_STATUS_0_MPUIA_BRST (shift << 0) +#define L3_STATUS_0_MPUIA_RSP (shift << 1) +#define L3_STATUS_0_MPUIA_INBAND (shift << 2) +#define L3_STATUS_0_IVAIA_BRST (shift << 6) +#define L3_STATUS_0_IVAIA_RSP (shift << 7) +#define L3_STATUS_0_IVAIA_INBAND (shift << 8) +#define L3_STATUS_0_SGXIA_BRST (shift << 9) +#define L3_STATUS_0_SGXIA_RSP (shift << 10) +#define L3_STATUS_0_SGXIA_MERROR (shift << 11) +#define L3_STATUS_0_CAMIA_BRST (shift << 12) +#define L3_STATUS_0_CAMIA_RSP (shift << 13) +#define L3_STATUS_0_CAMIA_INBAND (shift << 14) +#define L3_STATUS_0_DISPIA_BRST (shift << 15) +#define L3_STATUS_0_DISPIA_RSP (shift << 16) +#define L3_STATUS_0_DMARDIA_BRST (shift << 18) +#define L3_STATUS_0_DMARDIA_RSP (shift << 19) +#define L3_STATUS_0_DMAWRIA_BRST (shift << 21) +#define L3_STATUS_0_DMAWRIA_RSP (shift << 22) +#define L3_STATUS_0_USBOTGIA_BRST (shift << 24) +#define L3_STATUS_0_USBOTGIA_RSP (shift << 25) +#define L3_STATUS_0_USBOTGIA_INBAND (shift << 26) +#define L3_STATUS_0_USBHOSTIA_BRST (shift << 27) +#define L3_STATUS_0_USBHOSTIA_INBAND (shift << 28) +#define L3_STATUS_0_SMSTA_REQ (shift << 48) +#define L3_STATUS_0_GPMCTA_REQ (shift << 49) +#define L3_STATUS_0_OCMRAMTA_REQ (shift << 50) +#define L3_STATUS_0_OCMROMTA_REQ (shift << 51) +#define L3_STATUS_0_IVATA_REQ (shift << 54) +#define L3_STATUS_0_SGXTA_REQ (shift << 55) +#define L3_STATUS_0_SGXTA_SERROR (shift << 56) +#define L3_STATUS_0_GPMCTA_SERROR (shift << 57) +#define L3_STATUS_0_L4CORETA_REQ (shift << 58) +#define L3_STATUS_0_L4PERTA_REQ (shift << 59) +#define L3_STATUS_0_L4EMUTA_REQ (shift << 60) +#define L3_STATUS_0_MAD2DTA_REQ (shift << 61) + +#define L3_STATUS_0_TIMEOUT_MASK (L3_STATUS_0_MPUIA_BRST \ + | L3_STATUS_0_MPUIA_RSP \ + | L3_STATUS_0_IVAIA_BRST \ + | L3_STATUS_0_IVAIA_RSP \ + | L3_STATUS_0_SGXIA_BRST \ + | L3_STATUS_0_SGXIA_RSP \ + | L3_STATUS_0_CAMIA_BRST \ + | L3_STATUS_0_CAMIA_RSP \ + | L3_STATUS_0_DISPIA_BRST \ + | L3_STATUS_0_DISPIA_RSP \ + | L3_STATUS_0_DMARDIA_BRST \ + | L3_STATUS_0_DMARDIA_RSP \ + | L3_STATUS_0_DMAWRIA_BRST \ + | L3_STATUS_0_DMAWRIA_RSP \ + | L3_STATUS_0_USBOTGIA_BRST \ + | L3_STATUS_0_USBOTGIA_RSP \ + | L3_STATUS_0_USBHOSTIA_BRST \ + | L3_STATUS_0_SMSTA_REQ \ + | L3_STATUS_0_GPMCTA_REQ \ + | L3_STATUS_0_OCMRAMTA_REQ \ + | L3_STATUS_0_OCMROMTA_REQ \ + | L3_STATUS_0_IVATA_REQ \ + | L3_STATUS_0_SGXTA_REQ \ + | L3_STATUS_0_L4CORETA_REQ \ + | L3_STATUS_0_L4PERTA_REQ \ + | L3_STATUS_0_L4EMUTA_REQ \ + | L3_STATUS_0_MAD2DTA_REQ) + +#define L3_SI_FLAG_STATUS_1 0x530 + +#define L3_STATUS_1_MPU_DATAIA (1 << 0) +#define L3_STATUS_1_DAPIA0 (1 << 3) +#define L3_STATUS_1_DAPIA1 (1 << 4) +#define L3_STATUS_1_IVAIA (1 << 6) + +#define L3_PM_ERROR_LOG 0x020 +#define L3_PM_CONTROL 0x028 +#define L3_PM_ERROR_CLEAR_SINGLE 0x030 +#define L3_PM_ERROR_CLEAR_MULTI 0x038 +#define L3_PM_REQ_INFO_PERMISSION(n) (0x048 + (0x020 * n)) +#define L3_PM_READ_PERMISSION(n) (0x050 + (0x020 * n)) +#define L3_PM_WRITE_PERMISSION(n) (0x058 + (0x020 * n)) +#define L3_PM_ADDR_MATCH(n) (0x060 + (0x020 * n)) + +/* L3 error log bit fields. Common for IA and TA */ +#define L3_ERROR_LOG_CODE 24 +#define L3_ERROR_LOG_INITID 8 +#define L3_ERROR_LOG_CMD 0 + +/* L3 agent status bit fields. */ +#define L3_AGENT_STATUS_CLEAR_IA 0x10000000 +#define L3_AGENT_STATUS_CLEAR_TA 0x01000000 + +#define OMAP34xx_IRQ_L3_APP 10 +#define L3_APPLICATION_ERROR 0x0 +#define L3_DEBUG_ERROR 0x1 + +enum omap3_l3_initiator_id { + /* LCD has 1 ID */ + OMAP_L3_LCD = 29, + /* SAD2D has 1 ID */ + OMAP_L3_SAD2D = 28, + /* MPU has 5 IDs */ + OMAP_L3_IA_MPU_SS_1 = 27, + OMAP_L3_IA_MPU_SS_2 = 26, + OMAP_L3_IA_MPU_SS_3 = 25, + OMAP_L3_IA_MPU_SS_4 = 24, + OMAP_L3_IA_MPU_SS_5 = 23, + /* IVA2.2 SS has 3 IDs*/ + OMAP_L3_IA_IVA_SS_1 = 22, + OMAP_L3_IA_IVA_SS_2 = 21, + OMAP_L3_IA_IVA_SS_3 = 20, + /* IVA 2.2 SS DMA has 6 IDS */ + OMAP_L3_IA_IVA_SS_DMA_1 = 19, + OMAP_L3_IA_IVA_SS_DMA_2 = 18, + OMAP_L3_IA_IVA_SS_DMA_3 = 17, + OMAP_L3_IA_IVA_SS_DMA_4 = 16, + OMAP_L3_IA_IVA_SS_DMA_5 = 15, + OMAP_L3_IA_IVA_SS_DMA_6 = 14, + /* SGX has 1 ID */ + OMAP_L3_IA_SGX = 13, + /* CAM has 3 ID */ + OMAP_L3_IA_CAM_1 = 12, + OMAP_L3_IA_CAM_2 = 11, + OMAP_L3_IA_CAM_3 = 10, + /* DAP has 1 ID */ + OMAP_L3_IA_DAP = 9, + /* SDMA WR has 2 IDs */ + OMAP_L3_SDMA_WR_1 = 8, + OMAP_L3_SDMA_WR_2 = 7, + /* SDMA RD has 4 IDs */ + OMAP_L3_SDMA_RD_1 = 6, + OMAP_L3_SDMA_RD_2 = 5, + OMAP_L3_SDMA_RD_3 = 4, + OMAP_L3_SDMA_RD_4 = 3, + /* HSUSB OTG has 1 ID */ + OMAP_L3_USBOTG = 2, + /* HSUSB HOST has 1 ID */ + OMAP_L3_USBHOST = 1, +}; + +enum omap3_l3_code { + OMAP_L3_CODE_NOERROR = 0, + OMAP_L3_CODE_UNSUP_CMD = 1, + OMAP_L3_CODE_ADDR_HOLE = 2, + OMAP_L3_CODE_PROTECT_VIOLATION = 3, + OMAP_L3_CODE_IN_BAND_ERR = 4, + /* codes 5 and 6 are reserved */ + OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT = 7, + OMAP_L3_CODE_REQ_TOUT_NO_RESP = 8, + /* codes 9 - 15 are also reserved */ +}; + +struct omap3_l3 { + struct device *dev; + struct clk *ick; + + /* memory base*/ + void __iomem *rt; + + int debug_irq; + int app_irq; + + /* true when and inband functional error occurs */ + unsigned inband:1; +}; + +/* offsets for l3 agents in order with the Flag status register */ +unsigned int __iomem omap3_l3_app_bases[] = { + /* MPU IA */ + 0x1400, + 0x1400, + 0x1400, + /* RESERVED */ + 0, + 0, + 0, + /* IVA 2.2 IA */ + 0x1800, + 0x1800, + 0x1800, + /* SGX IA */ + 0x1c00, + 0x1c00, + /* RESERVED */ + 0, + /* CAMERA IA */ + 0x5800, + 0x5800, + 0x5800, + /* DISPLAY IA */ + 0x5400, + 0x5400, + /* RESERVED */ + 0, + /*SDMA RD IA */ + 0x4c00, + 0x4c00, + /* RESERVED */ + 0, + /* SDMA WR IA */ + 0x5000, + 0x5000, + /* RESERVED */ + 0, + /* USB OTG IA */ + 0x4400, + 0x4400, + 0x4400, + /* USB HOST IA */ + 0x4000, + 0x4000, + /* RESERVED */ + 0, + 0, + 0, + 0, + /* SAD2D IA */ + 0x3000, + 0x3000, + 0x3000, + /* RESERVED */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* SMA TA */ + 0x2000, + /* GPMC TA */ + 0x2400, + /* OCM RAM TA */ + 0x2800, + /* OCM ROM TA */ + 0x2C00, + /* L4 CORE TA */ + 0x6800, + /* L4 PER TA */ + 0x6c00, + /* IVA 2.2 TA */ + 0x6000, + /* SGX TA */ + 0x6400, + /* L4 EMU TA */ + 0x7000, + /* GPMC TA */ + 0x2400, + /* L4 CORE TA */ + 0x6800, + /* L4 PER TA */ + 0x6c00, + /* L4 EMU TA */ + 0x7000, + /* MAD2D TA */ + 0x3400, + /* RESERVED */ + 0, + 0, +}; + +unsigned int __iomem omap3_l3_debug_bases[] = { + /* MPU DATA IA */ + 0x1400, + /* RESERVED */ + 0, + 0, + /* DAP IA */ + 0x5c00, + 0x5c00, + /* RESERVED */ + 0, + /* IVA 2.2 IA */ + 0x1800, + /* REST RESERVED */ +}; + +u32 *omap3_l3_bases[] = { + omap3_l3_app_bases, + omap3_l3_debug_bases, +}; + +/* + * REVISIT define __raw_readll/__raw_writell here, but move them to + * at some point + */ +#define __raw_writell(v, a) (__chk_io_ptr(a), \ + *(volatile u64 __force *)(a) = (v)) +#define __raw_readll(a) (__chk_io_ptr(a), \ + *(volatile u64 __force *)(a)) + +#endif -- cgit v1.2.3 From 2722e56de60390969cf118933842b3f2f3c8d6b8 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 7 Mar 2011 20:53:10 +0530 Subject: OMAP4: l3: Introduce l3-interconnect error handling driver The driver provides the information regarding the ocp errors that gets logged in the interconnect. The error information gives the detail regarding the target that was attempted to be accessed and its corresponding address. Signed-off-by: sricharan Signed-off-by: Santosh Shilimkar Acked-by: Benoit Cousson --- arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/omap_l3_noc.c | 253 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/omap_l3_noc.h | 132 ++++++++++++++++++++ 3 files changed, 386 insertions(+) create mode 100644 arch/arm/mach-omap2/omap_l3_noc.c create mode 100644 arch/arm/mach-omap2/omap_l3_noc.h (limited to 'arch/arm/mach-omap2/Makefile') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index e4c9bb3ad894..8ef8711eac94 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -137,6 +137,7 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o # L3 interconnect obj-$(CONFIG_ARCH_OMAP3) += omap_l3_smx.o +obj-$(CONFIG_ARCH_OMAP4) += omap_l3_noc.o obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/arch/arm/mach-omap2/omap_l3_noc.c new file mode 100644 index 000000000000..82632c24076f --- /dev/null +++ b/arch/arm/mach-omap2/omap_l3_noc.c @@ -0,0 +1,253 @@ +/* + * OMAP4XXX L3 Interconnect error handling driver + * + * Copyright (C) 2011 Texas Corporation + * Santosh Shilimkar + * Sricharan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#include +#include +#include +#include +#include +#include + +#include "omap_l3_noc.h" + +/* + * Interrupt Handler for L3 error detection. + * 1) Identify the L3 clockdomain partition to which the error belongs to. + * 2) Identify the slave where the error information is logged + * 3) Print the logged information. + * 4) Add dump stack to provide kernel trace. + * + * Two Types of errors : + * 1) Custom errors in L3 : + * Target like DMM/FW/EMIF generates SRESP=ERR error + * 2) Standard L3 error: + * - Unsupported CMD. + * L3 tries to access target while it is idle + * - OCP disconnect. + * - Address hole error: + * If DSS/ISS/FDIF/USBHOSTFS access a target where they + * do not have connectivity, the error is logged in + * their default target which is DMM2. + * + * On High Secure devices, firewall errors are possible and those + * can be trapped as well. But the trapping is implemented as part + * secure software and hence need not be implemented here. + */ +static irqreturn_t l3_interrupt_handler(int irq, void *_l3) +{ + + struct omap4_l3 *l3 = _l3; + int inttype, i, j; + int err_src = 0; + u32 std_err_main_addr, std_err_main, err_reg; + u32 base, slave_addr, clear; + char *source_name; + + /* Get the Type of interrupt */ + if (irq == l3->app_irq) + inttype = L3_APPLICATION_ERROR; + else + inttype = L3_DEBUG_ERROR; + + for (i = 0; i < L3_MODULES; i++) { + /* + * Read the regerr register of the clock domain + * to determine the source + */ + base = (u32)l3->l3_base[i]; + err_reg = readl(base + l3_flagmux[i] + (inttype << 3)); + + /* Get the corresponding error and analyse */ + if (err_reg) { + /* Identify the source from control status register */ + for (j = 0; !(err_reg & (1 << j)); j++) + ; + + err_src = j; + /* Read the stderrlog_main_source from clk domain */ + std_err_main_addr = base + (*(l3_targ[i] + err_src)); + std_err_main = readl(std_err_main_addr); + + switch ((std_err_main & CUSTOM_ERROR)) { + case STANDARD_ERROR: + source_name = + l3_targ_stderrlog_main_name[i][err_src]; + + slave_addr = std_err_main_addr + + L3_SLAVE_ADDRESS_OFFSET; + WARN(true, "L3 standard error: SOURCE:%s at address 0x%x\n", + source_name, readl(slave_addr)); + /* clear the std error log*/ + clear = std_err_main | CLEAR_STDERR_LOG; + writel(clear, std_err_main_addr); + break; + + case CUSTOM_ERROR: + source_name = + l3_targ_stderrlog_main_name[i][err_src]; + + WARN(true, "CUSTOM SRESP error with SOURCE:%s\n", + source_name); + /* clear the std error log*/ + clear = std_err_main | CLEAR_STDERR_LOG; + writel(clear, std_err_main_addr); + break; + + default: + /* Nothing to be handled here as of now */ + break; + } + /* Error found so break the for loop */ + break; + } + } + return IRQ_HANDLED; +} + +static int __init omap4_l3_probe(struct platform_device *pdev) +{ + static struct omap4_l3 *l3; + struct resource *res; + int ret; + int irq; + + l3 = kzalloc(sizeof(*l3), GFP_KERNEL); + if (!l3) + ret = -ENOMEM; + + platform_set_drvdata(pdev, l3); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "couldn't find resource 0\n"); + ret = -ENODEV; + goto err1; + } + + l3->l3_base[0] = ioremap(res->start, resource_size(res)); + if (!(l3->l3_base[0])) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&pdev->dev, "couldn't find resource 1\n"); + ret = -ENODEV; + goto err3; + } + + l3->l3_base[1] = ioremap(res->start, resource_size(res)); + if (!(l3->l3_base[1])) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err4; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!res) { + dev_err(&pdev->dev, "couldn't find resource 2\n"); + ret = -ENODEV; + goto err5; + } + + l3->l3_base[2] = ioremap(res->start, resource_size(res)); + if (!(l3->l3_base[2])) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err6; + } + + /* + * Setup interrupt Handlers + */ + irq = platform_get_irq(pdev, 0); + ret = request_irq(irq, + l3_interrupt_handler, + IRQF_DISABLED, "l3-dbg-irq", l3); + if (ret) { + pr_crit("L3: request_irq failed to register for 0x%x\n", + OMAP44XX_IRQ_L3_DBG); + goto err7; + } + l3->debug_irq = irq; + + irq = platform_get_irq(pdev, 1); + ret = request_irq(irq, + l3_interrupt_handler, + IRQF_DISABLED, "l3-app-irq", l3); + if (ret) { + pr_crit("L3: request_irq failed to register for 0x%x\n", + OMAP44XX_IRQ_L3_APP); + goto err8; + } + l3->app_irq = irq; + + goto err0; +err8: +err7: + iounmap(l3->l3_base[2]); +err6: +err5: + iounmap(l3->l3_base[1]); +err4: +err3: + iounmap(l3->l3_base[0]); +err2: +err1: + kfree(l3); +err0: + return ret; +} + +static int __exit omap4_l3_remove(struct platform_device *pdev) +{ + struct omap4_l3 *l3 = platform_get_drvdata(pdev); + + free_irq(l3->app_irq, l3); + free_irq(l3->debug_irq, l3); + iounmap(l3->l3_base[0]); + iounmap(l3->l3_base[1]); + iounmap(l3->l3_base[2]); + kfree(l3); + + return 0; +} + +static struct platform_driver omap4_l3_driver = { + .remove = __exit_p(omap4_l3_remove), + .driver = { + .name = "omap_l3_noc", + }, +}; + +static int __init omap4_l3_init(void) +{ + return platform_driver_probe(&omap4_l3_driver, omap4_l3_probe); +} +postcore_initcall_sync(omap4_l3_init); + +static void __exit omap4_l3_exit(void) +{ + platform_driver_unregister(&omap4_l3_driver); +} +module_exit(omap4_l3_exit); diff --git a/arch/arm/mach-omap2/omap_l3_noc.h b/arch/arm/mach-omap2/omap_l3_noc.h new file mode 100644 index 000000000000..359b83348aed --- /dev/null +++ b/arch/arm/mach-omap2/omap_l3_noc.h @@ -0,0 +1,132 @@ + /* + * OMAP4XXX L3 Interconnect error handling driver header + * + * Copyright (C) 2011 Texas Corporation + * Santosh Shilimkar + * sricharan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H +#define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H + +/* + * L3 register offsets + */ +#define L3_MODULES 3 +#define CLEAR_STDERR_LOG (1 << 31) +#define CUSTOM_ERROR 0x2 +#define STANDARD_ERROR 0x0 +#define INBAND_ERROR 0x0 +#define EMIF_KERRLOG_OFFSET 0x10 +#define L3_SLAVE_ADDRESS_OFFSET 0x14 +#define LOGICAL_ADDR_ERRORLOG 0x4 +#define L3_APPLICATION_ERROR 0x0 +#define L3_DEBUG_ERROR 0x1 + +u32 l3_flagmux[L3_MODULES] = { + 0x50C, + 0x100C, + 0X020C +}; + +/* + * L3 Target standard Error register offsets + */ +u32 l3_targ_stderrlog_main_clk1[] = { + 0x148, /* DMM1 */ + 0x248, /* DMM2 */ + 0x348, /* ABE */ + 0x448, /* L4CFG */ + 0x648 /* CLK2 PWR DISC */ +}; + +u32 l3_targ_stderrlog_main_clk2[] = { + 0x548, /* CORTEX M3 */ + 0x348, /* DSS */ + 0x148, /* GPMC */ + 0x448, /* ISS */ + 0x748, /* IVAHD */ + 0xD48, /* missing in TRM corresponds to AES1*/ + 0x948, /* L4 PER0*/ + 0x248, /* OCMRAM */ + 0x148, /* missing in TRM corresponds to GPMC sERROR*/ + 0x648, /* SGX */ + 0x848, /* SL2 */ + 0x1648, /* C2C */ + 0x1148, /* missing in TRM corresponds PWR DISC CLK1*/ + 0xF48, /* missing in TRM corrsponds to SHA1*/ + 0xE48, /* missing in TRM corresponds to AES2*/ + 0xC48, /* L4 PER3 */ + 0xA48, /* L4 PER1*/ + 0xB48 /* L4 PER2*/ +}; + +u32 l3_targ_stderrlog_main_clk3[] = { + 0x0148 /* EMUSS */ +}; + +char *l3_targ_stderrlog_main_name[L3_MODULES][18] = { + { + "DMM1", + "DMM2", + "ABE", + "L4CFG", + "CLK2 PWR DISC", + }, + { + "CORTEX M3" , + "DSS ", + "GPMC ", + "ISS ", + "IVAHD ", + "AES1", + "L4 PER0", + "OCMRAM ", + "GPMC sERROR", + "SGX ", + "SL2 ", + "C2C ", + "PWR DISC CLK1", + "SHA1", + "AES2", + "L4 PER3", + "L4 PER1", + "L4 PER2", + }, + { + "EMUSS", + }, +}; + +u32 *l3_targ[L3_MODULES] = { + l3_targ_stderrlog_main_clk1, + l3_targ_stderrlog_main_clk2, + l3_targ_stderrlog_main_clk3, +}; + +struct omap4_l3 { + struct device *dev; + struct clk *ick; + + /* memory base */ + void __iomem *l3_base[4]; + + int debug_irq; + int app_irq; +}; + +#endif -- cgit v1.2.3