From a9d2ba1444b0af6c2d8534f0b306660ffc045bc6 Mon Sep 17 00:00:00 2001 From: Ian Wisbon Date: Thu, 10 Feb 2011 17:15:15 -0500 Subject: Linux 2.6.31 Release for Digi ConnectCore Wi-i.MX boards --- arch/arm/mach-mx23/Kconfig | 16 + arch/arm/mach-mx23/Makefile | 1 + arch/arm/mach-mx23/bus_freq.c | 82 +-- arch/arm/mach-mx23/clock.c | 962 ++++++++++++++++++++++++-------- arch/arm/mach-mx23/device.c | 237 ++++++-- arch/arm/mach-mx23/emi.S | 93 +-- arch/arm/mach-mx23/emi.inc | 68 ++- arch/arm/mach-mx23/include/mach/lcdif.h | 171 +++++- arch/arm/mach-mx23/include/mach/mx23.h | 6 + arch/arm/mach-mx23/mx23_pins.h | 2 +- arch/arm/mach-mx23/mx23evk.c | 41 ++ arch/arm/mach-mx23/mx23evk.h | 6 + arch/arm/mach-mx23/mx23evk_pins.c | 544 ++++++++++++++---- arch/arm/mach-mx23/pm.c | 2 +- arch/arm/mach-mx23/usb_dr.c | 32 +- 15 files changed, 1775 insertions(+), 488 deletions(-) (limited to 'arch/arm/mach-mx23') diff --git a/arch/arm/mach-mx23/Kconfig b/arch/arm/mach-mx23/Kconfig index 0a122b009687..28009b0d62cb 100644 --- a/arch/arm/mach-mx23/Kconfig +++ b/arch/arm/mach-mx23/Kconfig @@ -7,3 +7,19 @@ config MACH_MX23EVK select USB_ARCH_HAS_EHCI endchoice + + +config MXS_UNIQUE_ID + bool "Support for UniqueID on boot media" + default y + +config MXS_UNIQUE_ID_OTP + bool "UniqueID on OTP" + depends on MXS_UNIQUE_ID + default y + +config VECTORS_PHY_ADDR + int "vectors address" + default 0 + help + This config set vectors table is located which physical address diff --git a/arch/arm/mach-mx23/Makefile b/arch/arm/mach-mx23/Makefile index 622981c9572d..a5e278190326 100644 --- a/arch/arm/mach-mx23/Makefile +++ b/arch/arm/mach-mx23/Makefile @@ -7,6 +7,7 @@ obj-y += pinctrl.o clock.o device.o serial.o power.o pm.o sleep.o bus_freq.o obj-$(CONFIG_MACH_MX23EVK) += mx23evk.o mx23evk_pins.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o obj-$(CONFIG_MXS_RAM_FREQ_SCALING) +=emi.o +obj-$(CONFIG_MXS_UNIQUE_ID_OTP) += otp.o # USB support ifneq ($(strip $(CONFIG_USB_GADGET_ARC) $(CONFIG_USB_EHCI_ARC_OTG)),) diff --git a/arch/arm/mach-mx23/bus_freq.c b/arch/arm/mach-mx23/bus_freq.c index b4efabdfefcc..9133e6b1080a 100644 --- a/arch/arm/mach-mx23/bus_freq.c +++ b/arch/arm/mach-mx23/bus_freq.c @@ -46,36 +46,32 @@ #define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR) -#define BP_CLKCTRL_HBUS_ASM_ENABLE 20 -#define CLKCTRL_PLL_PWD_BIT 17 -#define CLKCTRL_PLL_BYPASS 0x1ff #define BF(value, field) (((value) << BP_##field) & BM_##field) struct profile profiles[] = { { 454736, 151580, 130910, 0, 1550000, - 1450000, 355000, 3300000, 1750000, 0 }, - { 392727, 130910, 130910, 0, 1475000, - 1375000, 225000, 3300000, 1750000, 0 }, - { 360000, 120000, 120000, 0, 1375000, - 1275000, 200000, 3300000, 1750000, 0 }, + 1450000, 355000, 3300000, 1750000, 24000, 0 }, + { 392727, 130910, 130910, 0, 1450000, + 1375000, 225000, 3300000, 1750000, 24000, 0x1CF3 }, + { 360000, 120000, 130910, 0, 1375000, + 1275000, 200000, 3300000, 1750000, 24000, 0x1CF3 }, { 261818, 130910, 130910, 0, 1275000, - 1175000, 173000, 3300000, 1750000, 0 }, + 1175000, 173000, 3300000, 1750000, 24000, 0x1CF3 }, #ifdef CONFIG_MXS_RAM_MDDR { 64000, 64000, 48000, 3, 1050000, - 975000, 150000, 3300000, 1750000, 0 }, + 975000, 150000, 3300000, 1750000, 24000, 0x1CF3 }, { 24000, 24000, 24000, 3, 1050000, - 975000, 150000, 3075000, 1725000, 1 }, + 975000, 150000, 3075000, 1725000, 6000, 0x1C93 }, #else { 64000, 64000, 96000, 3, 1050000, - 975000, 150000, 3300000, 1750000, 0 }, - { 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 }, + 975000, 150000, 3300000, 1750000, 24000, 0x1CF3 }, + { 24000, 24000, 96000, 3, 1050000, + 975000, 150000, 3300000, 1725000, 6000, 0x1C93 }, #endif }; static struct clk *usb_clk; static struct clk *lcdif_clk; -u32 clkseq_setting; int low_freq_used(void) { @@ -84,60 +80,14 @@ int low_freq_used(void) return 1; else return 0; - } - -void hbus_auto_slow_mode_enable(void) -{ - __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); -} -EXPORT_SYMBOL(hbus_auto_slow_mode_enable); - -void hbus_auto_slow_mode_disable(void) -{ - __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); } -EXPORT_SYMBOL(hbus_auto_slow_mode_disable); -int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq) +int is_hclk_autoslow_ok(void) { - struct cpufreq_freqs freqs; - - freqs.old = clk_get_rate(clk); - freqs.cpu = 0; - freqs.new = freq; - - if (freqs.old == 24000 && freqs.new > 24000) { - /* turn pll on */ - __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLLCTRL0_SET); - udelay(10); - } else if (freqs.old > 24000 && freqs.new == 24000) - clkseq_setting = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - return 0; -} - -int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq) -{ - struct cpufreq_freqs freqs; - - freqs.old = clk_get_rate(clk); - freqs.cpu = 0; - freqs.new = freq; - - if (freqs.old > 24000 && freqs.new == 24000) { - /* turn pll off */ - __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLLCTRL0_CLR); - __raw_writel(CLKCTRL_PLL_BYPASS, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - } else if (freqs.old == 24000 && freqs.new > 24000) - __raw_writel(clkseq_setting, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - - return 0; + if (clk_get_usecount(usb_clk) == 0) + return 1; + else + return 0; } int timing_ctrl_rams(int ss) diff --git a/arch/arm/mach-mx23/clock.c b/arch/arm/mach-mx23/clock.c index 957a70213399..9e18dbc74337 100644 --- a/arch/arm/mach-mx23/clock.c +++ b/arch/arm/mach-mx23/clock.c @@ -18,10 +18,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -29,17 +31,130 @@ #include "regs-clkctrl.h" #include "regs-digctl.h" +#include #include #define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR) +#define RTC_BASE_ADDR IO_ADDRESS(RTC_PHYS_ADDR) + +/* these are the maximum clock speeds that have been + * validated to run at the minumum VddD target voltage level for cpu operation + * (presently 1.05V target, .975V Brownout). Higher clock speeds for GPMI and + * SSP have not been validated. + */ +#define PLL_ENABLED_MAX_CLK_SSP 96000000 +#define PLL_ENABLED_MAX_CLK_GPMI 96000000 + /* external clock input */ -static struct clk xtal_clk[]; -static unsigned long xtal_clk_rate[3] = { 24000000, 24000000, 32000 }; +static struct clk pll_clk; +static struct clk ref_xtal_clk; + +#ifdef DEBUG +static void print_ref_counts(void); +#endif static unsigned long enet_mii_phy_rate; +static inline int clk_is_busy(struct clk *clk) +{ + if ((clk->parent == &ref_xtal_clk) && (clk->xtal_busy_bits)) + return __raw_readl(clk->busy_reg) & (1 << clk->xtal_busy_bits); + else if (clk->busy_bits && clk->busy_reg) + return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits); + else { + printk(KERN_ERR "WARNING: clock has no assigned busy \ + register or bits\n"); + udelay(10); + return 0; + } +} + +static inline int clk_busy_wait(struct clk *clk) +{ + int i; + + for (i = 10000000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) + return -ETIMEDOUT; + else + return 0; +} + +static bool mx23_enable_h_autoslow(bool enable) +{ + bool currently_enabled; + + if (__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS) & + BM_CLKCTRL_HBUS_AUTO_SLOW_MODE) + currently_enabled = true; + else + currently_enabled = false; + + if (enable) + __raw_writel(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE, + CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); + else + __raw_writel(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE, + CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); + return currently_enabled; +} + + +static void mx23_set_hbus_autoslow_flags(u16 mask) +{ + u32 reg; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + reg &= 0xFFFF; + reg |= mask << 16; + __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); +} + +static void local_clk_disable(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->ref) + return; + + if ((--clk->ref) & CLK_EN_MASK) + return; + + if (clk->disable) + clk->disable(clk); + local_clk_disable(clk->secondary); + local_clk_disable(clk->parent); +} + +static int local_clk_enable(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if ((clk->ref++) & CLK_EN_MASK) + return 0; + if (clk->parent) + local_clk_enable(clk->parent); + if (clk->secondary) + local_clk_enable(clk->secondary); + if (clk->enable) + clk->enable(clk); + return 0; +} + + +static bool mx23_is_clk_enabled(struct clk *clk) +{ + if (clk->enable_reg) + return (__raw_readl(clk->enable_reg) & + clk->enable_bits) ? 0 : 1; + else + return (clk->ref & CLK_EN_MASK) ? 1 : 0; +} + + static int mx23_raw_enable(struct clk *clk) { unsigned int reg; @@ -48,6 +163,9 @@ static int mx23_raw_enable(struct clk *clk) reg &= ~clk->enable_bits; __raw_writel(reg, clk->enable_reg); } + if (clk->busy_reg) + clk_busy_wait(clk); + return 0; } @@ -61,29 +179,14 @@ static void mx23_raw_disable(struct clk *clk) } } -static unsigned long xtal_get_rate(struct clk *clk) +static unsigned long ref_xtal_get_rate(struct clk *clk) { - int id = clk - xtal_clk; - return xtal_clk_rate[id]; + return 24000000; } -static struct clk xtal_clk[] = { - { - .flags = RATE_FIXED, - .get_rate = xtal_get_rate, - }, - { - .flags = RATE_FIXED, - .get_rate = xtal_get_rate, - }, - { - .flags = RATE_FIXED, - .get_rate = xtal_get_rate, - }, -}; - static struct clk ref_xtal_clk = { - .parent = &xtal_clk[0], + .flags = RATE_FIXED, + .get_rate = ref_xtal_get_rate, }; static unsigned long pll_get_rate(struct clk *clk); @@ -107,20 +210,23 @@ static unsigned long pll_get_rate(struct clk *clk) static int pll_enable(struct clk *clk) { - int timeout = 100; - unsigned long reg; + u32 reg; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0); + + if ((reg & BM_CLKCTRL_PLLCTRL0_POWER) && + (reg & BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS)) + return 0; __raw_writel(BM_CLKCTRL_PLLCTRL0_POWER | BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS, CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_SET); - do { - udelay(10); - reg = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLLCTRL1); - timeout--; - } while ((timeout > 0) && !(reg & BM_CLKCTRL_PLLCTRL1_LOCK)); - if (timeout <= 0) - return -EFAULT; + /* only a 10us delay is need. PLLCTRL1 LOCK bitfied is only a timer + * and is incorrect (excessive). Per definition of the PLLCTRL0 + * POWER field, waiting at least 10us. + */ + udelay(10); + return 0; } @@ -171,6 +277,8 @@ static unsigned long ref_cpu_get_rate(struct clk *clk) static struct clk ref_cpu_clk = { .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, .get_rate = ref_cpu_get_rate, .round_rate = ref_clk_round_rate, .set_rate = ref_clk_set_rate, @@ -178,6 +286,8 @@ static struct clk ref_cpu_clk = { .enable_bits = BM_CLKCTRL_FRAC_CLKGATECPU, .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, .scale_bits = BP_CLKCTRL_FRAC_CPUFRAC, + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU, + .busy_bits = 28, }; static unsigned long ref_emi_get_rate(struct clk *clk) @@ -191,6 +301,8 @@ static unsigned long ref_emi_get_rate(struct clk *clk) static struct clk ref_emi_clk = { .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, .get_rate = ref_emi_get_rate, .set_rate = ref_clk_set_rate, .round_rate = ref_clk_round_rate, @@ -202,10 +314,12 @@ static struct clk ref_emi_clk = { static unsigned long ref_io_get_rate(struct clk *clk); static struct clk ref_io_clk = { - .parent = &pll_clk, - .get_rate = ref_io_get_rate, - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, - .enable_bits = BM_CLKCTRL_FRAC_CLKGATEIO, + .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .get_rate = ref_io_get_rate, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, + .enable_bits = BM_CLKCTRL_FRAC_CLKGATEIO, }; static unsigned long ref_io_get_rate(struct clk *clk) @@ -229,6 +343,8 @@ static unsigned long ref_pix_get_rate(struct clk *clk) static struct clk ref_pix_clk = { .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, .get_rate = ref_pix_get_rate, .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, .enable_bits = BM_CLKCTRL_FRAC_CLKGATEPIX, @@ -237,63 +353,20 @@ static struct clk ref_pix_clk = { static struct clk cpu_clk, h_clk; static int clkseq_set_parent(struct clk *clk, struct clk *parent) { - int ret = -EINVAL; - int shift = 8; + int shift; + if (clk->parent == parent) + return 0; /* clock parent already at target. nothing to do */ /* bypass? */ if (parent == &ref_xtal_clk) shift = 4; + else + shift = 8; - if (clk->bypass_reg) { - u32 hbus_val, cpu_val; - - if (clk == &cpu_clk && shift == 4) { - hbus_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_HBUS); - cpu_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CPU); - - hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | - BM_CLKCTRL_HBUS_DIV); - hbus_val |= 1; - - cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; - cpu_val |= 1; - - __raw_writel(1 << clk->bypass_bits, - clk->bypass_reg + shift); - - __raw_writel(hbus_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - __raw_writel(cpu_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - /* h_clk.rate = 0; */ - } else if (clk == &cpu_clk && shift == 8) { - hbus_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_HBUS); - cpu_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CPU); - hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | - BM_CLKCTRL_HBUS_DIV); - hbus_val |= 2; - cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; - cpu_val |= 2; - - __raw_writel(hbus_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - __raw_writel(cpu_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - /* h_clk.rate = 0; */ + if (clk->bypass_reg) + __raw_writel(1 << clk->bypass_bits, clk->bypass_reg + shift); - __raw_writel(1 << clk->bypass_bits, - clk->bypass_reg + shift); - } else - __raw_writel(1 << clk->bypass_bits, - clk->bypass_reg + shift); - ret = 0; - } - - return ret; + return 0; } static unsigned long lcdif_get_rate(struct clk *clk) @@ -336,6 +409,8 @@ static int lcdif_set_rate(struct clk *clk, unsigned long rate) ns_cycle *= 2; /* Fix calculate double frequency */ + + for (div = 1; div < 256; ++div) { u32 fracdiv; u32 ps_result; @@ -394,16 +469,9 @@ static int lcdif_set_rate(struct clk *clk, unsigned long rate) __raw_writel(reg_val, clk->scale_reg); /* Wait for divider update */ - if (clk->busy_reg) { - int i; - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - if (!i) { - ret = -ETIMEDOUT; - goto out; - } - } + ret = clk_busy_wait(clk); + if (ret) + goto out; /* Switch to ref_pix source */ reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); @@ -414,6 +482,14 @@ out: return ret; } +/* + * We set lcdif_clk's parent as &pll_clk deliberately, although + * in IC spec lcdif_clk(CLK_PIX) is derived from ref_pix which in turn + * is derived from PLL. By doing so, users just need to set/get clock rate + * for lcdif_clk, without need to take care of ref_pix, because the clock + * driver will automatically calculate the fracdivider for HW_CLKCTRL_FRAC + * and the divider for HW_CLKCTRL_PIX conjointly. + */ static struct clk lcdif_clk = { .parent = &pll_clk, .enable = mx23_raw_enable, @@ -464,20 +540,77 @@ static unsigned long cpu_round_rate(struct clk *clk, unsigned long rate) static int cpu_set_rate(struct clk *clk, unsigned long rate) { - unsigned long root_rate = - clk->parent->parent->get_rate(clk->parent->parent); - int i; + unsigned long root_rate = pll_clk.get_rate(&pll_clk); + int ret = -EINVAL; u32 clkctrl_cpu = 1; u32 c = clkctrl_cpu; u32 clkctrl_frac = 1; u32 val; - u32 reg_val; + u32 reg_val, hclk_reg; + bool h_autoslow; - if (rate < 24000000) + /* make sure the cpu div_xtal is 1 */ + reg_val = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_CPU); + reg_val &= ~(BM_CLKCTRL_CPU_DIV_XTAL); + reg_val |= (1 << BP_CLKCTRL_CPU_DIV_XTAL); + __raw_writel(reg_val, CLKCTRL_BASE_ADDR+HW_CLKCTRL_CPU); + + if (rate < ref_xtal_get_rate(&ref_xtal_clk)) return -EINVAL; - else if (rate == 24000000) { + + if (rate == clk_get_rate(clk)) + return 0; + /* temporaily disable h autoslow to avoid + * hclk getting too slow while temporarily + * changing clocks + */ + h_autoslow = mx23_enable_h_autoslow(false); + + if (rate == ref_xtal_get_rate(&ref_xtal_clk)) { + /* switch to the 24M source */ clk_set_parent(clk, &ref_xtal_clk); + + /* to avoid bus starvation issues, we'll go ahead + * and change hbus clock divider to 1 now. Cpufreq + * or other clock management can lower it later if + * desired for power savings or other reasons, but + * there should be no need to with hbus autoslow + * functionality enabled. + */ + + ret = clk_busy_wait(&cpu_clk); + if (ret) { + printk(KERN_ERR "* couldn't set\ + up CPU divisor\n"); + return ret; + } + + ret = clk_busy_wait(&h_clk); + if (ret) { + printk(KERN_ERR "* H_CLK busy timeout\n"); + return ret; + } + + hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS); + hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV); + hclk_reg |= (1 << BP_CLKCTRL_HBUS_DIV); + + __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); + + ret = clk_busy_wait(&cpu_clk); + if (ret) { + printk(KERN_ERR "** couldn't set\ + up CPU divisor\n"); + return ret; + } + + ret = clk_busy_wait(&h_clk); + if (ret) { + printk(KERN_ERR "** CLK busy timeout\n"); + return ret; + } + } else { for ( ; c < 0x40; c++) { u32 f = ((root_rate/1000)*18/c + (rate/1000)/2) / @@ -502,33 +635,116 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) if ((abs(d) > 100) || (clkctrl_frac < 18) || (clkctrl_frac > 35)) return -EINVAL; - } + } - /* Set Frac div */ + /* prepare Frac div */ val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - val &= ~(BM_CLKCTRL_FRAC_CPUFRAC << BP_CLKCTRL_FRAC_CPUFRAC); - val |= clkctrl_frac; - __raw_writel(val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - /* Do not gate */ - __raw_writel(BM_CLKCTRL_FRAC_CLKGATECPU, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_FRAC_CLR); + val &= ~(BM_CLKCTRL_FRAC_CPUFRAC); + val |= (clkctrl_frac << BP_CLKCTRL_FRAC_CPUFRAC); - /* write clkctrl_cpu */ + /* prepare clkctrl_cpu div*/ reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); reg_val &= ~0x3F; reg_val |= clkctrl_cpu; + /* set safe hbus clock divider. A divider of 3 ensure that + * the Vddd voltage required for the cpuclk is sufficiently + * high for the hbus clock and under 24MHz cpuclk conditions, + * a divider of at least 3 ensures hbusclk doesn't remain + * uneccesarily low which hurts performance + */ + hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS); + hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV); + hclk_reg |= (3 << BP_CLKCTRL_HBUS_DIV); + + /* if the pll was OFF, we need to turn it ON. + * Even if it was ON, we want to temporarily + * increment it by 1 to avoid turning off + * in the upcoming parent clock change to xtal. This + * avoids waiting an extra 10us for every cpu clock + * change between ref_cpu sourced frequencies. + */ + pll_enable(&pll_clk); + pll_clk.ref++; + + /* switch to XTAL CLK source temparily while + * we manipulate ref_cpu frequency */ + clk_set_parent(clk, &ref_xtal_clk); + + ret = clk_busy_wait(&h_clk); + + if (ret) { + printk(KERN_ERR "-* HCLK busy wait timeout\n"); + return ret; + } + + ret = clk_busy_wait(clk); + + if (ret) { + printk(KERN_ERR "-* couldn't set\ + up CPU divisor\n"); + return ret; + } + + __raw_writel(val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); + + /* clear the gate */ + __raw_writel(BM_CLKCTRL_FRAC_CLKGATECPU, CLKCTRL_BASE_ADDR + + HW_CLKCTRL_FRAC_CLR); + + /* set the ref_cpu integer divider */ __raw_writel(reg_val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - if (!i) { - printk(KERN_ERR "couldn't set up CPU divisor\n"); - return -ETIMEDOUT; + /* wait for the ref_cpu path to become stable before + * switching over to it + */ + + ret = clk_busy_wait(&ref_cpu_clk); + + if (ret) { + printk(KERN_ERR "-** couldn't set\ + up CPU divisor\n"); + return ret; } + + /* change hclk divider to safe value for any ref_cpu + * value. + */ + __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + + ret = clk_busy_wait(&h_clk); + + if (ret) { + printk(KERN_ERR "-** HCLK busy wait timeout\n"); + return ret; + } + + clk_set_parent(clk, &ref_cpu_clk); + + /* decrement the pll_clk ref count because + * we temporarily enabled/incremented the count + * above. + */ + pll_clk.ref--; + + ret = clk_busy_wait(&cpu_clk); + + if (ret) { + printk(KERN_ERR "-*** Couldn't set\ + up CPU divisor\n"); + return ret; + } + + ret = clk_busy_wait(&h_clk); + + if (ret) { + printk(KERN_ERR "-*** HCLK busy wait timeout\n"); + return ret; + } + } - return 0; + mx23_enable_h_autoslow(h_autoslow); + return ret; } static struct clk cpu_clk = { @@ -543,6 +759,7 @@ static struct clk cpu_clk = { .bypass_bits = 7, .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU, .busy_bits = 28, + .xtal_busy_bits = 29, }; static unsigned long uart_get_rate(struct clk *clk) @@ -598,25 +815,99 @@ static unsigned long x_get_rate(struct clk *clk) return clk->parent->get_rate(clk->parent) / reg; } +static unsigned long x_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned int root_rate, frac_rate; + unsigned int div; + root_rate = clk->parent->get_rate(clk->parent); + frac_rate = root_rate % rate; + div = root_rate / rate; + /* while the reference manual specifies that divider + * values up to 1023 are aloud, other critial SoC compents + * require higher x clock values at all times. Through + * limited testing, the lradc functionality to measure + * the battery voltage and copy this value to the + * power supply requires at least a 64kHz xclk. + * so the divider will be limited to 375. + */ + if ((div == 0) || (div > 375)) + return root_rate; + if (frac_rate == 0) + return rate; + else + return root_rate / (div + 1); +} + +static int x_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long root_rate; + unsigned long round_rate; + unsigned int reg, div; + root_rate = clk->parent->get_rate(clk->parent); + + if ((!clk->round_rate) || !(clk->scale_reg)) + return -EINVAL; + + round_rate = clk->round_rate(clk, rate); + div = root_rate / round_rate; + + if (root_rate % round_rate) + return -EINVAL; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); + reg &= ~(BM_CLKCTRL_XBUS_DIV_FRAC_EN | BM_CLKCTRL_XBUS_DIV); + reg |= BF_CLKCTRL_XBUS_DIV(div); + __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); + + return clk_busy_wait(clk); + +} + static struct clk x_clk = { .parent = &ref_xtal_clk, .get_rate = x_get_rate, + .set_rate = x_set_rate, + .round_rate = x_round_rate, + .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS, + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS, + .busy_bits = 31, }; + + static struct clk ana_clk = { .parent = &ref_xtal_clk, }; -static unsigned long rtc_get_rate(struct clk *clk) + + +static unsigned long xtal_clock32k_get_rate(struct clk *clk) { - if (clk->parent == &xtal_clk[2]) - return clk->parent->get_rate(clk->parent); - return clk->parent->get_rate(clk->parent) / 768; + if (__raw_readl(RTC_BASE_ADDR + HW_RTC_PERSISTENT0) & + BM_RTC_PERSISTENT0_XTAL32_FREQ) + return 32000; + else + return 32768; } -static struct clk rtc_clk = { - .parent = &ref_xtal_clk, - .get_rate = rtc_get_rate, +static struct clk xtal_clock32k_clk = { + .get_rate = xtal_clock32k_get_rate, +}; + +static unsigned long rtc32k_get_rate(struct clk *clk) +{ + if (clk->parent == &ref_xtal_clk) + /* mx23 reference manual had error. + * fixed divider is 750 not 768 + */ + return clk->parent->get_rate(clk->parent) / 750; + else + return xtal_clock32k_get_rate(clk); +} + +static struct clk rtc32k_clk = { + .parent = &xtal_clock32k_clk, + .get_rate = rtc32k_get_rate, }; static unsigned long h_get_rate(struct clk *clk) @@ -656,23 +947,14 @@ static int h_set_rate(struct clk *clk, unsigned long rate) if (root_rate % round_rate) return -EINVAL; - if ((root_rate < rate) && (root_rate == 64000000)) - div = 3; - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); reg &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | BM_CLKCTRL_HBUS_DIV); reg |= BF_CLKCTRL_HBUS_DIV(div); __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - if (clk->busy_reg) { - int i; - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - if (!i) { - printk(KERN_ERR "couldn't set up AHB divisor\n"); - return -ETIMEDOUT; - } + if (clk_busy_wait(clk)) { + printk(KERN_ERR "couldn't set up AHB divisor\n"); + return -EINVAL; } return 0; @@ -720,29 +1002,39 @@ static unsigned long emi_round_rate(struct clk *clk, unsigned long rate) return root_rate / div; } +/* when changing the emi clock, dram access must be + * disabled. Special handling is needed to perform + * the emi clock change without touching sdram. + */ static int emi_set_rate(struct clk *clk, unsigned long rate) { int ret = 0; - if (rate < 24000) + struct mxs_emi_scaling_data sc_data; + + unsigned long clkctrl_emi; + unsigned long clkctrl_frac; + int div = 1; + unsigned long root_rate, cur_emi_div, cur_emi_frac; + struct clk *target_parent_p = &ref_xtal_clk; + + if (rate < ref_xtal_get_rate(&ref_xtal_clk)) return -EINVAL; - else { - int i; - struct mxs_emi_scaling_data sc_data; - int (*scale)(struct mxs_emi_scaling_data *) = - (void *)(MX23_OCRAM_BASE + 0x1000); - void *saved_ocram; - unsigned long clkctrl_emi; - unsigned long clkctrl_frac; - int div = 1; - unsigned long root_rate = - clk->parent->parent->get_rate(clk->parent->parent); - /* - * We've been setting div to HW_CLKCTRL_CPU_RD() & 0x3f so far. - * TODO: verify 1 is still valid. - */ - if (!mxs_ram_funcs_sz) - goto out; + + if (!mxs_ram_funcs_sz) + goto out; + + sc_data.cur_freq = (clk->get_rate(clk)) / 1000 / 1000; + sc_data.new_freq = rate / 1000 / 1000; + + if (sc_data.cur_freq == sc_data.new_freq) + goto out; + + if (rate != ref_xtal_get_rate(&ref_xtal_clk)) { + target_parent_p = &ref_emi_clk; + pll_enable(&pll_clk); + + root_rate = pll_clk.get_rate(&pll_clk); for (clkctrl_emi = div; clkctrl_emi < 0x3f; clkctrl_emi += div) { @@ -764,37 +1056,62 @@ static int emi_set_rate(struct clk *clk, unsigned long rate) pr_debug("%s: clkctrl_emi %ld, clkctrl_frac %ld\n", __func__, clkctrl_emi, clkctrl_frac); - saved_ocram = kmalloc(mxs_ram_funcs_sz, GFP_KERNEL); - if (!saved_ocram) - return -ENOMEM; - memcpy(saved_ocram, scale, mxs_ram_funcs_sz); - memcpy(scale, mxs_ram_freq_scale, mxs_ram_funcs_sz); - sc_data.emi_div = clkctrl_emi; sc_data.frac_div = clkctrl_frac; - sc_data.cur_freq = (clk->get_rate(clk)) / 1000 / 1000; - sc_data.new_freq = rate / 1000 / 1000; + } + + + cur_emi_div = ((__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_EMI) & + BM_CLKCTRL_EMI_DIV_EMI) >> BP_CLKCTRL_EMI_DIV_EMI); + cur_emi_frac = ((__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_FRAC) & + BM_CLKCTRL_EMI_DIV_EMI) >> BP_CLKCTRL_FRAC_EMIFRAC); + + if ((cur_emi_div == sc_data.emi_div) && + (cur_emi_frac == sc_data.frac_div)) + goto out; + { + unsigned long iram_phy; + bool h_autoslow; + int (*scale)(struct mxs_emi_scaling_data *) = + iram_alloc(mxs_ram_funcs_sz, &iram_phy); + + if (NULL == scale) { + pr_err("%s Not enough iram\n", __func__); + return -ENOMEM; + } + + /* temporaily disable h autoslow to maximize + * performance/minimize time spent with no + * sdram access + */ + h_autoslow = mx23_enable_h_autoslow(false); + + memcpy(scale, mxs_ram_freq_scale, mxs_ram_funcs_sz); local_irq_disable(); local_fiq_disable(); scale(&sc_data); + iram_free(iram_phy, mxs_ram_funcs_sz); + local_fiq_enable(); local_irq_enable(); - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - memcpy(scale, saved_ocram, mxs_ram_funcs_sz); - kfree(saved_ocram); - - if (!i) { - printk(KERN_ERR "couldn't set up EMI divisor\n"); - ret = -ETIMEDOUT; - goto out; - } + /* temporaily disable h autoslow to avoid + * hclk getting too slow while temporarily + * changing clocks + */ + mx23_enable_h_autoslow(h_autoslow); } + + /* this code is for keeping track of ref counts. + * and disabling previous parent if necessary + * actual clkseq changes have already + * been made. + */ + clk_set_parent(clk, target_parent_p); + out: return ret; } @@ -812,8 +1129,9 @@ static struct clk emi_clk = { .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_EMI, .busy_bits = 28, + .xtal_busy_bits = 29, .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, - .bypass_bits = 7, + .bypass_bits = 6, }; static unsigned long ssp_get_rate(struct clk *clk); @@ -821,37 +1139,40 @@ static unsigned long ssp_get_rate(struct clk *clk); static int ssp_set_rate(struct clk *clk, unsigned long rate) { int ret = -EINVAL; - int div = (clk_get_rate(clk->parent) + rate - 1) / rate; - u32 reg_frac; - const int mask = 0x1FF; - int try = 10; - int i = -1; + u32 reg, div; + bool is_clk_enable; - if (div == 0 || div > mask) - goto out; + is_clk_enable = mx23_is_clk_enabled(clk); + if (!is_clk_enable) + local_clk_enable(clk); - reg_frac = __raw_readl(clk->scale_reg); - reg_frac &= ~(mask << clk->scale_bits); + /* if the desired clock can be sourced from ref_xtal, + * use ref_xtal to save power + */ + if ((rate <= ref_xtal_get_rate(&ref_xtal_clk)) && + ((ref_xtal_get_rate(&ref_xtal_clk) % rate) == 0)) + clk_set_parent(clk, &ref_xtal_clk); + else + clk_set_parent(clk, &ref_io_clk); - while (try--) { - __raw_writel(reg_frac | (div << clk->scale_bits), - clk->scale_reg); + if (rate > PLL_ENABLED_MAX_CLK_SSP) + rate = PLL_ENABLED_MAX_CLK_SSP; - if (clk->busy_reg) { - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - } - if (i) - break; - } + div = (clk_get_rate(clk->parent) + rate - 1) / rate; - if (!i) - ret = -ETIMEDOUT; - else - ret = 0; + if (div == 0 || div > BM_CLKCTRL_SSP_DIV) + goto out; + + reg = __raw_readl(clk->scale_reg); + reg &= ~(BM_CLKCTRL_SSP_DIV | BM_CLKCTRL_SSP_DIV_FRAC_EN); + reg |= div << clk->scale_bits; + __raw_writel(reg, clk->scale_reg); + ret = clk_busy_wait(clk); out: + if (!is_clk_enable) + local_clk_disable(clk); + if (ret != 0) printk(KERN_ERR "%s: error %d\n", __func__, ret); return ret; @@ -877,6 +1198,26 @@ static int ssp_set_parent(struct clk *clk, struct clk *parent) return ret; } +/* handle peripheral clocks whose optimal parent dependent on + * system parameters such as cpu_clk rate. For now, this optimization + * only occurs to the peripheral clock when it's not in use to avoid + * handling more complex system clock coordination issues. + */ +static int ssp_set_sys_dependent_parent(struct clk *clk) +{ + if ((clk->ref & CLK_EN_MASK) == 0) { + if (clk_get_rate(&cpu_clk) > ref_xtal_get_rate(&ref_xtal_clk)) { + clk_set_parent(clk, &ref_io_clk); + clk_set_rate(clk, PLL_ENABLED_MAX_CLK_SSP); + } else { + clk_set_parent(clk, &ref_xtal_clk); + clk_set_rate(clk, ref_xtal_get_rate(&ref_xtal_clk)); + } + } + + return 0; +} + static struct clk ssp_clk = { .parent = &ref_io_clk, .get_rate = ssp_get_rate, @@ -889,9 +1230,10 @@ static struct clk ssp_clk = { .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP, .scale_bits = 0, .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, - .bypass_bits = 3, + .bypass_bits = 5, .set_rate = ssp_set_rate, .set_parent = ssp_set_parent, + .set_sys_dependent_parent = ssp_set_sys_dependent_parent, }; static unsigned long ssp_get_rate(struct clk *clk) @@ -903,6 +1245,123 @@ static unsigned long ssp_get_rate(struct clk *clk) return clk->parent->get_rate(clk->parent) / reg; } +static unsigned long gpmi_get_rate(struct clk *clk) +{ + unsigned int reg; + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI) & + BM_CLKCTRL_GPMI_DIV; + + return clk->parent->get_rate(clk->parent) / reg; +} + +static int gpmi_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + u32 reg, div; + + /* Make absolutely certain the clock is enabled. */ + local_clk_enable(clk); + + /* if the desired clock can be sourced from ref_xtal, + * use ref_xtal to save power + */ + if ((rate <= ref_xtal_get_rate(&ref_xtal_clk)) && + ((ref_xtal_get_rate(&ref_xtal_clk) % rate) == 0)) + clk_set_parent(clk, &ref_xtal_clk); + else + clk_set_parent(clk, &ref_io_clk); + + if (rate > PLL_ENABLED_MAX_CLK_SSP) + rate = PLL_ENABLED_MAX_CLK_GPMI; + + div = (clk_get_rate(clk->parent) + rate - 1) / rate; + + if (div == 0 || div > BM_CLKCTRL_GPMI_DIV) + goto out; + + reg = __raw_readl(clk->scale_reg); + reg &= ~(BM_CLKCTRL_GPMI_DIV | BM_CLKCTRL_GPMI_DIV_FRAC_EN); + reg |= div << clk->scale_bits; + __raw_writel(reg, clk->scale_reg); + + ret = clk_busy_wait(clk); + +out: + + /* Undo the enable above. */ + local_clk_disable(clk); + + if (ret != 0) + printk(KERN_ERR "%s: error %d\n", __func__, ret); + return ret; +} + +static int gpmi_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -EINVAL; + + if (clk->bypass_reg) { + if (clk->parent == parent) + return 0; + if (parent == &ref_io_clk) + __raw_writel(1 << clk->bypass_bits, + clk->bypass_reg + CLR_REGISTER); + else + __raw_writel(1 << clk->bypass_bits, + clk->bypass_reg + SET_REGISTER); + clk->parent = parent; + ret = 0; + } + + return ret; +} + +/* handle peripheral clocks whose optimal parent dependent on + * system parameters such as cpu_clk rate. For now, this optimization + * only occurs to the peripheral clock when it's not in use to avoid + * handling more complex system clock coordination issues. + */ +static int gpmi_set_sys_dependent_parent(struct clk *clk) +{ + + if ((clk->ref & CLK_EN_MASK) == 0) { + if (clk_get_rate(&cpu_clk) > ref_xtal_get_rate(&ref_xtal_clk)) { + clk_set_parent(clk, &ref_io_clk); + clk_set_rate(clk, PLL_ENABLED_MAX_CLK_GPMI); + } else { + clk_set_parent(clk, &ref_xtal_clk); + clk_set_rate(clk, ref_xtal_get_rate(&ref_xtal_clk)); + } + } + + return 0; +} + +static struct clk gpmi_clk = { + .parent = &ref_io_clk, + .secondary = 0, + .flags = 0, + .set_parent = gpmi_set_parent, + .set_sys_dependent_parent = gpmi_set_sys_dependent_parent, + + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI, + .enable_bits = BM_CLKCTRL_GPMI_CLKGATE, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + + .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI, + .scale_bits = 0, + .round_rate = 0, + .set_rate = gpmi_set_rate, + .get_rate = gpmi_get_rate, + + .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, + .bypass_bits = 4, + + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI, + .busy_bits = 29, +}; + static unsigned long pcmspdif_get_rate(struct clk *clk) { return clk->parent->get_rate(clk->parent) / 4; @@ -935,20 +1394,33 @@ static struct clk audio_clk = { .enable_bits = BM_CLKCTRL_XTAL_FILT_CLK24M_GATE, }; +static struct clk vid_clk = { + .parent = &ref_xtal_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC1, + .enable_bits = BM_CLKCTRL_FRAC1_CLKGATEVID, +}; + +static struct clk tv108M_ng_clk = { + .parent = &vid_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_TV, + .enable_bits = BM_CLKCTRL_TV_CLK_TV108M_GATE, + .flags = RATE_FIXED, +}; + +static struct clk tv27M_clk = { + .parent = &vid_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_TV, + .enable_bits = BM_CLKCTRL_TV_CLK_TV_GATE, + .flags = RATE_FIXED, +}; static struct clk_lookup onchip_clocks[] = { - { - .con_id = "xtal.0", - .clk = &xtal_clk[0], - }, - { - .con_id = "xtal.1", - .clk = &xtal_clk[1], - }, - { - .con_id = "xtal.2", - .clk = &xtal_clk[2], - }, { .con_id = "pll.0", .clk = &pll_clk, @@ -977,9 +1449,13 @@ static struct clk_lookup onchip_clocks[] = { .con_id = "lcdif", .clk = &lcdif_clk, }, + { + .con_id = "xtal_clock32k", + .clk = &xtal_clock32k_clk, + }, { .con_id = "rtc", - .clk = &rtc_clk, + .clk = &rtc32k_clk, }, { .con_id = "cpu", @@ -1032,9 +1508,53 @@ static struct clk_lookup onchip_clocks[] = { { .con_id = "spdif", .clk = &pcmspdif_clk, - } + }, + { + .con_id = "ref_vid", + .clk = &vid_clk, + }, + { + .con_id = "tv108M_ng", + .clk = &tv108M_ng_clk, + }, + { + .con_id = "tv27M", + .clk = &tv27M_clk, + }, + { + .con_id = "gpmi", + .clk = &gpmi_clk, + }, }; +/* for debugging */ +#ifdef DEBUG +static void print_ref_counts(void) +{ + + printk(KERN_INFO "pll_clk ref count: %i\n", + pll_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ref_cpu_clk ref count: %i\n", + ref_cpu_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ref_emi_clk ref count: %i\n", + ref_emi_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "lcdif_clk ref count: %i\n", + lcdif_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ref_io_clk ref count: %i\n", + ref_io_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ssp_clk ref count: %i\n", + ssp_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "gpmi_clk ref count: %i\n", + gpmi_clk.ref & CLK_EN_MASK); + +} +#endif static void mx23_clock_scan(void) { @@ -1046,16 +1566,19 @@ static void mx23_clock_scan(void) emi_clk.parent = &ref_xtal_clk; if (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP) ssp_clk.parent = &ref_xtal_clk; -}; + if (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) + gpmi_clk.parent = &ref_xtal_clk; + reg = __raw_readl(RTC_BASE_ADDR + HW_RTC_PERSISTENT0); + if (!(reg & BM_RTC_PERSISTENT0_CLOCKSOURCE)) + rtc32k_clk.parent = &ref_xtal_clk; +}; void __init mx23_set_input_clk(unsigned long xtal0, unsigned long xtal1, unsigned long xtal2, unsigned long enet) { - xtal_clk_rate[0] = xtal0; - xtal_clk_rate[1] = xtal1; - xtal_clk_rate[2] = xtal2; + } void __init mx23_clock_init(void) @@ -1067,4 +1590,7 @@ void __init mx23_clock_init(void) clk_enable(&cpu_clk); clk_enable(&emi_clk); + + clk_en_public_h_asm_ctrl(mx23_enable_h_autoslow, + mx23_set_hbus_autoslow_flags); } diff --git a/arch/arm/mach-mx23/device.c b/arch/arm/mach-mx23/device.c index 38ad3f77181f..cda2285ec3bc 100644 --- a/arch/arm/mach-mx23/device.c +++ b/arch/arm/mach-mx23/device.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -43,6 +44,7 @@ #include "device.h" #include "mx23_pins.h" +#include "mx23evk.h" #include "mach/mx23.h" #if defined(CONFIG_SERIAL_MXS_DUART) || \ @@ -510,69 +512,97 @@ static void __init mx23_init_dcp(void) } #endif -#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) -#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3) -#define MMC0_WP MXS_PIN_TO_GPIO(PINID_PWM4) +#if defined(CONFIG_MTD_NAND_GPMI_NFC) -static int mxs_mmc_get_wp_mmc0(void) +static int gpmi_nfc_platform_init(unsigned int max_chip_count) { - return gpio_get_value(MMC0_WP); + return 0; } -static int mxs_mmc_hw_init_mmc0(void) +static void gpmi_nfc_platform_exit(unsigned int max_chip_count) { - int ret = 0; - - /* Configure write protect GPIO pin */ - ret = gpio_request(MMC0_WP, "mmc0_wp"); - if (ret) { - pr_err("wp\r\n"); - goto out_wp; - } - gpio_set_value(MMC0_WP, 0); - gpio_direction_input(MMC0_WP); - - /* Configure POWER pin as gpio to drive power to MMC slot */ - ret = gpio_request(MMC0_POWER, "mmc0_power"); - if (ret) { - pr_err("power\r\n"); - goto out_power; - } - gpio_direction_output(MMC0_POWER, 0); - mdelay(100); +} - return 0; +static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 }; + +static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = { + .nfc_version = 0, + .boot_rom_version = 0, + .clock_name = "gpmi", + .platform_init = gpmi_nfc_platform_init, + .platform_exit = gpmi_nfc_platform_exit, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 2, + .boot_area_size_in_bytes = 20 * SZ_1M, + .partition_source_types = gpmi_nfc_partition_source_types, + .partitions = 0, + .partition_count = 0, +}; -out_power: - gpio_free(MMC0_WP); -out_wp: - return ret; -} +static struct resource gpmi_nfc_resources[] = { + { + .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = GPMI_PHYS_ADDR, + .end = GPMI_PHYS_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_GPMI_ATTENTION, + .end = IRQ_GPMI_ATTENTION, + }, + { + .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = BCH_PHYS_ADDR, + .end = BCH_PHYS_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_BCH, + .end = IRQ_BCH, + }, + { + .name = GPMI_NFC_DMA_CHANNELS_RES_NAME, + .flags = IORESOURCE_DMA, + .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0, + .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI3, + }, + { + .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_GPMI_DMA, + .end = IRQ_GPMI_DMA, + }, +}; -static void mxs_mmc_hw_release_mmc0(void) +static void __init mx23_init_gpmi_nfc(void) { - gpio_free(MMC0_POWER); - gpio_free(MMC0_WP); + struct platform_device *pdev; + pdev = mxs_get_device(GPMI_NFC_DRIVER_NAME, 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->dev.platform_data = &gpmi_nfc_platform_data; + pdev->resource = gpmi_nfc_resources; + pdev->num_resources = ARRAY_SIZE(gpmi_nfc_resources); + mxs_add_device(pdev, 1); } - -static void mxs_mmc_cmd_pullup_mmc0(int enable) +#else +static void mx23_init_gpmi_nfc(void) { - mxs_set_pullup(PINID_SSP1_CMD, enable, "mmc0_cmd"); } +#endif +#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) static unsigned long mxs_mmc_setclock_mmc0(unsigned long hz) { - struct clk *ssp = clk_get(NULL, "ssp.0"), *parent; - - if (hz > 1000000) - parent = clk_get(NULL, "ref_io.0"); - else - parent = clk_get(NULL, "xtal.0"); + struct clk *ssp = clk_get(NULL, "ssp.0"); - clk_set_parent(ssp, parent); clk_set_rate(ssp, 2 * hz); - clk_put(parent); clk_put(ssp); return hz; @@ -583,7 +613,11 @@ static struct mxs_mmc_platform_data mx23_mmc0_data = { .hw_release = mxs_mmc_hw_release_mmc0, .get_wp = mxs_mmc_get_wp_mmc0, .cmd_pullup = mxs_mmc_cmd_pullup_mmc0, - .setclock = mxs_mmc_setclock_mmc0, + /* + Don't change ssp clock because ssp1 and ssp2 share one ssp clock source + ssp module have own divider. + .setclock = mxs_mmc_setclock_mmc0, + */ .caps = MMC_CAP_4_BIT_DATA, .min_clk = 400000, .max_clk = 48000000, @@ -636,6 +670,68 @@ static void mx23_init_mmc(void) } #endif +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) +static struct resource ssp1_resources[] = { + { + .start = SSP1_PHYS_ADDR, + .end = SSP1_PHYS_ADDR + 0x1FFF, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_SSP1_DMA, + .end = IRQ_SSP1_DMA, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_SSP_ERROR, + .end = IRQ_SSP_ERROR, + .flags = IORESOURCE_IRQ, + }, { + .start = MXS_DMA_CHANNEL_AHB_APBH_SSP1, + .end = MXS_DMA_CHANNEL_AHB_APBH_SSP1, + .flags = IORESOURCE_DMA, + }, +}; + +static void __init mx23_init_spi1(void) +{ + struct platform_device *pdev; + + pdev = mxs_get_device("mxs-spi", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->resource = ssp1_resources; + pdev->num_resources = ARRAY_SIZE(ssp1_resources); + + mxs_add_device(pdev, 3); +} +#else +static void mx23_init_spi1(void) +{ + ; +} +#endif + +#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2) \ + static char *cmdline_device_##name; \ + static int cmdline_device_##name##_setup(char *dev) \ + { \ + cmdline_device_##name = dev + 1; \ + return 0; \ + } \ + __setup(#name, cmdline_device_##name##_setup); \ + void mx23_init_##name(void) \ + { \ + if (!cmdline_device_##name || \ + !strcmp(cmdline_device_##name, #dev1)) \ + mx23_init_##dev1(); \ + else if (!strcmp(cmdline_device_##name, #dev2)) \ + mx23_init_##dev2(); \ + else \ + pr_err("Unknown %s assignment '%s'.\n", \ + #name, cmdline_device_##name); \ + } + +CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1) + #if defined(CONFIG_BATTERY_MXS) /* battery info data */ static ddi_bc_Cfg_t battery_data = { @@ -729,7 +825,7 @@ void __init mx23_init_spdif(void) mxs_add_device(pdev, 3); } #else -static inline mx23_init_spdif(void) +static inline void mx23_init_spdif(void) { } #endif @@ -835,6 +931,49 @@ static void mx23_init_persistent() } #endif +#if defined(CONFIG_FSL_OTP) +/* Building up eight registers's names of a bank */ +#define BANK(a, b, c, d, e, f, g, h) \ + {\ + ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \ + ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \ + } + +#define BANKS (4) +#define BANK_ITEMS (8) +static const char *bank_reg_desc[BANKS][BANK_ITEMS] = { + BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3), + BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP), + BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2), + BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7), +}; + +static struct fsl_otp_data otp_data = { + .fuse_name = (char **)bank_reg_desc, + .regulator_name = "vddio", + .fuse_num = BANKS * BANK_ITEMS, +}; +#undef BANK +#undef BANKS +#undef BANK_ITEMS + +static void mx23_init_otp(void) +{ + struct platform_device *pdev; + pdev = mxs_get_device("ocotp", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->dev.platform_data = &otp_data; + pdev->resource = NULL; + pdev->num_resources = 0; + mxs_add_device(pdev, 3); +} +#else +static void mx23_init_otp(void) +{ +} +#endif + int __init mx23_device_init(void) { mx23_init_dma(); @@ -848,12 +987,14 @@ int __init mx23_device_init(void) mx23_init_ts(); mx23_init_rtc(); mx23_init_dcp(); - mx23_init_mmc(); + mx23_init_ssp1(); + mx23_init_gpmi_nfc(); mx23_init_spdif(); mx23_init_lcdif(); mx23_init_pxp(); mx23_init_battery(); mx23_init_persistent(); + mx23_init_otp(); return 0; } diff --git a/arch/arm/mach-mx23/emi.S b/arch/arm/mach-mx23/emi.S index 5799ca23be8f..41e1ea6abe71 100644 --- a/arch/arm/mach-mx23/emi.S +++ b/arch/arm/mach-mx23/emi.S @@ -38,6 +38,8 @@ #define SCALING_DATA_NEW_FREQ_OFFSET 12 #define REGS_CLKCTRL_BASE MX23_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define HW_CLKCTRL_EMI_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) +#define HW_CLKCTRL_FRAC_SET_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC_SET) +#define HW_CLKCTRL_FRAC_CLR_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC_CLR) #define HW_CLKCTRL_FRAC_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) #define HW_EMI_CTRL_ADDR MX23_SOC_IO_ADDRESS(REGS_EMI_PHYS + HW_EMI_CTRL) #define HW_DRAM_CTL04_ADDR MX23_SOC_IO_ADDRESS(REGS_DRAM_PHYS + HW_DRAM_CTL04) @@ -72,53 +74,82 @@ ENTRY(mxs_ram_freq_scale) beq 1b nop + + @ RAM to clk from xtal + mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) + mov r1, #(1<<6) + str r1, [r0, #4] + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) +101: ldr r1, [r0] + tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 101b + + @ Gate ref_emi + mov r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0xFF000000) + + mov r1, #(BM_CLKCTRL_FRAC_CLKGATEEMI) + str r1, [r0] + + @ prepare for change cmp r5, #24 bgt 2f bl mx23_ram_24M_set_timings - b 100f + b 44f 2: cmp r5, #48 bgt 3f bl mx23_ram_48M_set_timings - b 100f + b 55f 3: cmp r5, #60 bgt 4f bl mx23_ram_60M_set_timings - b 100f + b 55f 4: cmp r5, #80 bgt 5f bl mx23_ram_80M_set_timings - b 100f + b 55f 5: cmp r5, #96 bgt 6f bl mx23_ram_96M_set_timings - b 100f + b 55f 6: cmp r5, #120 bgt 7f bl mx23_ram_120M_set_timings - b 100f + b 55f 7: cmp r5, #133 bgt 8f bl mx23_ram_133M_set_timings - b 100f + b 55f 8: bl mx23_ram_150M_set_timings -100: - @ RAM to clk from xtal - mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) - orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) - orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) - orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) - mov r1, #(1<<6) - str r1, [r0, #4] - mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) -101: ldr r1, [r0] - tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL - bne 101b +44: + + bl __mx23_emi_set_values_xtal + + @ resttore normal DRAM mode + ldr r0, __mx23_dram_ctl00 + ldr r1, [r0, #0x20] + bic r1, r1, #(1 << 8) + str r1, [r0, #0x20] + + @ wait for it to actually happen + ldr r0, __mx23_dram_emi00 +99: ldr r1, [r0, #0x10] + tst r1, #(1 << 1) + bne 99b + b 110f + +55: @When are using the DLL, reset the DRAM controller and DLL @start point logic (via DLL_SHIFT_RESET and DLL_RESET). @After changing clock dividers and loading @@ -136,14 +167,15 @@ ENTRY(mxs_ram_freq_scale) orr r1, r1, #BM_EMI_CTRL_DLL_RESET str r1, [r0] @write back values to HW_EMI_CTRL register. - bl __mx23_emi_set_values + bl __mx23_emi_set_values2 @ EMI back to PLL mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) - mov r1, #(1<<6) + mov r1, #(BM_CLKCTRL_CLKSEQ_BYPASS_EMI) + @clear bypass bit str r1, [r0, #8] @ Wait for BUSY_REF_EMI, to assure new clock dividers @@ -179,16 +211,6 @@ ENTRY(mxs_ram_freq_scale) bic r1, #BM_EMI_CTRL_DLL_RESET str r1, [r0] -@Wait for BUSY_REF_EMI, to assure new clock dividers are done transferring. -@(\todo is that necessary. we already did this above. - mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) -66: ldr r1, [r0] - tst r1, #BM_CLKCTRL_EMI_BUSY_REF_EMI - bne 66b - @ Wait for DLL locking. @ while(HW_DRAM_CTL04.B.DLLLOCKREG==0); @@ -200,7 +222,7 @@ ENTRY(mxs_ram_freq_scale) tst r1, #BM_DRAM_CTL04_DLLLOCKREG beq 77b - +88: @ resttore normal DRAM mode ldr r0, __mx23_dram_ctl00 ldr r1, [r0, #0x20] @@ -213,6 +235,7 @@ ENTRY(mxs_ram_freq_scale) tst r1, #(1 << 1) bne 102b +110: @ restore regs and return ldmfd sp!, {r1 - r9, lr} mov pc, lr diff --git a/arch/arm/mach-mx23/emi.inc b/arch/arm/mach-mx23/emi.inc index 194181f9f753..290d35ed2729 100644 --- a/arch/arm/mach-mx23/emi.inc +++ b/arch/arm/mach-mx23/emi.inc @@ -20,15 +20,38 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -__mx23_emi_set_values: + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + + +__mx23_emi_set_values_xtal: stmfd r9!, {r0 - r4, lr} + mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) -@ DDC_RESNCY is deprecated at mx23 -@ mov r3, #BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE +32: ldr r4, [r1] + tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 32b + b 4f + +__mx23_emi_set_values2: + + stmfd r9!, {r0 - r4, lr} + + mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) mov r0, #(HW_CLKCTRL_FRAC_ADDR & 0x000000FF) orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x0000FF00) @@ -36,17 +59,34 @@ __mx23_emi_set_values: orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0xFF000000) ldr r2, [r0] - and r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC - lsr r4, r4, #8 - /* new pll div > cur pll div? */ - cmp r4, r8 - bgt 1f + @clear EMIFRAC bits and store result in r4 bic r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC - orr r4, r4, r8, lsl #8 - str r4, [r0] - nop - nop - nop + + orr r4, r4, r8, lsl #BP_CLKCTRL_FRAC_EMIFRAC + str r4, [r0] + + @ ungate ref_emi + mov r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0xFF000000) + + mov r2, #(BM_CLKCTRL_FRAC_CLKGATEEMI) + str r2, [r0] + + + @ set the integer divider + ldr r2, [r1] + bic r2, r2, #BM_CLKCTRL_EMI_DIV_EMI + orr r2, r2, r7, lsl #BP_CLKCTRL_EMI_DIV_EMI + + str r2, [r1] + + @ wait for clock to stabilize +50: ldr r2, [r1] + tst r2, #BM_CLKCTRL_EMI_BUSY_REF_EMI + bne 50b + b 4f @ Change integer/fractional dividers. @@ -103,8 +143,6 @@ __mx23_emi_set_values: 31: ldr r4, [r1] tst r4, #BM_CLKCTRL_EMI_BUSY_REF_EMI bne 31b - tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL - bne 31b 4: ldmfd r9!, {r0 - r4, lr} mov pc, lr diff --git a/arch/arm/mach-mx23/include/mach/lcdif.h b/arch/arm/mach-mx23/include/mach/lcdif.h index f0ee0d5e5c1a..f12802087320 100644 --- a/arch/arm/mach-mx23/include/mach/lcdif.h +++ b/arch/arm/mach-mx23/include/mach/lcdif.h @@ -201,10 +201,10 @@ static inline void setup_dotclk_panel(u16 v_pulse_width, BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE | BM_LCDIF_CTRL_LCD_DATABUS_WIDTH, REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); - __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ - BM_LCDIF_CTRL_DATA_SELECT | /* data mode */ - BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ - BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3), /* 24 bit */ + __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) |/* 24 bit */ + BM_LCDIF_CTRL_DATA_SELECT |/* data mode */ + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) |/* no swap */ + BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3),/* 24 bit */ REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_VDCTRL0); @@ -275,4 +275,167 @@ static inline void release_dotclk_panel(void) __raw_writel(0, REGS_LCDIF_BASE + HW_LCDIF_VDCTRL3); } +static inline void setup_dvi_panel(u16 h_active, u16 v_active, + u16 h_blanking, u16 v_lines, + u16 v1_blank_start, u16 v1_blank_end, + u16 v2_blank_start, u16 v2_blank_end, + u16 f1_start, u16 f1_end, + u16 f2_start, u16 f2_end) +{ + u32 val; + /* 32bit packed format (RGB) */ + __raw_writel(BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + __raw_writel(BF_LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x7) | + BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_TRANSFER_COUNT); + val &= ~(BM_LCDIF_TRANSFER_COUNT_V_COUNT | + BM_LCDIF_TRANSFER_COUNT_H_COUNT); + val |= BF_LCDIF_TRANSFER_COUNT_H_COUNT(h_active) | + BF_LCDIF_TRANSFER_COUNT_V_COUNT(v_active); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_TRANSFER_COUNT); + + /* set lcdif to DVI mode */ + __raw_writel(BM_LCDIF_CTRL_DVI_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + __raw_writel(BM_LCDIF_CTRL_VSYNC_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + __raw_writel(BM_LCDIF_CTRL_DOTCLK_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + + __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + /* convert input RGB -> YCbCr */ + __raw_writel(BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + /* interlace odd and even fields */ + __raw_writel(BM_LCDIF_CTRL1_INTERLACE_FIELDS, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); + + __raw_writel(BM_LCDIF_CTRL_WORD_LENGTH | + BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE | + BM_LCDIF_CTRL_LCD_DATABUS_WIDTH, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ + BM_LCDIF_CTRL_DATA_SELECT | /* data mode */ + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ + BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(1), /* 8 bit */ + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + + /* LCDIF_DVI */ + /* set frame size */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL0); + val &= ~(BM_LCDIF_DVICTRL0_H_ACTIVE_CNT | + BM_LCDIF_DVICTRL0_H_BLANKING_CNT | + BM_LCDIF_DVICTRL0_V_LINES_CNT); + val |= BF_LCDIF_DVICTRL0_H_ACTIVE_CNT(1440) | + BF_LCDIF_DVICTRL0_H_BLANKING_CNT(h_blanking) | + BF_LCDIF_DVICTRL0_V_LINES_CNT(v_lines); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL0); + + /* set start/end of field-1 and start of field-2 */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL1); + val &= ~(BM_LCDIF_DVICTRL1_F1_START_LINE | + BM_LCDIF_DVICTRL1_F1_END_LINE | + BM_LCDIF_DVICTRL1_F2_START_LINE); + val |= BF_LCDIF_DVICTRL1_F1_START_LINE(f1_start) | + BF_LCDIF_DVICTRL1_F1_END_LINE(f1_end) | + BF_LCDIF_DVICTRL1_F2_START_LINE(f2_start); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL1); + + /* set first vertical blanking interval and end of filed-2 */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL2); + val &= ~(BM_LCDIF_DVICTRL2_F2_END_LINE | + BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE | + BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE); + val |= BF_LCDIF_DVICTRL2_F2_END_LINE(f2_end) | + BF_LCDIF_DVICTRL2_V1_BLANK_START_LINE(v1_blank_start) | + BF_LCDIF_DVICTRL2_V1_BLANK_END_LINE(v1_blank_end); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL2); + + /* set second vertical blanking interval */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL3); + val &= ~(BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE | + BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE); + val |= BF_LCDIF_DVICTRL3_V2_BLANK_START_LINE(v2_blank_start) | + BF_LCDIF_DVICTRL3_V2_BLANK_END_LINE(v2_blank_end); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL3); + + /* fill the rest area black color if the input frame + * is not 720 pixels/line + */ + if (h_active != 720) { + /* the input frame can't be less then (720-256) pixels/line */ + if (720 - h_active > 0xff) + h_active = 720 - 0xff; + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL4); + val &= ~(BM_LCDIF_DVICTRL4_H_FILL_CNT | + BM_LCDIF_DVICTRL4_Y_FILL_VALUE | + BM_LCDIF_DVICTRL4_CB_FILL_VALUE | + BM_LCDIF_DVICTRL4_CR_FILL_VALUE); + val |= BF_LCDIF_DVICTRL4_H_FILL_CNT(720 - h_active) | + BF_LCDIF_DVICTRL4_Y_FILL_VALUE(16) | + BF_LCDIF_DVICTRL4_CB_FILL_VALUE(128) | + BF_LCDIF_DVICTRL4_CR_FILL_VALUE(128); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL4); + } + + /* Color Space Conversion RGB->YCbCr */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF0); + val &= ~(BM_LCDIF_CSC_COEFF0_C0 | + BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER); + val |= BF_LCDIF_CSC_COEFF0_C0(0x41) | + BF_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(3); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF0); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF1); + val &= ~(BM_LCDIF_CSC_COEFF1_C1 | BM_LCDIF_CSC_COEFF1_C2); + val |= BF_LCDIF_CSC_COEFF1_C1(0x81) | + BF_LCDIF_CSC_COEFF1_C2(0x19); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF1); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF2); + val &= ~(BM_LCDIF_CSC_COEFF2_C3 | BM_LCDIF_CSC_COEFF2_C4); + val |= BF_LCDIF_CSC_COEFF2_C3(0x3DB) | + BF_LCDIF_CSC_COEFF2_C4(0x3B6); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF2); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF3); + val &= ~(BM_LCDIF_CSC_COEFF3_C5 | BM_LCDIF_CSC_COEFF3_C6); + val |= BF_LCDIF_CSC_COEFF3_C5(0x70) | + BF_LCDIF_CSC_COEFF3_C6(0x70); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF3); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF4); + val &= ~(BM_LCDIF_CSC_COEFF4_C7 | BM_LCDIF_CSC_COEFF4_C8); + val |= BF_LCDIF_CSC_COEFF4_C7(0x3A2) | BF_LCDIF_CSC_COEFF4_C8(0x3EE); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF4); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_OFFSET); + val &= ~(BM_LCDIF_CSC_OFFSET_CBCR_OFFSET + | BM_LCDIF_CSC_OFFSET_Y_OFFSET); + val |= BF_LCDIF_CSC_OFFSET_CBCR_OFFSET(0x80) | + BF_LCDIF_CSC_OFFSET_Y_OFFSET(0x10); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_OFFSET); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_LIMIT); + val &= ~(BM_LCDIF_CSC_LIMIT_CBCR_MIN | + BM_LCDIF_CSC_LIMIT_CBCR_MAX | + BM_LCDIF_CSC_LIMIT_Y_MIN | + BM_LCDIF_CSC_LIMIT_Y_MAX); + val |= BF_LCDIF_CSC_LIMIT_CBCR_MIN(16) | + BF_LCDIF_CSC_LIMIT_CBCR_MAX(240) | + BF_LCDIF_CSC_LIMIT_Y_MIN(16) | + BF_LCDIF_CSC_LIMIT_Y_MAX(235); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_LIMIT); +} + +static inline void release_dvi_panel(void) +{ + __raw_writel(BM_LCDIF_CTRL_DVI_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); +} #endif /* _ARCH_ARM_LCDIF_H */ diff --git a/arch/arm/mach-mx23/include/mach/mx23.h b/arch/arm/mach-mx23/include/mach/mx23.h index 09269524a4f0..6e1d2aa7106e 100644 --- a/arch/arm/mach-mx23/include/mach/mx23.h +++ b/arch/arm/mach-mx23/include/mach/mx23.h @@ -50,6 +50,7 @@ #define OCOTP_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x02C000) #define AXI_AHB0_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x02E000) #define LCDIF_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x030000) +#define TVENC_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x038000) #define CLKCTRL_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x040000) #define SAIF0_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x042000) #define POWER_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x044000) @@ -72,12 +73,17 @@ #define MX23_SOC_IO_ADDRESS(x) \ ((x) - MX23_SOC_IO_PHYS_BASE + MX23_SOC_IO_VIRT_BASE) +#ifdef __ASSEMBLER__ +#define IO_ADDRESS(x) \ + MX23_SOC_IO_ADDRESS(x) +#else #define IO_ADDRESS(x) \ (void __force __iomem *) \ (((x) >= (unsigned long)MX23_SOC_IO_PHYS_BASE) && \ ((x) < (unsigned long)MX23_SOC_IO_PHYS_BASE + \ MX23_SOC_IO_AREA_SIZE) ? \ MX23_SOC_IO_ADDRESS(x) : 0xDEADBEEF) +#endif #ifdef CONFIG_MXS_EARLY_CONSOLE #define MXS_DEBUG_CONSOLE_PHYS DUART_PHYS_ADDR diff --git a/arch/arm/mach-mx23/mx23_pins.h b/arch/arm/mach-mx23/mx23_pins.h index 4659315e29f6..9811bfdd0cad 100644 --- a/arch/arm/mach-mx23/mx23_pins.h +++ b/arch/arm/mach-mx23/mx23_pins.h @@ -47,7 +47,7 @@ #define PINID_GPMI_D15 MXS_PIN_ENCODE(0, 15) #define PINID_GPMI_CLE MXS_PIN_ENCODE(0, 16) #define PINID_GPMI_ALE MXS_PIN_ENCODE(0, 17) -#define PINID_GMPI_CE2N MXS_PIN_ENCODE(0, 18) +#define PINID_GPMI_CE2N MXS_PIN_ENCODE(0, 18) #define PINID_GPMI_RDY0 MXS_PIN_ENCODE(0, 19) #define PINID_GPMI_RDY1 MXS_PIN_ENCODE(0, 20) #define PINID_GPMI_RDY2 MXS_PIN_ENCODE(0, 21) diff --git a/arch/arm/mach-mx23/mx23evk.c b/arch/arm/mach-mx23/mx23evk.c index 53f958779c1c..6ce1583e28eb 100644 --- a/arch/arm/mach-mx23/mx23evk.c +++ b/arch/arm/mach-mx23/mx23evk.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include "device.h" #include "mx23evk.h" @@ -58,6 +60,28 @@ static void i2c_device_init(void) i2c_register_board_info(0, &mma7450_i2c_device, 1); } +static struct mxs_spi_platform_data enc_data = { + .hw_pin_init = mxs_spi_enc_pin_init, + .hw_pin_release = mxs_spi_enc_pin_release, +}; +static struct spi_board_info spi_board_info[] __initdata = { +#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE) + { + .modalias = "enc28j60", + .max_speed_hz = 6 * 1000 * 1000, + .bus_num = 1, + .chip_select = 0, + .platform_data = &enc_data, + }, +#endif +}; + +static void spi_device_init(void) +{ + spi_board_info[0].irq = gpio_to_irq(MXS_PIN_TO_GPIO(PINID_SSP1_DATA1)); + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +} + static void __init fixup_board(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { @@ -80,11 +104,23 @@ static void __init mx23evk_init_adc(void) } #endif +#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR) +int get_evk_board_version() +{ + int boardid; + boardid = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUSTCAP); + boardid &= 0x30000000; + boardid = boardid >> 28; + + return boardid; +} +EXPORT_SYMBOL_GPL(get_evk_board_version); static void __init mx23evk_device_init(void) { /* Add mx23evk special code */ i2c_device_init(); + spi_device_init(); mx23evk_init_adc(); } @@ -94,7 +130,12 @@ static void __init mx23evk_init_machine(void) mx23_pinctrl_init(); /* Init iram allocate */ +#ifdef CONFIG_VECTORS_PHY_ADDR + /* reserve the first page for irq vectors table*/ + iram_init(MX23_OCRAM_PHBASE + PAGE_SIZE, MX23_OCRAM_SIZE - PAGE_SIZE); +#else iram_init(MX23_OCRAM_PHBASE, MX23_OCRAM_SIZE); +#endif mx23_gpio_init(); mx23evk_pins_init(); diff --git a/arch/arm/mach-mx23/mx23evk.h b/arch/arm/mach-mx23/mx23evk.h index afe7bcf4ffe1..ea2ab4def477 100644 --- a/arch/arm/mach-mx23/mx23evk.h +++ b/arch/arm/mach-mx23/mx23evk.h @@ -22,5 +22,11 @@ extern void __init mx23evk_pins_init(void); extern void mx23evk_mma7450_pin_init(void); extern int mx23evk_mma7450_pin_release(void); +extern int mxs_spi_enc_pin_init(void); +extern int mxs_spi_enc_pin_release(void); +extern int mxs_mmc_get_wp_mmc0(void); +extern int mxs_mmc_hw_init_mmc0(void); +extern void mxs_mmc_hw_release_mmc0(void); +extern void mxs_mmc_cmd_pullup_mmc0(int enable); #endif /* __ASM_ARM_MACH_MX23EVK_H */ diff --git a/arch/arm/mach-mx23/mx23evk_pins.c b/arch/arm/mach-mx23/mx23evk_pins.c index 5e60a2b1e387..cdf86cfbea63 100644 --- a/arch/arm/mach-mx23/mx23evk_pins.c +++ b/arch/arm/mach-mx23/mx23evk_pins.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -60,6 +61,28 @@ static struct pin_desc mx23evk_fixed_pins[] = { }, #endif +#ifdef CONFIG_MXS_AUART2_DEVICE_ENABLE + { + .name = "AUART2.RX", + .id = PINID_GPMI_D14, + .fun = PIN_FUN2, + }, + { + .name = "AUART2.TX", + .id = PINID_GPMI_D15, + .fun = PIN_FUN2, + }, + { + .name = "AUART2.CTS", + .id = PINID_ROTARYB, + .fun = PIN_FUN2, + }, + { + .name = "AUART2.RTS", + .id = PINID_ROTARYA, + .fun = PIN_FUN2, + }, +#endif #if defined(CONFIG_I2C_MXS) || \ defined(CONFIG_I2C_MXS_MODULE) { @@ -321,79 +344,6 @@ static struct pin_desc mx23evk_fixed_pins[] = { .drive = 1, }, #endif -#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) - /* Configurations of SSP0 SD/MMC port pins */ - { - .name = "SSP1_DATA0", - .id = PINID_SSP1_DATA0, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DATA1", - .id = PINID_SSP1_DATA1, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DATA2", - .id = PINID_SSP1_DATA2, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DATA3", - .id = PINID_SSP1_DATA3, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_CMD", - .id = PINID_SSP1_CMD, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DETECT", - .id = PINID_SSP1_DETECT, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 0, - .drive = 1, - .pull = 0, - }, - { - .name = "SSP1_SCK", - .id = PINID_SSP1_SCK, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 0, - .drive = 1, - .pull = 0, - }, -#endif #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) { @@ -510,8 +460,323 @@ static struct pin_desc mx23evk_fixed_pins[] = { .pull = 1, }, #endif + +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) + { + .name = "GPMI D0", + .id = PINID_GPMI_D00, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D1", + .id = PINID_GPMI_D01, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D2", + .id = PINID_GPMI_D02, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D3", + .id = PINID_GPMI_D03, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D4", + .id = PINID_GPMI_D04, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D5", + .id = PINID_GPMI_D05, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D6", + .id = PINID_GPMI_D06, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D7", + .id = PINID_GPMI_D07, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI CLE", + .id = PINID_GPMI_CLE, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI ALE", + .id = PINID_GPMI_ALE, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI WPN-", + .id = PINID_GPMI_WPN, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI WR-", + .id = PINID_GPMI_WRN, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI RD-", + .id = PINID_GPMI_RDN, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI RDY0", + .id = PINID_GPMI_RDY0, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI RDY1", + .id = PINID_GPMI_RDY1, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI CE0-", + .id = PINID_GPMI_CE0N, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI CE1-", + .id = PINID_GPMI_CE1N, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, +#endif + }; +#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) +static struct pin_desc mx23evk_mmc_pins[] = { + /* Configurations of SSP0 SD/MMC port pins */ + { + .name = "SSP1_DATA0", + .id = PINID_SSP1_DATA0, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DATA1", + .id = PINID_SSP1_DATA1, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DATA2", + .id = PINID_SSP1_DATA2, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DATA3", + .id = PINID_SSP1_DATA3, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_CMD", + .id = PINID_SSP1_CMD, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DETECT", + .id = PINID_SSP1_DETECT, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = 1, + .pull = 0, + }, + { + .name = "SSP1_SCK", + .id = PINID_SSP1_SCK, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = 1, + .pull = 0, + }, +}; +#endif + +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) +static struct pin_desc mx23evk_spi_pins[] = { + { + .name = "SSP1_DATA0", + .id = PINID_SSP1_DATA0, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .drive = 1, + }, + { + .name = "SSP1_DATA3", + .id = PINID_SSP1_DATA3, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .drive = 1, + }, + { + .name = "SSP1_CMD", + .id = PINID_SSP1_CMD, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .drive = 1, + }, + { + .name = "SSP1_SCK", + .id = PINID_SSP1_SCK, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .drive = 1, + }, +}; +#endif + + +static void mxs_request_pins(struct pin_desc *pins, int nr) +{ + int i; + struct pin_desc *pin; + + /* configure the pins */ + for (i = 0; i < nr; i++) { + pin = &pins[i]; + if (pin->fun == PIN_GPIO) + gpio_request(MXS_PIN_TO_GPIO(pin->id), pin->name); + else + mxs_request_pin(pin->id, pin->fun, pin->name); + if (pin->drive) { + mxs_set_strength(pin->id, pin->strength, pin->name); + mxs_set_voltage(pin->id, pin->voltage, pin->name); + } + if (pin->pull) + mxs_set_pullup(pin->id, pin->pullup, pin->name); + if (pin->fun == PIN_GPIO) { + if (pin->output) + gpio_direction_output(MXS_PIN_TO_GPIO(pin->id), + pin->data); + else + gpio_direction_input(MXS_PIN_TO_GPIO(pin->id)); + } + } +} + +static void mxs_release_pins(struct pin_desc *pins, int nr) +{ + int i; + struct pin_desc *pin; + + /* release the pins */ + for (i = 0; i < nr; i++) { + pin = &pins[i]; + if (pin->fun == PIN_GPIO) + gpio_free(MXS_PIN_TO_GPIO(pin->id)); + else + mxs_release_pin(pin->id, pin->name); + } +} + #if defined(CONFIG_MXC_MMA7450) || defined(CONFIG_MXC_MMA7450_MODULE) int mx23evk_mma7450_pin_init(void) { @@ -537,6 +802,116 @@ int mx23evk_mma7450_pin_release(void) } #endif +#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) +#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3) +#define MMC0_WP MXS_PIN_TO_GPIO(PINID_PWM4) + +int mxs_mmc_get_wp_mmc0(void) +{ + return gpio_get_value(MMC0_WP); +} + +int mxs_mmc_hw_init_mmc0(void) +{ + int ret = 0; + + mxs_request_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins)); + + /* Configure write protect GPIO pin */ + ret = gpio_request(MMC0_WP, "mmc0_wp"); + if (ret) { + pr_err("wp\n"); + goto out_wp; + } + gpio_set_value(MMC0_WP, 0); + gpio_direction_input(MMC0_WP); + + /* Configure POWER pin as gpio to drive power to MMC slot */ + ret = gpio_request(MMC0_POWER, "mmc0_power"); + if (ret) { + pr_err("power\n"); + goto out_power; + } + gpio_direction_output(MMC0_POWER, 0); + mdelay(100); + + return 0; + +out_power: + gpio_free(MMC0_WP); +out_wp: + mxs_release_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins)); + return ret; +} + +void mxs_mmc_hw_release_mmc0(void) +{ + gpio_free(MMC0_POWER); + gpio_free(MMC0_WP); + + mxs_release_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins)); +} + +void mxs_mmc_cmd_pullup_mmc0(int enable) +{ + mxs_set_pullup(PINID_SSP1_CMD, enable, "mmc0_cmd"); +} +#else +int mxs_mmc_get_wp_mmc0(void) +{ + return 0; +} +int mxs_mmc_hw_init_mmc0(void) +{ + return 0; +} + +void mxs_mmc_hw_release_mmc0(void) +{ +} + +void mxs_mmc_cmd_pullup_mmc0(int enable) +{ +} +#endif + +#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE) +int mxs_spi_enc_pin_init(void) +{ + unsigned gpio = MXS_PIN_TO_GPIO(PINID_SSP1_DATA1); + + mxs_request_pins(mx23evk_spi_pins, ARRAY_SIZE(mx23evk_spi_pins)); + + gpio_request(gpio, "ENC28J60_INTR"); + gpio_direction_input(gpio); + set_irq_type(gpio_to_irq(gpio), IRQ_TYPE_EDGE_FALLING); + + return 0; +} +int mxs_spi_enc_pin_release(void) +{ + unsigned gpio = MXS_PIN_TO_GPIO(PINID_SSP1_DATA1); + + + gpio_free(gpio); + set_irq_type(gpio_to_irq(gpio), IRQ_TYPE_NONE); + + /* release the pins */ + mxs_release_pins(mx23evk_spi_pins, ARRAY_SIZE(mx23evk_spi_pins)); + + return 0; +} +#else +int mxs_spi_enc_pin_init(void) +{ + return 0; +} +int mxs_spi_enc_pin_release(void) +{ + return 0; +} +#endif + #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) int mx23evk_enet_gpio_init(void) { @@ -560,26 +935,5 @@ int mx23evk_enet_gpio_init(void) void __init mx23evk_pins_init(void) { - int i; - struct pin_desc *pin; - for (i = 0; i < ARRAY_SIZE(mx23evk_fixed_pins); i++) { - pin = &mx23evk_fixed_pins[i]; - if (pin->fun == PIN_GPIO) - gpio_request(MXS_PIN_TO_GPIO(pin->id), pin->name); - else - mxs_request_pin(pin->id, pin->fun, pin->name); - if (pin->drive) { - mxs_set_strength(pin->id, pin->strength, pin->name); - mxs_set_voltage(pin->id, pin->voltage, pin->name); - } - if (pin->pull) - mxs_set_pullup(pin->id, pin->pullup, pin->name); - if (pin->fun == PIN_GPIO) { - if (pin->output) - gpio_direction_output(MXS_PIN_TO_GPIO(pin->id), - pin->data); - else - gpio_direction_input(MXS_PIN_TO_GPIO(pin->id)); - } - } + mxs_request_pins(mx23evk_fixed_pins, ARRAY_SIZE(mx23evk_fixed_pins)); } diff --git a/arch/arm/mach-mx23/pm.c b/arch/arm/mach-mx23/pm.c index c44a81f94b5e..0538326f441c 100644 --- a/arch/arm/mach-mx23/pm.c +++ b/arch/arm/mach-mx23/pm.c @@ -280,6 +280,7 @@ static inline void do_standby(void) } local_fiq_disable(); + mxs_nomatch_suspend_timer(); __raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH, REGS_POWER_BASE + HW_POWER_CTRL_SET); @@ -502,7 +503,6 @@ static suspend_state_t saved_state; static int mx23_pm_begin(suspend_state_t state) { - mxs_nomatch_suspend_timer(); saved_state = state; return 0; } diff --git a/arch/arm/mach-mx23/usb_dr.c b/arch/arm/mach-mx23/usb_dr.c index 13f9a296909c..4c702ffcd07c 100644 --- a/arch/arm/mach-mx23/usb_dr.c +++ b/arch/arm/mach-mx23/usb_dr.c @@ -27,7 +27,7 @@ #include "usb.h" #include "mx23_pins.h" -#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_GMPI_CE2N) +#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_GPMI_CE2N) #define USB_ID_PIN MXS_PIN_TO_GPIO(PINID_ROTARYA) static void usb_host_phy_resume(struct fsl_usb2_platform_data *plat) @@ -64,7 +64,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { }; /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -84,6 +84,28 @@ static struct resource otg_resources[] = { }, }; +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)USBCTRL_PHYS_ADDR, + .end = (u32)(USBCTRL_PHYS_ADDR + 0x1ff), + .flags = IORESOURCE_MEM, + }, + + [1] = { + .start = IRQ_USB_CTRL, + .flags = IORESOURCE_IRQ, + }, + + [2] = { + .start = IRQ_USB_WAKEUP, + .flags = IORESOURCE_IRQ, + }, +}; + + static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) { @@ -101,8 +123,8 @@ static struct platform_device dr_udc_device = { .dma_mask = &dr_udc_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; static u64 dr_otg_dmamask = ~(u32) 0; @@ -167,5 +189,5 @@ void fsl_phy_set_power(struct fsl_xcvr_ops *this, #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW fs_initcall(usb_dr_init); #else - module_init(usb_dr_init); + subsys_initcall(usb_dr_init); #endif -- cgit v1.2.3