summaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap1/io.c1
-rw-r--r--arch/arm/plat-omap/Kconfig13
-rw-r--r--arch/arm/plat-omap/clock.c369
-rw-r--r--arch/arm/plat-omap/clock.h10
-rw-r--r--arch/arm/plat-omap/dma.c44
-rw-r--r--arch/arm/plat-omap/mcbsp.c97
-rw-r--r--arch/arm/plat-omap/mux.c17
-rw-r--r--arch/arm/plat-omap/usb.c2
8 files changed, 461 insertions, 92 deletions
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index f1258c1f3a9..207df0fe934 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -17,6 +17,7 @@
#include <asm/io.h>
#include <asm/arch/tc.h>
+extern int clk_init(void);
extern void omap_check_revision(void);
/*
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index a72fe55b513..345365852f8 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -19,6 +19,19 @@ endchoice
comment "OMAP Feature Selections"
+config OMAP_RESET_CLOCKS
+ bool "Reset unused clocks during boot"
+ depends on ARCH_OMAP
+ default n
+ help
+ Say Y if you want to reset unused clocks during boot.
+ This option saves power, but assumes all drivers are
+ using the clock framework. Broken drivers that do not
+ yet use clock framework may not work with this option.
+ If you are booting from another operating system, you
+ probably do not want this option enabled until your
+ device drivers work properly.
+
config OMAP_MUX
bool "OMAP multiplexing support"
depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 155157f309e..59d91b3262b 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/err.h>
+#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/hardware/clock.h>
#include <asm/arch/board.h>
@@ -25,6 +26,8 @@ static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
static DEFINE_SPINLOCK(clockfw_lock);
static void propagate_rate(struct clk * clk);
+/* UART clock function */
+static int set_uart_rate(struct clk * clk, unsigned long rate);
/* External clock (MCLK & BCLK) functions */
static int set_ext_clk_rate(struct clk * clk, unsigned long rate);
static long round_ext_clk_rate(struct clk * clk, unsigned long rate);
@@ -34,7 +37,7 @@ static int select_table_rate(struct clk * clk, unsigned long rate);
static long round_to_table_rate(struct clk * clk, unsigned long rate);
void clk_setdpll(__u16, __u16);
-struct mpu_rate rate_table[] = {
+static struct mpu_rate rate_table[] = {
/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
* armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
*/
@@ -48,7 +51,7 @@ struct mpu_rate rate_table[] = {
{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
{ 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
- { 48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
+ { 48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */
{ 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
#endif
#if defined(CONFIG_OMAP_ARM_182MHZ)
@@ -58,7 +61,7 @@ struct mpu_rate rate_table[] = {
{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
#endif
#if defined(CONFIG_OMAP_ARM_150MHZ)
- { 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+ { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
#endif
#if defined(CONFIG_OMAP_ARM_120MHZ)
{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
@@ -76,19 +79,11 @@ struct mpu_rate rate_table[] = {
};
-static void ckctl_recalc(struct clk * clk)
-{
- int dsor;
-
- /* Calculate divisor encoded as 2-bit exponent */
- dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
- if (unlikely(clk->rate == clk->parent->rate / dsor))
- return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
-
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
-}
+static void ckctl_recalc(struct clk * clk);
+int __clk_enable(struct clk *clk);
+void __clk_disable(struct clk *clk);
+void __clk_unuse(struct clk *clk);
+int __clk_use(struct clk *clk);
static void followparent_recalc(struct clk * clk)
@@ -102,6 +97,14 @@ static void watchdog_recalc(struct clk * clk)
clk->rate = clk->parent->rate / 14;
}
+static void uart_recalc(struct clk * clk)
+{
+ unsigned int val = omap_readl(clk->enable_reg);
+ if (val & clk->enable_bit)
+ clk->rate = 48000000;
+ else
+ clk->rate = 12000000;
+}
static struct clk ck_ref = {
.name = "ck_ref",
@@ -138,7 +141,7 @@ static struct clk arm_ck = {
static struct clk armper_ck = {
.name = "armper_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ .flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
RATE_CKCTL,
.enable_reg = ARM_IDLECT2,
.enable_bit = EN_PERCK,
@@ -185,7 +188,7 @@ static struct clk armwdt_ck = {
static struct clk arminth_ck16xx = {
.name = "arminth_ck",
.parent = &arm_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
/* Note: On 16xx the frequency can be divided by 2 by programming
* ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
@@ -214,6 +217,38 @@ static struct clk dspmmu_ck = {
.recalc = &ckctl_recalc,
};
+static struct clk dspper_ck = {
+ .name = "dspper_ck",
+ .parent = &ck_dpll1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_PERCK,
+ .rate_offset = CKCTL_PERDIV_OFFSET,
+ .recalc = &followparent_recalc,
+ //.recalc = &ckctl_recalc,
+};
+
+static struct clk dspxor_ck = {
+ .name = "dspxor_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_XORPCK,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk dsptim_ck = {
+ .name = "dsptim_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_DSPTIMCK,
+ .recalc = &followparent_recalc,
+};
+
static struct clk tc_ck = {
.name = "tc_ck",
.parent = &ck_dpll1,
@@ -226,7 +261,7 @@ static struct clk tc_ck = {
static struct clk arminth_ck1510 = {
.name = "arminth_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510,
+ .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
/* Note: On 1510 the frequency follows TC_CK
*
@@ -237,7 +272,7 @@ static struct clk arminth_ck1510 = {
static struct clk tipb_ck = {
.name = "tibp_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510,
+ .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
@@ -271,14 +306,15 @@ static struct clk tc2_ck = {
static struct clk dma_ck = {
.name = "dma_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
static struct clk dma_lcdfree_ck = {
.name = "dma_lcdfree_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
@@ -303,14 +339,14 @@ static struct clk lb_ck = {
static struct clk rhea1_ck = {
.name = "rhea1_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
static struct clk rhea2_ck = {
.name = "rhea2_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
@@ -325,43 +361,55 @@ static struct clk lcd_ck = {
.recalc = &ckctl_recalc,
};
-static struct clk uart1_ck = {
+static struct clk uart1_1510 = {
+ .name = "uart1_ck",
+ /* Direct from ULPD, no parent */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+ .enable_reg = MOD_CONF_CTRL_0,
+ .enable_bit = 29, /* Chooses between 12MHz and 48MHz */
+ .set_rate = &set_uart_rate,
+ .recalc = &uart_recalc,
+};
+
+static struct clk uart1_16xx = {
.name = "uart1_ck",
/* Direct from ULPD, no parent */
.rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = MOD_CONF_CTRL_0,
.enable_bit = 29,
- /* (Only on 1510)
- * The "enable bit" actually chooses between 48MHz and 12MHz.
- */
};
static struct clk uart2_ck = {
.name = "uart2_ck",
/* Direct from ULPD, no parent */
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
.enable_reg = MOD_CONF_CTRL_0,
- .enable_bit = 30,
- /* (for both 1510 and 16xx)
- * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
- */
+ .enable_bit = 30, /* Chooses between 12MHz and 48MHz */
+ .set_rate = &set_uart_rate,
+ .recalc = &uart_recalc,
};
-static struct clk uart3_ck = {
+static struct clk uart3_1510 = {
+ .name = "uart3_ck",
+ /* Direct from ULPD, no parent */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+ .enable_reg = MOD_CONF_CTRL_0,
+ .enable_bit = 31, /* Chooses between 12MHz and 48MHz */
+ .set_rate = &set_uart_rate,
+ .recalc = &uart_recalc,
+};
+
+static struct clk uart3_16xx = {
.name = "uart3_ck",
/* Direct from ULPD, no parent */
.rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = MOD_CONF_CTRL_0,
.enable_bit = 31,
- /* (Only on 1510)
- * The "enable bit" actually chooses between 48MHz and 12MHz.
- */
};
static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */
@@ -480,6 +528,9 @@ static struct clk * onchip_clks[] = {
/* CK_GEN2 clocks */
&dsp_ck,
&dspmmu_ck,
+ &dspper_ck,
+ &dspxor_ck,
+ &dsptim_ck,
/* CK_GEN3 clocks */
&tc_ck,
&tipb_ck,
@@ -494,9 +545,11 @@ static struct clk * onchip_clks[] = {
&rhea2_ck,
&lcd_ck,
/* ULPD clocks */
- &uart1_ck,
+ &uart1_1510,
+ &uart1_16xx,
&uart2_ck,
- &uart3_ck,
+ &uart3_1510,
+ &uart3_16xx,
&usb_clko,
&usb_hhc_ck1510, &usb_hhc_ck16xx,
&mclk_1510, &mclk_16xx,
@@ -547,14 +600,34 @@ int __clk_enable(struct clk *clk)
return 0;
}
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_use(&api_ck);
+ }
+
if (clk->flags & ENABLE_REG_32BIT) {
- regval32 = omap_readl(clk->enable_reg);
- regval32 |= (1 << clk->enable_bit);
- omap_writel(regval32, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
+ } else {
+ regval32 = omap_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ omap_writel(regval32, clk->enable_reg);
+ }
} else {
- regval16 = omap_readw(clk->enable_reg);
- regval16 |= (1 << clk->enable_bit);
- omap_writew(regval16, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 |= (1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
+ } else {
+ regval16 = omap_readw(clk->enable_reg);
+ regval16 |= (1 << clk->enable_bit);
+ omap_writew(regval16, clk->enable_reg);
+ }
+ }
+
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_unuse(&api_ck);
}
return 0;
@@ -569,14 +642,34 @@ void __clk_disable(struct clk *clk)
if (clk->enable_reg == 0)
return;
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_use(&api_ck);
+ }
+
if (clk->flags & ENABLE_REG_32BIT) {
- regval32 = omap_readl(clk->enable_reg);
- regval32 &= ~(1 << clk->enable_bit);
- omap_writel(regval32, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
+ } else {
+ regval32 = omap_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ omap_writel(regval32, clk->enable_reg);
+ }
} else {
- regval16 = omap_readw(clk->enable_reg);
- regval16 &= ~(1 << clk->enable_bit);
- omap_writew(regval16, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 &= ~(1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
+ } else {
+ regval16 = omap_readw(clk->enable_reg);
+ regval16 &= ~(1 << clk->enable_bit);
+ omap_writew(regval16, clk->enable_reg);
+ }
+ }
+
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_unuse(&api_ck);
}
}
@@ -766,6 +859,33 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate)
return dsor_exp;
}
+
+static void ckctl_recalc(struct clk * clk)
+{
+ int dsor;
+
+ /* Calculate divisor encoded as 2-bit exponent */
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ /* The clock control bits are in DSP domain,
+ * so api_ck is needed for access.
+ * Note that DSP_CKCTL virt addr = phys addr, so
+ * we must use __raw_readw() instead of omap_readw().
+ */
+ __clk_use(&api_ck);
+ dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
+ __clk_unuse(&api_ck);
+ } else {
+ dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+ }
+ if (unlikely(clk->rate == clk->parent->rate / dsor))
+ return; /* No change, quick exit */
+ clk->rate = clk->parent->rate / dsor;
+
+ if (unlikely(clk->flags & RATE_PROPAGATES))
+ propagate_rate(clk);
+}
+
+
long clk_round_rate(struct clk *clk, unsigned long rate)
{
int dsor_exp;
@@ -826,6 +946,9 @@ static int select_table_rate(struct clk * clk, unsigned long rate)
if (!ptr->rate)
return -EINVAL;
+ if (!ptr->rate)
+ return -EINVAL;
+
if (unlikely(ck_dpll1.rate == 0)) {
omap_writew(ptr->dpllctl_val, DPLL_CTL);
ck_dpll1.rate = ptr->pll_rate;
@@ -921,6 +1044,23 @@ static unsigned calc_ext_dsor(unsigned long rate)
return dsor;
}
+/* Only needed on 1510 */
+static int set_uart_rate(struct clk * clk, unsigned long rate)
+{
+ unsigned int val;
+
+ val = omap_readl(clk->enable_reg);
+ if (rate == 12000000)
+ val &= ~(1 << clk->enable_bit);
+ else if (rate == 48000000)
+ val |= (1 << clk->enable_bit);
+ else
+ return -EINVAL;
+ omap_writel(val, clk->enable_reg);
+ clk->rate = rate;
+
+ return 0;
+}
static int set_ext_clk_rate(struct clk * clk, unsigned long rate)
{
@@ -985,7 +1125,18 @@ void clk_unregister(struct clk *clk)
}
EXPORT_SYMBOL(clk_unregister);
-
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+/*
+ * Resets some clocks that may be left on from bootloader,
+ * but leaves serial clocks on. See also omap_late_clk_reset().
+ */
+static inline void omap_early_clk_reset(void)
+{
+ //omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+}
+#else
+#define omap_early_clk_reset() {}
+#endif
int __init clk_init(void)
{
@@ -993,6 +1144,8 @@ int __init clk_init(void)
const struct omap_clock_config *info;
int crystal_type = 0; /* Default 12 MHz */
+ omap_early_clk_reset();
+
for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
clk_register(*clkp);
@@ -1023,9 +1176,42 @@ int __init clk_init(void)
ck_ref.rate = 19200000;
#endif
+ printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+ omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+ omap_readw(ARM_CKCTL));
+
/* We want to be in syncronous scalable mode */
omap_writew(0x1000, ARM_SYSST);
+#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
+ /* Use values set by bootloader. Determine PLL rate and recalculate
+ * dependent clocks as if kernel had changed PLL or divisors.
+ */
+ {
+ unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+ ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+ if (pll_ctl_val & 0x10) {
+ /* PLL enabled, apply multiplier and divisor */
+ if (pll_ctl_val & 0xf80)
+ ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+ ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+ } else {
+ /* PLL disabled, apply bypass divisor */
+ switch (pll_ctl_val & 0xc) {
+ case 0:
+ break;
+ case 0x4:
+ ck_dpll1.rate /= 2;
+ break;
+ default:
+ ck_dpll1.rate /= 4;
+ break;
+ }
+ }
+ }
+ propagate_rate(&ck_dpll1);
+#else
/* Find the highest supported frequency and enable it */
if (select_table_rate(&virtual_ck_mpu, ~0)) {
printk(KERN_ERR "System frequencies not set. Check your config.\n");
@@ -1034,12 +1220,13 @@ int __init clk_init(void)
omap_writew(0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
propagate_rate(&ck_dpll1);
- printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
- ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
}
-
+#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
propagate_rate(&ck_ref);
+ printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+ ck_dpll1.rate, arm_ck.rate);
#ifdef CONFIG_MACH_OMAP_PERSEUS2
/* Select slicer output as OMAP input clock */
@@ -1074,3 +1261,63 @@ int __init clk_init(void)
return 0;
}
+
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+
+static int __init omap_late_clk_reset(void)
+{
+ /* Turn off all unused clocks */
+ struct clk *p;
+ __u32 regval32;
+
+ omap_writew(0, SOFT_REQ_REG);
+ omap_writew(0, SOFT_REQ_REG2);
+
+ list_for_each_entry(p, &clocks, node) {
+ if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
+ p->enable_reg == 0)
+ continue;
+
+ /* Assume no DSP clocks have been activated by bootloader */
+ if (p->flags & DSP_DOMAIN_CLOCK)
+ continue;
+
+ /* Is the clock already disabled? */
+ if (p->flags & ENABLE_REG_32BIT) {
+ if (p->flags & VIRTUAL_IO_ADDRESS)
+ regval32 = __raw_readl(p->enable_reg);
+ else
+ regval32 = omap_readl(p->enable_reg);
+ } else {
+ if (p->flags & VIRTUAL_IO_ADDRESS)
+ regval32 = __raw_readw(p->enable_reg);
+ else
+ regval32 = omap_readw(p->enable_reg);
+ }
+
+ if ((regval32 & (1 << p->enable_bit)) == 0)
+ continue;
+
+ /* FIXME: This clock seems to be necessary but no-one
+ * has asked for its activation. */
+ if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera
+ || p == &ck_dpll1out // FIX: SoSSI, SSR
+ || p == &arm_gpio_ck // FIX: GPIO code for 1510
+ ) {
+ printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+ p->name);
+ continue;
+ }
+
+ printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+ __clk_disable(p);
+ printk(" done\n");
+ }
+
+ return 0;
+}
+
+late_initcall(omap_late_clk_reset);
+
+#endif
diff --git a/arch/arm/plat-omap/clock.h b/arch/arm/plat-omap/clock.h
index 08b504deb1a..a89e1e8c251 100644
--- a/arch/arm/plat-omap/clock.h
+++ b/arch/arm/plat-omap/clock.h
@@ -52,6 +52,8 @@ struct mpu_rate {
#define CLOCK_IN_OMAP16XX 64
#define CLOCK_IN_OMAP1510 128
#define CLOCK_IN_OMAP730 256
+#define DSP_DOMAIN_CLOCK 512
+#define VIRTUAL_IO_ADDRESS 1024
/* ARM_CKCTL bit shifts */
#define CKCTL_PERDIV_OFFSET 0
@@ -63,6 +65,8 @@ struct mpu_rate {
/*#define ARM_TIMXO 12*/
#define EN_DSPCK 13
/*#define ARM_INTHCK_SEL 14*/ /* Divide-by-2 for mpu inth_ck */
+/* DSP_CKCTL bit shifts */
+#define CKCTL_DSPPERDIV_OFFSET 0
/* ARM_IDLECT1 bit shifts */
/*#define IDLWDT_ARM 0*/
@@ -96,6 +100,9 @@ struct mpu_rate {
#define EN_TC1_CK 2
#define EN_TC2_CK 4
+/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
+#define EN_DSPTIMCK 5
+
/* Various register defines for clock controls scattered around OMAP chip */
#define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */
#define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */
@@ -103,7 +110,8 @@ struct mpu_rate {
#define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */
#define SWD_CLK_DIV_CTRL_SEL 0xfffe0874
#define COM_CLK_DIV_CTRL_SEL 0xfffe0878
-
+#define SOFT_REQ_REG 0xfffe0834
+#define SOFT_REQ_REG2 0xfffe0880
int clk_register(struct clk *clk);
void clk_unregister(struct clk *clk);
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 015bd2cf869..c0a5c2fa42b 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -794,10 +794,6 @@ static void set_b1_regs(void)
w = omap_readw(OMAP1610_DMA_LCD_CTRL);
/* Always set the source port as SDRAM for now*/
w &= ~(0x03 << 6);
- if (lcd_dma.ext_ctrl)
- w |= 1 << 8;
- else
- w &= ~(1 << 8);
if (lcd_dma.callback != NULL)
w |= 1 << 1; /* Block interrupt enable */
else
@@ -889,9 +885,15 @@ void omap_enable_lcd_dma(void)
*/
if (enable_1510_mode || !lcd_dma.ext_ctrl)
return;
+
+ w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+ w |= 1 << 8;
+ omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+
w = omap_readw(OMAP1610_DMA_LCD_CCR);
w |= 1 << 7;
omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
lcd_dma.active = 1;
}
@@ -922,10 +924,19 @@ void omap_setup_lcd_dma(void)
void omap_stop_lcd_dma(void)
{
+ u16 w;
+
lcd_dma.active = 0;
- if (!enable_1510_mode && lcd_dma.ext_ctrl)
- omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~(1 << 7),
- OMAP1610_DMA_LCD_CCR);
+ if (enable_1510_mode || !lcd_dma.ext_ctrl)
+ return;
+
+ w = omap_readw(OMAP1610_DMA_LCD_CCR);
+ w &= ~(1 << 7);
+ omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
+ w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+ w &= ~(1 << 8);
+ omap_writew(w, OMAP1610_DMA_LCD_CTRL);
}
/*
@@ -972,6 +983,25 @@ dma_addr_t omap_get_dma_dst_pos(int lch)
(OMAP_DMA_CDSA_U(lch) << 16));
}
+int omap_dma_running(void)
+{
+ int lch;
+
+ /* Check if LCD DMA is running */
+ if (cpu_is_omap16xx())
+ if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
+ return 1;
+
+ for (lch = 0; lch < dma_chan_count; lch++) {
+ u16 w;
+
+ w = omap_readw(OMAP_DMA_CCR(lch));
+ if (w & OMAP_DMA_CCR_EN)
+ return 1;
+ }
+ return 0;
+}
+
static int __init omap_init_dma(void)
{
int ch, r;
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 10c3f22f9c6..43567d5eddd 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -66,6 +66,7 @@ struct omap_mcbsp {
static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
static struct clk *mcbsp_dsp_ck = 0;
static struct clk *mcbsp_api_ck = 0;
+static struct clk *mcbsp_dspxor_ck = 0;
static void omap_mcbsp_dump_reg(u8 id)
@@ -175,7 +176,7 @@ static int omap_mcbsp_check(unsigned int id)
return 0;
}
- if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
if (id > OMAP_MAX_MCBSP_COUNT) {
printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
return -1;
@@ -191,15 +192,12 @@ static int omap_mcbsp_check(unsigned int id)
static void omap_mcbsp_dsp_request(void)
{
- if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
- omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
- ARM_RSTCT1);
- clk_enable(mcbsp_dsp_ck);
- clk_enable(mcbsp_api_ck);
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ clk_use(mcbsp_dsp_ck);
+ clk_use(mcbsp_api_ck);
/* enable 12MHz clock to mcbsp 1 & 3 */
- __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
- DSP_IDLECT2);
+ clk_use(mcbsp_dspxor_ck);
__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
DSP_RSTCT2);
}
@@ -207,10 +205,13 @@ static void omap_mcbsp_dsp_request(void)
static void omap_mcbsp_dsp_free(void)
{
- /* Useless for now */
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ clk_unuse(mcbsp_dspxor_ck);
+ clk_unuse(mcbsp_dsp_ck);
+ clk_unuse(mcbsp_api_ck);
+ }
}
-
int omap_mcbsp_request(unsigned int id)
{
int err;
@@ -350,6 +351,73 @@ void omap_mcbsp_stop(unsigned int id)
}
+/* polled mcbsp i/o operations */
+int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
+{
+ u32 base = mcbsp[id].io_base;
+ writew(buf, base + OMAP_MCBSP_REG_DXR1);
+ /* if frame sync error - clear the error */
+ if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) {
+ /* clear error */
+ writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR),
+ base + OMAP_MCBSP_REG_SPCR2);
+ /* resend */
+ return -1;
+ } else {
+ /* wait for transmit confirmation */
+ int attemps = 0;
+ while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) {
+ if (attemps++ > 1000) {
+ writew(readw(base + OMAP_MCBSP_REG_SPCR2) &
+ (~XRST),
+ base + OMAP_MCBSP_REG_SPCR2);
+ udelay(10);
+ writew(readw(base + OMAP_MCBSP_REG_SPCR2) |
+ (XRST),
+ base + OMAP_MCBSP_REG_SPCR2);
+ udelay(10);
+ printk(KERN_ERR
+ " Could not write to McBSP Register\n");
+ return -2;
+ }
+ }
+ }
+ return 0;
+}
+
+int omap_mcbsp_pollread(unsigned int id, u16 * buf)
+{
+ u32 base = mcbsp[id].io_base;
+ /* if frame sync error - clear the error */
+ if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) {
+ /* clear error */
+ writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR),
+ base + OMAP_MCBSP_REG_SPCR1);
+ /* resend */
+ return -1;
+ } else {
+ /* wait for recieve confirmation */
+ int attemps = 0;
+ while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) {
+ if (attemps++ > 1000) {
+ writew(readw(base + OMAP_MCBSP_REG_SPCR1) &
+ (~RRST),
+ base + OMAP_MCBSP_REG_SPCR1);
+ udelay(10);
+ writew(readw(base + OMAP_MCBSP_REG_SPCR1) |
+ (RRST),
+ base + OMAP_MCBSP_REG_SPCR1);
+ udelay(10);
+ printk(KERN_ERR
+ " Could not read from McBSP Register\n");
+ return -2;
+ }
+ }
+ }
+ *buf = readw(base + OMAP_MCBSP_REG_DRR1);
+ return 0;
+}
+
/*
* IRQ based word transmission.
*/
@@ -625,10 +693,15 @@ static int __init omap_mcbsp_init(void)
return PTR_ERR(mcbsp_dsp_ck);
}
mcbsp_api_ck = clk_get(0, "api_ck");
- if (IS_ERR(mcbsp_dsp_ck)) {
+ if (IS_ERR(mcbsp_api_ck)) {
printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
return PTR_ERR(mcbsp_api_ck);
}
+ mcbsp_dspxor_ck = clk_get(0, "dspxor_ck");
+ if (IS_ERR(mcbsp_dspxor_ck)) {
+ printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n");
+ return PTR_ERR(mcbsp_dspxor_ck);
+ }
#ifdef CONFIG_ARCH_OMAP730
if (cpu_is_omap730()) {
@@ -643,7 +716,7 @@ static int __init omap_mcbsp_init(void)
}
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
- if (cpu_is_omap1610() || cpu_is_omap1710()) {
+ if (cpu_is_omap16xx()) {
mcbsp_info = mcbsp_1610;
mcbsp_count = ARRAY_SIZE(mcbsp_1610);
}
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index cbecd10d0b6..ea7b955b9c8 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -53,19 +53,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
return -EINVAL;
}
- cfg = &reg_cfg_table[reg_cfg];
-
- /*
- * We do a pretty long section here with lock on, but pin muxing
- * should only happen on driver init for each driver, so it's not time
- * critical.
- */
- spin_lock_irqsave(&mux_spin_lock, flags);
+ cfg = (reg_cfg_set *)&reg_cfg_table[reg_cfg];
/* Check the mux register in question */
if (cfg->mux_reg) {
unsigned tmp1, tmp2;
+ spin_lock_irqsave(&mux_spin_lock, flags);
reg_orig = omap_readl(cfg->mux_reg);
/* The mux registers always seem to be 3 bits long */
@@ -80,11 +74,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
warn = 1;
omap_writel(reg, cfg->mux_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
}
/* Check for pull up or pull down selection on 1610 */
if (!cpu_is_omap1510()) {
if (cfg->pu_pd_reg && cfg->pull_val) {
+ spin_lock_irqsave(&mux_spin_lock, flags);
pu_pd_orig = omap_readl(cfg->pu_pd_reg);
mask = 1 << cfg->pull_bit;
@@ -100,11 +96,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
pu_pd = pu_pd_orig & ~mask;
}
omap_writel(pu_pd, cfg->pu_pd_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
}
}
/* Check for an associated pull down register */
if (cfg->pull_reg) {
+ spin_lock_irqsave(&mux_spin_lock, flags);
pull_orig = omap_readl(cfg->pull_reg);
mask = 1 << cfg->pull_bit;
@@ -121,6 +119,7 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
}
omap_writel(pull, cfg->pull_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
}
if (warn) {
@@ -149,8 +148,6 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
}
#endif
- spin_unlock_irqrestore(&mux_spin_lock, flags);
-
#ifdef CONFIG_OMAP_MUX_ERRORS
return warn ? -ETXTBSY : 0;
#else
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index ab38e4eb313..25bc4a8dd76 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -326,7 +326,7 @@ static u64 ohci_dmamask = ~(u32)0;
static struct resource ohci_resources[] = {
{
.start = OMAP_OHCI_BASE,
- .end = OMAP_OHCI_BASE + 4096,
+ .end = OMAP_OHCI_BASE + 4096 - 1,
.flags = IORESOURCE_MEM,
},
{