summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx23
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mx23')
-rw-r--r--arch/arm/mach-mx23/Kconfig16
-rw-r--r--arch/arm/mach-mx23/Makefile1
-rw-r--r--arch/arm/mach-mx23/bus_freq.c82
-rw-r--r--arch/arm/mach-mx23/clock.c962
-rw-r--r--arch/arm/mach-mx23/device.c237
-rw-r--r--arch/arm/mach-mx23/emi.S93
-rw-r--r--arch/arm/mach-mx23/emi.inc68
-rw-r--r--arch/arm/mach-mx23/include/mach/lcdif.h171
-rw-r--r--arch/arm/mach-mx23/include/mach/mx23.h6
-rw-r--r--arch/arm/mach-mx23/mx23_pins.h2
-rw-r--r--arch/arm/mach-mx23/mx23evk.c41
-rw-r--r--arch/arm/mach-mx23/mx23evk.h6
-rw-r--r--arch/arm/mach-mx23/mx23evk_pins.c544
-rw-r--r--arch/arm/mach-mx23/pm.c2
-rw-r--r--arch/arm/mach-mx23/usb_dr.c32
15 files changed, 1775 insertions, 488 deletions
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 <linux/kernel.h>
#include <linux/init.h>
+#include <linux/err.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/iram_alloc.h>
#include <linux/platform_device.h>
#include <mach/clock.h>
@@ -29,17 +31,130 @@
#include "regs-clkctrl.h"
#include "regs-digctl.h"
+#include <mach/regs-rtc.h>
#include <mach/mx23.h>
#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,21 +1394,34 @@ 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,
},
@@ -978,8 +1450,12 @@ static struct clk_lookup onchip_clocks[] = {
.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 <linux/mmc/host.h>
#include <linux/phy.h>
#include <linux/fec.h>
+#include <linux/gpmi-nfc.h>
#include <asm/mach/map.h>
@@ -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 <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -30,6 +31,7 @@
#include <mach/hardware.h>
#include <mach/device.h>
#include <mach/pinctrl.h>
+#include <mach/regs-ocotp.h>
#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 <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <mach/pinctrl.h>
@@ -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