diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2009-08-10 14:24:18 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-08-10 14:24:18 +0100 |
commit | f40aac940aa83645ec2218ccce90cc1c6881b74c (patch) | |
tree | 6d775da1489722a684f85249fa57528851e11957 /arch/arm/mach-omap2 | |
parent | 7063c88c726a704e648ba36ca78baa630f8b7b0a (diff) | |
parent | 3c82e229f09a6acc8d24dc27c5e0e60b1d7161c2 (diff) | |
download | blackbird-op-linux-f40aac940aa83645ec2218ccce90cc1c6881b74c.tar.gz blackbird-op-linux-f40aac940aa83645ec2218ccce90cc1c6881b74c.zip |
Merge branch 'omap_fixes_31' of git://git.pwsan.com/linux-2.6
Diffstat (limited to 'arch/arm/mach-omap2')
24 files changed, 575 insertions, 180 deletions
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index 9c3fdcdf76c3..8ec2a132904d 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -141,7 +141,7 @@ static inline void board_smc91x_init(void) static void __init omap_2430sdp_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); } diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 496a90e4ea7a..ac262cd74503 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -169,7 +169,7 @@ static struct platform_device *sdp3430_devices[] __initdata = { static void __init omap_3430sdp_init_irq(void) { - omap2_init_common_hw(hyb18m512160af6_sdrc_params); + omap2_init_common_hw(hyb18m512160af6_sdrc_params, NULL); omap_init_irq(); omap_gpio_init(); } diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 57e477bd89c6..b0c7402248f7 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -59,7 +59,7 @@ static void __init gic_init_irq(void) static void __init omap_4430sdp_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); #ifdef CONFIG_OMAP_32K_TIMER omap2_gp_clockevent_set_gptimer(1); #endif diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index 06dfba888b0c..dcfc20d03894 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -250,7 +250,7 @@ out: static void __init omap_apollon_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); apollon_init_smc91x(); diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 3492162a65c3..fd00aa03690c 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -33,7 +33,7 @@ static void __init omap_generic_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); } diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index e7d017cdc438..7b1d61d5bb2c 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -270,7 +270,7 @@ static void __init h4_init_flash(void) static void __init omap_h4_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); h4_init_flash(); diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index d8bc0a7dcb8d..ea383f88cb1b 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -270,7 +270,7 @@ static inline void __init ldp_init_smsc911x(void) static void __init omap_ldp_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); ldp_init_smsc911x(); diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 991ac9c38032..e00ba128cece 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -282,7 +282,8 @@ static int __init omap3_beagle_i2c_init(void) static void __init omap3_beagle_init_irq(void) { - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); omap_init_irq(); #ifdef CONFIG_OMAP_32K_TIMER omap2_gp_clockevent_set_gptimer(12); @@ -408,6 +409,10 @@ static void __init omap3_beagle_init(void) usb_musb_init(); omap3beagle_flash_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); } static void __init omap3_beagle_map_io(void) diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index cf3dd771a678..c4b144647dc5 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -280,7 +280,7 @@ struct spi_board_info omap3evm_spi_board_info[] = { static void __init omap3_evm_init_irq(void) { - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, NULL); omap_init_irq(); omap_gpio_init(); omap3evm_init_smc911x(); diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index e32aa23ce962..864ee3d021f7 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -40,6 +40,7 @@ #include <mach/mcspi.h> #include <mach/usb.h> #include <mach/keypad.h> +#include <mach/mux.h> #include "sdram-micron-mt46h32m32lf-6.h" #include "mmc-twl4030.h" @@ -310,7 +311,8 @@ static int __init omap3pandora_i2c_init(void) static void __init omap3pandora_init_irq(void) { - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); omap_init_irq(); omap_gpio_init(); } @@ -397,6 +399,10 @@ static void __init omap3pandora_init(void) omap3pandora_ads7846_init(); pandora_keys_gpio_init(); usb_musb_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); } static void __init omap3pandora_map_io(void) diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index fec1bb19b9ff..a76e6b7afe6b 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -44,6 +44,7 @@ #include <mach/gpmc.h> #include <mach/hardware.h> #include <mach/nand.h> +#include <mach/mux.h> #include <mach/usb.h> #include "sdram-micron-mt46h32m32lf-6.h" @@ -360,7 +361,8 @@ static int __init overo_i2c_init(void) static void __init overo_init_irq(void) { - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); omap_init_irq(); omap_gpio_init(); } @@ -395,6 +397,10 @@ static void __init overo_init(void) overo_ads7846_init(); overo_init_smsc911x(); + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); + if ((gpio_request(OVERO_GPIO_W2W_NRESET, "OVERO_GPIO_W2W_NRESET") == 0) && (gpio_direction_output(OVERO_GPIO_W2W_NRESET, 1) == 0)) { diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index 374ff63c3eb2..1c9e07fe8266 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -61,7 +61,7 @@ static struct omap_board_config_kernel rx51_config[] = { static void __init rx51_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); } @@ -75,6 +75,10 @@ static void __init rx51_init(void) omap_serial_init(); usb_musb_init(); rx51_peripherals_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); } static void __init rx51_map_io(void) diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c index bcc0f7632dea..427b7b8b1237 100644 --- a/arch/arm/mach-omap2/board-zoom2.c +++ b/arch/arm/mach-omap2/board-zoom2.c @@ -25,7 +25,7 @@ static void __init omap_zoom2_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); } diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index b0665f161c03..456e2ad5f621 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -27,6 +27,7 @@ #include <mach/clock.h> #include <mach/clockdomain.h> #include <mach/cpu.h> +#include <mach/prcm.h> #include <asm/div64.h> #include <mach/sdrc.h> @@ -38,8 +39,6 @@ #include "cm-regbits-24xx.h" #include "cm-regbits-34xx.h" -#define MAX_CLOCK_ENABLE_WAIT 100000 - /* DPLL rate rounding: minimum DPLL multiplier, divider values */ #define DPLL_MIN_MULTIPLIER 1 #define DPLL_MIN_DIVIDER 1 @@ -274,83 +273,97 @@ unsigned long omap2_fixed_divisor_recalc(struct clk *clk) } /** - * omap2_wait_clock_ready - wait for clock to enable - * @reg: physical address of clock IDLEST register - * @mask: value to mask against to determine if the clock is active - * @name: name of the clock (for printk) + * omap2_clk_dflt_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Note: We don't need special code here for INVERT_ENABLE for the + * time being since INVERT_ENABLE only applies to clocks enabled by + * CM_CLKEN_PLL * - * Returns 1 if the clock enabled in time, or 0 if it failed to enable - * in roughly MAX_CLOCK_ENABLE_WAIT microseconds. + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's + * just a matter of XORing the bits. + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as MAILBOXES) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. */ -int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name) +void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, + u8 *other_bit) { - int i = 0; - int ena = 0; + u32 r; /* - * 24xx uses 0 to indicate not ready, and 1 to indicate ready. - * 34xx reverses this, just to keep us on our toes + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes + * it's just a matter of XORing the bits. */ - if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) - ena = mask; - else if (cpu_mask & RATE_IN_343X) - ena = 0; - - /* Wait for lock */ - while (((__raw_readl(reg) & mask) != ena) && - (i++ < MAX_CLOCK_ENABLE_WAIT)) { - udelay(1); - } - - if (i <= MAX_CLOCK_ENABLE_WAIT) - pr_debug("Clock %s stable after %d loops\n", name, i); - else - printk(KERN_ERR "Clock %s didn't enable in %d tries\n", - name, MAX_CLOCK_ENABLE_WAIT); - - - return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0; -}; + r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); + *other_reg = (__force void __iomem *)r; + *other_bit = clk->enable_bit; +} -/* - * Note: We don't need special code here for INVERT_ENABLE - * for the time being since INVERT_ENABLE only applies to clocks enabled by - * CM_CLKEN_PLL +/** + * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk + * @clk: struct clk * to find IDLEST info for + * @idlest_reg: void __iomem ** to return the CM_IDLEST va in + * @idlest_bit: u8 ** to return the CM_IDLEST bit shift in + * + * Return the CM_IDLEST register address and bit shift corresponding + * to the module that "owns" this clock. This default code assumes + * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that + * the IDLEST register address ID corresponds to the CM_*CLKEN + * register address ID (e.g., that CM_FCLKEN2 corresponds to + * CM_IDLEST2). This is not true for all modules. No return value. */ -static void omap2_clk_wait_ready(struct clk *clk) +void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, + u8 *idlest_bit) { - void __iomem *reg, *other_reg, *st_reg; - u32 bit; + u32 r; - /* - * REVISIT: This code is pretty ugly. It would be nice to generalize - * it and pull it into struct clk itself somehow. - */ - reg = clk->enable_reg; + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; +} - /* - * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes - * it's just a matter of XORing the bits. - */ - other_reg = (void __iomem *)((u32)reg ^ (CM_FCLKEN ^ CM_ICLKEN)); +/** + * omap2_module_wait_ready - wait for an OMAP module to leave IDLE + * @clk: struct clk * belonging to the module + * + * If the necessary clocks for the OMAP hardware IP block that + * corresponds to clock @clk are enabled, then wait for the module to + * indicate readiness (i.e., to leave IDLE). This code does not + * belong in the clock code and will be moved in the medium term to + * module-dependent code. No return value. + */ +static void omap2_module_wait_ready(struct clk *clk) +{ + void __iomem *companion_reg, *idlest_reg; + u8 other_bit, idlest_bit; + + /* Not all modules have multiple clocks that their IDLEST depends on */ + if (clk->ops->find_companion) { + clk->ops->find_companion(clk, &companion_reg, &other_bit); + if (!(__raw_readl(companion_reg) & (1 << other_bit))) + return; + } - /* Check if both functional and interface clocks - * are running. */ - bit = 1 << clk->enable_bit; - if (!(__raw_readl(other_reg) & bit)) - return; - st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */ + clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit); - omap2_wait_clock_ready(st_reg, bit, clk->name); + omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name); } -static int omap2_dflt_clk_enable(struct clk *clk) +int omap2_dflt_clk_enable(struct clk *clk) { u32 v; if (unlikely(clk->enable_reg == NULL)) { - printk(KERN_ERR "clock.c: Enable for %s without enable code\n", + pr_err("clock.c: Enable for %s without enable code\n", clk->name); return 0; /* REVISIT: -EINVAL */ } @@ -363,26 +376,13 @@ static int omap2_dflt_clk_enable(struct clk *clk) __raw_writel(v, clk->enable_reg); v = __raw_readl(clk->enable_reg); /* OCP barrier */ - return 0; -} + if (clk->ops->find_idlest) + omap2_module_wait_ready(clk); -static int omap2_dflt_clk_enable_wait(struct clk *clk) -{ - int ret; - - if (!clk->enable_reg) { - printk(KERN_ERR "clock.c: Enable for %s without enable code\n", - clk->name); - return 0; /* REVISIT: -EINVAL */ - } - - ret = omap2_dflt_clk_enable(clk); - if (ret == 0) - omap2_clk_wait_ready(clk); - return ret; + return 0; } -static void omap2_dflt_clk_disable(struct clk *clk) +void omap2_dflt_clk_disable(struct clk *clk) { u32 v; @@ -406,8 +406,10 @@ static void omap2_dflt_clk_disable(struct clk *clk) } const struct clkops clkops_omap2_dflt_wait = { - .enable = omap2_dflt_clk_enable_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, }; const struct clkops clkops_omap2_dflt = { diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 2679ddfa6424..9ae7540f8af2 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -65,6 +65,12 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); u32 omap2_get_dpll_rate(struct clk *clk); int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); void omap2_clk_prepare_for_reboot(void); +int omap2_dflt_clk_enable(struct clk *clk); +void omap2_dflt_clk_disable(struct clk *clk); +void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, + u8 *idlest_bit); extern const struct clkops clkops_omap2_dflt_wait; extern const struct clkops clkops_omap2_dflt; diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c index 44de0271fc2f..bc5d3ac66611 100644 --- a/arch/arm/mach-omap2/clock24xx.c +++ b/arch/arm/mach-omap2/clock24xx.c @@ -30,6 +30,7 @@ #include <mach/clock.h> #include <mach/sram.h> +#include <mach/prcm.h> #include <asm/div64.h> #include <asm/clkdev.h> @@ -43,6 +44,18 @@ static const struct clkops clkops_oscck; static const struct clkops clkops_fixed; +static void omap2430_clk_i2chs_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); + +/* 2430 I2CHS has non-standard IDLEST register */ +static const struct clkops clkops_omap2430_i2chs_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap2430_clk_i2chs_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + #include "clock24xx.h" struct omap_clk { @@ -240,6 +253,26 @@ static void __iomem *prcm_clksrc_ctrl; *-------------------------------------------------------------------------*/ /** + * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the + * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function + * passes back the correct CM_IDLEST register address for I2CHS + * modules. No return value. + */ +static void omap2430_clk_i2chs_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + *idlest_reg = OMAP_CM_REGADDR(CORE_MOD, CM_IDLEST); + *idlest_bit = clk->enable_bit; +} + + +/** * omap2xxx_clk_get_core_rate - return the CORE_CLK rate * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") * @@ -325,8 +358,8 @@ static int omap2_clk_fixed_enable(struct clk *clk) else if (clk == &apll54_ck) cval = OMAP24XX_ST_54M_APLL; - omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval, - clk->name); + omap2_cm_wait_idlest(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval, + clk->name); /* * REVISIT: Should we return an error code if omap2_wait_clock_ready() diff --git a/arch/arm/mach-omap2/clock24xx.h b/arch/arm/mach-omap2/clock24xx.h index 458f00cdcbea..d19cf7a7d8db 100644 --- a/arch/arm/mach-omap2/clock24xx.h +++ b/arch/arm/mach-omap2/clock24xx.h @@ -2337,7 +2337,7 @@ static struct clk i2c2_fck = { static struct clk i2chs2_fck = { .name = "i2c_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2430_i2chs_wait, .id = 2, .parent = &func_96m_ck, .clkdm_name = "core_l4_clkdm", @@ -2370,7 +2370,7 @@ static struct clk i2c1_fck = { static struct clk i2chs1_fck = { .name = "i2c_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2430_i2chs_wait, .id = 1, .parent = &func_96m_ck, .clkdm_name = "core_l4_clkdm", diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 045da923e75b..cd7819cc0c9e 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -2,7 +2,7 @@ * OMAP3-specific clock framework functions * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2008 Nokia Corporation + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * Testing and integration fixes by Jouni Högander @@ -41,6 +41,37 @@ static const struct clkops clkops_noncore_dpll_ops; +static void omap3430es2_clk_ssi_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); +static void omap3430es2_clk_hsotgusb_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); +static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); + +static const struct clkops clkops_omap3430es2_ssi_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap3430es2_clk_ssi_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +static const struct clkops clkops_omap3430es2_hsotgusb_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +static const struct clkops clkops_omap3430es2_dss_usbhost_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + #include "clock34xx.h" struct omap_clk { @@ -157,10 +188,13 @@ static struct omap_clk omap34xx_clks[] = { CLK(NULL, "fshostusb_fck", &fshostusb_fck, CK_3430ES1), CLK(NULL, "core_12m_fck", &core_12m_fck, CK_343X), CLK("omap_hdq.0", "fck", &hdq_fck, CK_343X), - CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck, CK_343X), - CLK(NULL, "ssi_sst_fck", &ssi_sst_fck, CK_343X), + CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1, CK_3430ES1), + CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2, CK_3430ES2), + CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1, CK_3430ES1), + CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2, CK_3430ES2), CLK(NULL, "core_l3_ick", &core_l3_ick, CK_343X), - CLK("musb_hdrc", "ick", &hsotgusb_ick, CK_343X), + CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es1, CK_3430ES1), + CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es2, CK_3430ES2), CLK(NULL, "sdrc_ick", &sdrc_ick, CK_343X), CLK(NULL, "gpmc_fck", &gpmc_fck, CK_343X), CLK(NULL, "security_l3_ick", &security_l3_ick, CK_343X), @@ -193,18 +227,21 @@ static struct omap_clk omap34xx_clks[] = { CLK(NULL, "mailboxes_ick", &mailboxes_ick, CK_343X), CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_343X), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_343X), - CLK(NULL, "ssi_ick", &ssi_ick, CK_343X), + CLK(NULL, "ssi_ick", &ssi_ick_3430es1, CK_3430ES1), + CLK(NULL, "ssi_ick", &ssi_ick_3430es2, CK_3430ES2), CLK(NULL, "usb_l4_ick", &usb_l4_ick, CK_3430ES1), CLK(NULL, "security_l4_ick2", &security_l4_ick2, CK_343X), CLK(NULL, "aes1_ick", &aes1_ick, CK_343X), CLK("omap_rng", "ick", &rng_ick, CK_343X), CLK(NULL, "sha11_ick", &sha11_ick, CK_343X), CLK(NULL, "des1_ick", &des1_ick, CK_343X), - CLK("omapfb", "dss1_fck", &dss1_alwon_fck, CK_343X), + CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1), + CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2), CLK("omapfb", "tv_fck", &dss_tv_fck, CK_343X), CLK("omapfb", "video_fck", &dss_96m_fck, CK_343X), CLK("omapfb", "dss2_fck", &dss2_alwon_fck, CK_343X), - CLK("omapfb", "ick", &dss_ick, CK_343X), + CLK("omapfb", "ick", &dss_ick_3430es1, CK_3430ES1), + CLK("omapfb", "ick", &dss_ick_3430es2, CK_3430ES2), CLK(NULL, "cam_mclk", &cam_mclk, CK_343X), CLK(NULL, "cam_ick", &cam_ick, CK_343X), CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X), @@ -301,6 +338,73 @@ static struct omap_clk omap34xx_clks[] = { #define SDRC_MPURATE_LOOPS 96 /** + * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift + * from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_ssi_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; +} + +/** + * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * Some OMAP modules on OMAP3 ES2+ chips have both initiator and + * target IDLEST bits. For our purposes, we are concerned with the + * target IDLEST bits, which exist at a different bit position than + * the *CLKEN bit position for these modules (DSS and USBHOST) (The + * default find_idlest code assumes that they are at the same + * position.) No return value. + */ +static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + /* USBHOST_IDLE has same shift */ + *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; +} + +/** + * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different + * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_hsotgusb_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; +} + +/** * omap3_dpll_recalc - recalculate DPLL rate * @clk: DPLL struct clk * @@ -725,7 +829,9 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) u32 unlock_dll = 0; u32 c; unsigned long validrate, sdrcrate, mpurate; - struct omap_sdrc_params *sp; + struct omap_sdrc_params *sdrc_cs0; + struct omap_sdrc_params *sdrc_cs1; + int ret; if (!clk || !rate) return -EINVAL; @@ -743,8 +849,8 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) else sdrcrate >>= ((clk->rate / rate) >> 1); - sp = omap2_sdrc_get_params(sdrcrate); - if (!sp) + ret = omap2_sdrc_get_params(sdrcrate, &sdrc_cs0, &sdrc_cs1); + if (ret) return -EINVAL; if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) { @@ -765,12 +871,29 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, validrate); - pr_debug("clock: SDRC timing params used: %08x %08x %08x\n", - sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb); - - omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla, - sp->actim_ctrlb, new_div, unlock_dll, c, - sp->mr, rate > clk->rate); + pr_debug("clock: SDRC CS0 timing params used:" + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr); + if (sdrc_cs1) + pr_debug("clock: SDRC CS1 timing params used: " + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + + if (sdrc_cs1) + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + else + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + 0, 0, 0, 0); return 0; } diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index e433aec4efdd..57cc2725b923 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -1568,7 +1568,7 @@ static const struct clksel ssi_ssr_clksel[] = { { .parent = NULL } }; -static struct clk ssi_ssr_fck = { +static struct clk ssi_ssr_fck_3430es1 = { .name = "ssi_ssr_fck", .ops = &clkops_omap2_dflt, .init = &omap2_init_clksel_parent, @@ -1581,10 +1581,31 @@ static struct clk ssi_ssr_fck = { .recalc = &omap2_clksel_recalc, }; -static struct clk ssi_sst_fck = { +static struct clk ssi_ssr_fck_3430es2 = { + .name = "ssi_ssr_fck", + .ops = &clkops_omap3430es2_ssi_wait, + .init = &omap2_init_clksel_parent, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), + .enable_bit = OMAP3430_EN_SSI_SHIFT, + .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL), + .clksel_mask = OMAP3430_CLKSEL_SSI_MASK, + .clksel = ssi_ssr_clksel, + .clkdm_name = "core_l4_clkdm", + .recalc = &omap2_clksel_recalc, +}; + +static struct clk ssi_sst_fck_3430es1 = { .name = "ssi_sst_fck", .ops = &clkops_null, - .parent = &ssi_ssr_fck, + .parent = &ssi_ssr_fck_3430es1, + .fixed_div = 2, + .recalc = &omap2_fixed_divisor_recalc, +}; + +static struct clk ssi_sst_fck_3430es2 = { + .name = "ssi_sst_fck", + .ops = &clkops_null, + .parent = &ssi_ssr_fck_3430es2, .fixed_div = 2, .recalc = &omap2_fixed_divisor_recalc, }; @@ -1606,9 +1627,19 @@ static struct clk core_l3_ick = { .recalc = &followparent_recalc, }; -static struct clk hsotgusb_ick = { +static struct clk hsotgusb_ick_3430es1 = { .name = "hsotgusb_ick", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2_dflt, + .parent = &core_l3_ick, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), + .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT, + .clkdm_name = "core_l3_clkdm", + .recalc = &followparent_recalc, +}; + +static struct clk hsotgusb_ick_3430es2 = { + .name = "hsotgusb_ick", + .ops = &clkops_omap3430es2_hsotgusb_wait, .parent = &core_l3_ick, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT, @@ -1947,7 +1978,7 @@ static struct clk ssi_l4_ick = { .recalc = &followparent_recalc, }; -static struct clk ssi_ick = { +static struct clk ssi_ick_3430es1 = { .name = "ssi_ick", .ops = &clkops_omap2_dflt, .parent = &ssi_l4_ick, @@ -1957,6 +1988,16 @@ static struct clk ssi_ick = { .recalc = &followparent_recalc, }; +static struct clk ssi_ick_3430es2 = { + .name = "ssi_ick", + .ops = &clkops_omap3430es2_ssi_wait, + .parent = &ssi_l4_ick, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), + .enable_bit = OMAP3430_EN_SSI_SHIFT, + .clkdm_name = "core_l4_clkdm", + .recalc = &followparent_recalc, +}; + /* REVISIT: Technically the TRM claims that this is CORE_CLK based, * but l4_ick makes more sense to me */ @@ -2024,7 +2065,7 @@ static struct clk des1_ick = { }; /* DSS */ -static struct clk dss1_alwon_fck = { +static struct clk dss1_alwon_fck_3430es1 = { .name = "dss1_alwon_fck", .ops = &clkops_omap2_dflt, .parent = &dpll4_m4x2_ck, @@ -2034,6 +2075,16 @@ static struct clk dss1_alwon_fck = { .recalc = &followparent_recalc, }; +static struct clk dss1_alwon_fck_3430es2 = { + .name = "dss1_alwon_fck", + .ops = &clkops_omap3430es2_dss_usbhost_wait, + .parent = &dpll4_m4x2_ck, + .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN), + .enable_bit = OMAP3430_EN_DSS1_SHIFT, + .clkdm_name = "dss_clkdm", + .recalc = &followparent_recalc, +}; + static struct clk dss_tv_fck = { .name = "dss_tv_fck", .ops = &clkops_omap2_dflt, @@ -2067,7 +2118,7 @@ static struct clk dss2_alwon_fck = { .recalc = &followparent_recalc, }; -static struct clk dss_ick = { +static struct clk dss_ick_3430es1 = { /* Handles both L3 and L4 clocks */ .name = "dss_ick", .ops = &clkops_omap2_dflt, @@ -2079,6 +2130,18 @@ static struct clk dss_ick = { .recalc = &followparent_recalc, }; +static struct clk dss_ick_3430es2 = { + /* Handles both L3 and L4 clocks */ + .name = "dss_ick", + .ops = &clkops_omap3430es2_dss_usbhost_wait, + .parent = &l4_ick, + .init = &omap2_init_clk_clkdm, + .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN), + .enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT, + .clkdm_name = "dss_clkdm", + .recalc = &followparent_recalc, +}; + /* CAM */ static struct clk cam_mclk = { @@ -2118,7 +2181,7 @@ static struct clk csi2_96m_fck = { static struct clk usbhost_120m_fck = { .name = "usbhost_120m_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2_dflt, .parent = &dpll5_m2_ck, .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN), @@ -2129,7 +2192,7 @@ static struct clk usbhost_120m_fck = { static struct clk usbhost_48m_fck = { .name = "usbhost_48m_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap3430es2_dss_usbhost_wait, .parent = &omap_48m_fck, .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN), @@ -2141,7 +2204,7 @@ static struct clk usbhost_48m_fck = { static struct clk usbhost_ick = { /* Handles both L3 and L4 clocks */ .name = "usbhost_ick", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap3430es2_dss_usbhost_wait, .parent = &l4_ick, .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN), diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 3a86b0f66031..e9b9bcb19b4e 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -276,14 +276,15 @@ static int __init _omap2_init_reprogram_sdrc(void) return v; } -void __init omap2_init_common_hw(struct omap_sdrc_params *sp) +void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, + struct omap_sdrc_params *sdrc_cs1) { omap2_mux_init(); #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ pwrdm_init(powerdomains_omap); clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); omap2_clk_init(); - omap2_sdrc_init(sp); + omap2_sdrc_init(sdrc_cs0, sdrc_cs1); _omap2_init_reprogram_sdrc(); #endif gpmc_init(); diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 026c4fc883a7..43d6b92b65f2 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -486,6 +486,12 @@ MUX_CFG_34XX("H19_34XX_GPIO164_OUT", 0x19c, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT) MUX_CFG_34XX("J25_34XX_GPIO170", 0x1c6, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) + +/* OMAP3 SDRC CKE signals to SDR/DDR ram chips */ +MUX_CFG_34XX("H16_34XX_SDRC_CKE0", 0x262, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT) +MUX_CFG_34XX("H17_34XX_SDRC_CKE1", 0x264, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT) }; #define OMAP34XX_PINS_SZ ARRAY_SIZE(omap34xx_pins) diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index f945156d5585..ced555a4cd1a 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/delay.h> #include <mach/common.h> #include <mach/prcm.h> @@ -28,6 +29,8 @@ static void __iomem *prm_base; static void __iomem *cm_base; +#define MAX_MODULE_ENABLE_WAIT 100000 + u32 omap_prcm_get_reset_sources(void) { /* XXX This presumably needs modification for 34XX */ @@ -120,6 +123,46 @@ u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) } EXPORT_SYMBOL(cm_rmw_mod_reg_bits); +/** + * omap2_cm_wait_idlest - wait for IDLEST bit to indicate module readiness + * @reg: physical address of module IDLEST register + * @mask: value to mask against to determine if the module is active + * @name: name of the clock (for printk) + * + * Returns 1 if the module indicated readiness in time, or 0 if it + * failed to enable in roughly MAX_MODULE_ENABLE_WAIT microseconds. + */ +int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name) +{ + int i = 0; + int ena = 0; + + /* + * 24xx uses 0 to indicate not ready, and 1 to indicate ready. + * 34xx reverses this, just to keep us on our toes + */ + if (cpu_is_omap24xx()) + ena = mask; + else if (cpu_is_omap34xx()) + ena = 0; + else + BUG(); + + /* Wait for lock */ + while (((__raw_readl(reg) & mask) != ena) && + (i++ < MAX_MODULE_ENABLE_WAIT)) + udelay(1); + + if (i < MAX_MODULE_ENABLE_WAIT) + pr_debug("cm: Module associated with clock %s ready after %d " + "loops\n", name, i); + else + pr_err("cm: Module associated with clock %s didn't enable in " + "%d tries\n", name, MAX_MODULE_ENABLE_WAIT); + + return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; +}; + void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals) { prm_base = omap2_globals->prm; diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c index 2045441e8385..9e3bd4fa7810 100644 --- a/arch/arm/mach-omap2/sdrc.c +++ b/arch/arm/mach-omap2/sdrc.c @@ -32,7 +32,7 @@ #include <mach/sdrc.h> #include "sdrc.h" -static struct omap_sdrc_params *sdrc_init_params; +static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1; void __iomem *omap2_sdrc_base; void __iomem *omap2_sms_base; @@ -45,33 +45,49 @@ void __iomem *omap2_sms_base; /** * omap2_sdrc_get_params - return SDRC register values for a given clock rate * @r: SDRC clock rate (in Hz) + * @sdrc_cs0: chip select 0 ram timings ** + * @sdrc_cs1: chip select 1 ram timings ** * * Return pre-calculated values for the SDRC_ACTIM_CTRLA, - * SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL, and SDRC_MR registers, for a given - * SDRC clock rate 'r'. These parameters control various timing - * delays in the SDRAM controller that are expressed in terms of the - * number of SDRC clock cycles to wait; hence the clock rate - * dependency. Note that sdrc_init_params must be sorted rate - * descending. Also assumes that both chip-selects use the same - * timing parameters. Returns a struct omap_sdrc_params * upon - * success, or NULL upon failure. + * SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL and SDRC_MR registers in sdrc_cs[01] + * structs,for a given SDRC clock rate 'r'. + * These parameters control various timing delays in the SDRAM controller + * that are expressed in terms of the number of SDRC clock cycles to + * wait; hence the clock rate dependency. + * + * Supports 2 different timing parameters for both chip selects. + * + * Note 1: the sdrc_init_params_cs[01] must be sorted rate descending. + * Note 2: If sdrc_init_params_cs_1 is not NULL it must be of same size + * as sdrc_init_params_cs_0. + * + * Fills in the struct omap_sdrc_params * for each chip select. + * Returns 0 upon success or -1 upon failure. */ -struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r) +int omap2_sdrc_get_params(unsigned long r, + struct omap_sdrc_params **sdrc_cs0, + struct omap_sdrc_params **sdrc_cs1) { - struct omap_sdrc_params *sp; + struct omap_sdrc_params *sp0, *sp1; - if (!sdrc_init_params) - return NULL; + if (!sdrc_init_params_cs0) + return -1; - sp = sdrc_init_params; + sp0 = sdrc_init_params_cs0; + sp1 = sdrc_init_params_cs1; - while (sp->rate && sp->rate != r) - sp++; + while (sp0->rate && sp0->rate != r) { + sp0++; + if (sdrc_init_params_cs1) + sp1++; + } - if (!sp->rate) - return NULL; + if (!sp0->rate) + return -1; - return sp; + *sdrc_cs0 = sp0; + *sdrc_cs1 = sp1; + return 0; } @@ -83,13 +99,15 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals) /** * omap2_sdrc_init - initialize SMS, SDRC devices on boot - * @sp: pointer to a null-terminated list of struct omap_sdrc_params + * @sdrc_cs[01]: pointers to a null-terminated list of struct omap_sdrc_params + * Support for 2 chip selects timings * * Turn on smart idle modes for SDRAM scheduler and controller. * Program a known-good configuration for the SDRC to deal with buggy * bootloaders. */ -void __init omap2_sdrc_init(struct omap_sdrc_params *sp) +void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0, + struct omap_sdrc_params *sdrc_cs1) { u32 l; @@ -103,11 +121,15 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp) l |= (0x2 << 3); sdrc_write_reg(l, SDRC_SYSCONFIG); - sdrc_init_params = sp; + sdrc_init_params_cs0 = sdrc_cs0; + sdrc_init_params_cs1 = sdrc_cs1; /* XXX Enable SRFRONIDLEREQ here also? */ + /* + * PWDENA should not be set due to 34xx erratum 1.150 - PWDENA + * can cause random memory corruption + */ l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) | - (1 << SDRC_POWER_PWDENA_SHIFT) | (1 << SDRC_POWER_PAGEPOLICY_SHIFT); sdrc_write_reg(l, SDRC_POWER); } diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S index f41f8d96ddba..82aa4a3d160c 100644 --- a/arch/arm/mach-omap2/sram34xx.S +++ b/arch/arm/mach-omap2/sram34xx.S @@ -36,7 +36,7 @@ .text -/* r4 parameters */ +/* r1 parameters */ #define SDRC_NO_UNLOCK_DLL 0x0 #define SDRC_UNLOCK_DLL 0x1 @@ -58,7 +58,6 @@ /* SDRC_POWER bit settings */ #define SRFRONIDLEREQ_MASK 0x40 -#define PWDENA_MASK 0x4 /* CM_IDLEST1_CORE bit settings */ #define ST_SDRC_MASK 0x2 @@ -71,41 +70,72 @@ /* * omap3_sram_configure_core_dpll - change DPLL3 M2 divider - * r0 = new SDRC_RFR_CTRL register contents - * r1 = new SDRC_ACTIM_CTRLA register contents - * r2 = new SDRC_ACTIM_CTRLB register contents - * r3 = new M2 divider setting (only 1 and 2 supported right now) - * r4 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for + * + * Params passed in registers: + * r0 = new M2 divider setting (only 1 and 2 supported right now) + * r1 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for * SDRC rates < 83MHz - * r5 = number of MPU cycles to wait for SDRC to stabilize after + * r2 = number of MPU cycles to wait for SDRC to stabilize after * reprogramming the SDRC when switching to a slower MPU speed - * r6 = new SDRC_MR_0 register value - * r7 = increasing SDRC rate? (1 = yes, 0 = no) + * r3 = increasing SDRC rate? (1 = yes, 0 = no) + * + * Params passed via the stack. The needed params will be copied in SRAM + * before use by the code in SRAM (SDRAM is not accessible during SDRC + * reconfiguration): + * new SDRC_RFR_CTRL_0 register contents + * new SDRC_ACTIM_CTRL_A_0 register contents + * new SDRC_ACTIM_CTRL_B_0 register contents + * new SDRC_MR_0 register value + * new SDRC_RFR_CTRL_1 register contents + * new SDRC_ACTIM_CTRL_A_1 register contents + * new SDRC_ACTIM_CTRL_B_1 register contents + * new SDRC_MR_1 register value * + * If the param SDRC_RFR_CTRL_1 is 0, the parameters + * are not programmed into the SDRC CS1 registers */ ENTRY(omap3_sram_configure_core_dpll) stmfd sp!, {r1-r12, lr} @ store regs to stack - ldr r4, [sp, #52] @ pull extra args off the stack - ldr r5, [sp, #56] @ load extra args from the stack - ldr r6, [sp, #60] @ load extra args from the stack - ldr r7, [sp, #64] @ load extra args from the stack + + @ pull the extra args off the stack + @ and store them in SRAM + ldr r4, [sp, #52] + str r4, omap_sdrc_rfr_ctrl_0_val + ldr r4, [sp, #56] + str r4, omap_sdrc_actim_ctrl_a_0_val + ldr r4, [sp, #60] + str r4, omap_sdrc_actim_ctrl_b_0_val + ldr r4, [sp, #64] + str r4, omap_sdrc_mr_0_val + ldr r4, [sp, #68] + str r4, omap_sdrc_rfr_ctrl_1_val + cmp r4, #0 @ if SDRC_RFR_CTRL_1 is 0, + beq skip_cs1_params @ do not use cs1 params + ldr r4, [sp, #72] + str r4, omap_sdrc_actim_ctrl_a_1_val + ldr r4, [sp, #76] + str r4, omap_sdrc_actim_ctrl_b_1_val + ldr r4, [sp, #80] + str r4, omap_sdrc_mr_1_val +skip_cs1_params: dsb @ flush buffered writes to interconnect - cmp r7, #1 @ if increasing SDRC clk rate, + + cmp r3, #1 @ if increasing SDRC clk rate, bleq configure_sdrc @ program the SDRC regs early (for RFR) - cmp r4, #SDRC_UNLOCK_DLL @ set the intended DLL state + cmp r1, #SDRC_UNLOCK_DLL @ set the intended DLL state bleq unlock_dll blne lock_dll bl sdram_in_selfrefresh @ put SDRAM in self refresh, idle SDRC bl configure_core_dpll @ change the DPLL3 M2 divider + mov r12, r2 + bl wait_clk_stable @ wait for SDRC to stabilize bl enable_sdrc @ take SDRC out of idle - cmp r4, #SDRC_UNLOCK_DLL @ wait for DLL status to change + cmp r1, #SDRC_UNLOCK_DLL @ wait for DLL status to change bleq wait_dll_unlock blne wait_dll_lock - cmp r7, #1 @ if increasing SDRC clk rate, + cmp r3, #1 @ if increasing SDRC clk rate, beq return_to_sdram @ return to SDRAM code, otherwise, bl configure_sdrc @ reprogram SDRC regs now - mov r12, r5 - bl wait_clk_stable @ wait for SDRC to stabilize return_to_sdram: isb @ prevent speculative exec past here mov r0, #0 @ return value @@ -113,7 +143,7 @@ return_to_sdram: unlock_dll: ldr r11, omap3_sdrc_dlla_ctrl ldr r12, [r11] - and r12, r12, #FIXEDDELAY_MASK + bic r12, r12, #FIXEDDELAY_MASK orr r12, r12, #FIXEDDELAY_DEFAULT orr r12, r12, #DLLIDLE_MASK str r12, [r11] @ (no OCP barrier needed) @@ -129,7 +159,6 @@ sdram_in_selfrefresh: ldr r12, [r11] @ read the contents of SDRC_POWER mov r9, r12 @ keep a copy of SDRC_POWER bits orr r12, r12, #SRFRONIDLEREQ_MASK @ enable self refresh on idle - bic r12, r12, #PWDENA_MASK @ clear PWDENA str r12, [r11] @ write back to SDRC_POWER register ldr r12, [r11] @ posted-write barrier for SDRC idle_sdrc: @@ -149,7 +178,7 @@ configure_core_dpll: ldr r12, [r11] ldr r10, core_m2_mask_val @ modify m2 for core dpll and r12, r12, r10 - orr r12, r12, r3, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT + orr r12, r12, r0, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT str r12, [r11] ldr r12, [r11] @ posted-write barrier for CM bx lr @@ -187,15 +216,34 @@ wait_dll_unlock: bne wait_dll_unlock bx lr configure_sdrc: - ldr r11, omap3_sdrc_rfr_ctrl - str r0, [r11] - ldr r11, omap3_sdrc_actim_ctrla - str r1, [r11] - ldr r11, omap3_sdrc_actim_ctrlb - str r2, [r11] + ldr r12, omap_sdrc_rfr_ctrl_0_val @ fetch value from SRAM + ldr r11, omap3_sdrc_rfr_ctrl_0 @ fetch addr from SRAM + str r12, [r11] @ store + ldr r12, omap_sdrc_actim_ctrl_a_0_val + ldr r11, omap3_sdrc_actim_ctrl_a_0 + str r12, [r11] + ldr r12, omap_sdrc_actim_ctrl_b_0_val + ldr r11, omap3_sdrc_actim_ctrl_b_0 + str r12, [r11] + ldr r12, omap_sdrc_mr_0_val ldr r11, omap3_sdrc_mr_0 - str r6, [r11] - ldr r6, [r11] @ posted-write barrier for SDRC + str r12, [r11] + ldr r12, omap_sdrc_rfr_ctrl_1_val + cmp r12, #0 @ if SDRC_RFR_CTRL_1 is 0, + beq skip_cs1_prog @ do not program cs1 params + ldr r11, omap3_sdrc_rfr_ctrl_1 + str r12, [r11] + ldr r12, omap_sdrc_actim_ctrl_a_1_val + ldr r11, omap3_sdrc_actim_ctrl_a_1 + str r12, [r11] + ldr r12, omap_sdrc_actim_ctrl_b_1_val + ldr r11, omap3_sdrc_actim_ctrl_b_1 + str r12, [r11] + ldr r12, omap_sdrc_mr_1_val + ldr r11, omap3_sdrc_mr_1 + str r12, [r11] +skip_cs1_prog: + ldr r12, [r11] @ posted-write barrier for SDRC bx lr omap3_sdrc_power: @@ -206,14 +254,40 @@ omap3_cm_idlest1_core: .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST) omap3_cm_iclken1_core: .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1) -omap3_sdrc_rfr_ctrl: + +omap3_sdrc_rfr_ctrl_0: .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0) -omap3_sdrc_actim_ctrla: +omap3_sdrc_rfr_ctrl_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_1) +omap3_sdrc_actim_ctrl_a_0: .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0) -omap3_sdrc_actim_ctrlb: +omap3_sdrc_actim_ctrl_a_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_1) +omap3_sdrc_actim_ctrl_b_0: .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0) +omap3_sdrc_actim_ctrl_b_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_1) omap3_sdrc_mr_0: .word OMAP34XX_SDRC_REGADDR(SDRC_MR_0) +omap3_sdrc_mr_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_MR_1) +omap_sdrc_rfr_ctrl_0_val: + .word 0xDEADBEEF +omap_sdrc_rfr_ctrl_1_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_a_0_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_a_1_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_b_0_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_b_1_val: + .word 0xDEADBEEF +omap_sdrc_mr_0_val: + .word 0xDEADBEEF +omap_sdrc_mr_1_val: + .word 0xDEADBEEF + omap3_sdrc_dlla_status: .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) omap3_sdrc_dlla_ctrl: @@ -223,3 +297,4 @@ core_m2_mask_val: ENTRY(omap3_sram_configure_core_dpll_sz) .word . - omap3_sram_configure_core_dpll + |