* [PATCHv9 7/8] ARM: OMAP: PM: update target fpwrst to what pwrdm can reach
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
As the code within pwrdm_set_fpwrst is updating powerstate and logic
states according to powerdomain capabilities, it may alter the target
fpwrst also. Update the target fpwrst status according to these checks,
otherwise rest of the code in this function will malfunction.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/powerdomain.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index f5786b4..f92a867 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -711,6 +711,9 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
return -EINVAL;
}
+ /* Refresh target fprwst according to what we can reach */
+ fpwrst = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic);
+
pr_debug("%s: set fpwrst %0x to pwrdm %s\n",
__func__, fpwrst, pwrdm->name);
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 6/8] ARM: OMAP4: retrigger localtimers after re-enabling gic
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
From: Colin Cross <ccross@android.com>
'Workaround for ROM bug because of CA9 r2pX gic control'
register change disables the gic distributor while the secondary
cpu is being booted. If a localtimer interrupt on the primary cpu
occurs when the distributor is turned off, the interrupt is lost,
and the localtimer never fires again.
Make the primary cpu wait for the secondary cpu to reenable the
gic distributor (with interrupts off for safety), and then
check if the pending bit is set in the localtimer but not the
gic. If so, ack it in the localtimer, and reset the timer with
the minimum timeout to trigger a new timer interrupt.
Signed-off-by: Colin Cross <ccross@android.com>
[s-jan at ti.com: adapted to k3.4 + validated functionality]
Signed-off-by: Sebastien Jan <s-jan@ti.com>
[t-kristo at ti.com: dropped generic ARM kernel exports from the code, rebased
to mainline]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/common.h | 2 ++
arch/arm/mach-omap2/omap-smp.c | 13 ++++++++++++-
arch/arm/mach-omap2/omap4-common.c | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 48 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 70993a9..d29dbaa 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -276,6 +276,8 @@ static inline void __iomem *omap4_get_scu_base(void)
extern void __init gic_init_irq(void);
extern void gic_dist_disable(void);
+extern bool gic_dist_disabled(void);
+extern void gic_timer_retrigger(void);
extern void omap_smc1(u32 fn, u32 arg);
extern void __iomem *omap4_get_sar_ram_base(void);
extern void omap_do_wfi(void);
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 7d9c0e3..49a08df 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -134,11 +134,22 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
* 2) CPU1 must re-enable the GIC distributor on
* it's wakeup path.
*/
- if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD))
+ if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
+ local_irq_disable();
gic_dist_disable();
+ }
clkdm_wakeup(cpu1_clkdm);
clkdm_allow_idle(cpu1_clkdm);
+
+ if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
+ while (gic_dist_disabled()) {
+ udelay(1);
+ cpu_relax();
+ }
+ gic_timer_retrigger();
+ local_irq_enable();
+ }
} else {
dsb_sev();
booted = true;
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 72cf396..6f94b4e 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/memblock.h>
#include <linux/of_irq.h>
@@ -24,6 +25,7 @@
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h>
#include <asm/memblock.h>
+#include <asm/smp_twd.h>
#include <plat/sram.h>
#include <plat/omap-secure.h>
@@ -42,6 +44,9 @@ static void __iomem *l2cache_base;
static void __iomem *sar_ram_base;
static void __iomem *gic_dist_base_addr;
+static void __iomem *twd_base;
+
+#define IRQ_LOCALTIMER 29
#ifdef CONFIG_OMAP4_ERRATA_I688
/* Used to implement memory barrier on DRAM path */
@@ -101,6 +106,9 @@ void __init gic_init_irq(void)
gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
BUG_ON(!gic_dist_base_addr);
+ twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_4K);
+ BUG_ON(!twd_base);
+
/* Static mapping, never released */
omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
BUG_ON(!omap_irq_base);
@@ -116,6 +124,32 @@ void gic_dist_disable(void)
__raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
}
+bool gic_dist_disabled(void)
+{
+ return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1);
+}
+
+void gic_timer_retrigger(void)
+{
+ u32 twd_int = __raw_readl(twd_base + TWD_TIMER_INTSTAT);
+ u32 gic_int = __raw_readl(gic_dist_base_addr + GIC_DIST_PENDING_SET);
+ u32 twd_ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
+
+ if (twd_int && !(gic_int & BIT(IRQ_LOCALTIMER))) {
+ /*
+ * The local timer interrupt got lost while the distributor was
+ * disabled. Ack the pending interrupt, and retrigger it.
+ */
+ pr_warn("%s: lost localtimer interrupt\n", __func__);
+ __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
+ if (!(twd_ctrl & TWD_TIMER_CONTROL_PERIODIC)) {
+ __raw_writel(1, twd_base + TWD_TIMER_COUNTER);
+ twd_ctrl |= TWD_TIMER_CONTROL_ENABLE;
+ __raw_writel(twd_ctrl, twd_base + TWD_TIMER_CONTROL);
+ }
+ }
+}
+
#ifdef CONFIG_CACHE_L2X0
void __iomem *omap4_get_l2cache_base(void)
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 5/8] ARM: OMAP4: PM: put all domains to OSWR during suspend
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
Currently OMAP4 suspend puts all power domains to CSWR. OSWR is a deeper
state that saves more power, but has higher latencies also. As suspend
is considered a high-latency operation, OSWR is appropriate here.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/pm44xx.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index a313165..d36e4e5 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -100,7 +100,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
return -ENOMEM;
pwrst->pwrdm = pwrdm;
- pwrst->next_state = PWRDM_FUNC_PWRST_CSWR;
+ pwrst->next_state = PWRDM_FUNC_PWRST_OSWR;
list_add(&pwrst->node, &pwrst_list);
return pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_state);
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 4/8] ARM: OMAP4: suspend: Program all domains to retention
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
From: Rajendra Nayak <rnayak@ti.com>
Remove the FIXME's in the suspend sequence since
we now intend to support system level RET support.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/mach-omap2/pm44xx.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 07e7ef2..a313165 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -95,13 +95,6 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
if (!strncmp(pwrdm->name, "cpu", 3))
return 0;
- /*
- * FIXME: Remove this check when core retention is supported
- * Only MPUSS power domain is added in the list.
- */
- if (strcmp(pwrdm->name, "mpu_pwrdm"))
- return 0;
-
pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
if (!pwrst)
return -ENOMEM;
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 3/8] ARM: OMAP4460: Workaround for ROM bug because of CA9 r2pX GIC control register change.
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
From: Santosh Shilimkar <santosh.shilimkar@ti.com>
On OMAP4+ devices, GIC register context is lost when MPUSS hits
the OSWR(Open Switch Retention). On the CPU wakeup path, ROM code
gets executed and one of the steps in it is to restore the
saved context of the GIC. The ROM Code GIC distributor restoration
is split in two parts: CPU specific register done by each CPU and
common register done by only one CPU.
Below is the abstract flow.
...............................................................
- MPUSS in OSWR state.
- CPU0 wakes up on the event(interrupt) and start executing ROM code.
[..]
- CPU0 executes "GIC Restoration:"
[...]
- CPU0 swicthes to non-secure mode and jumps to OS resume code.
[...]
- CPU0 is online in OS
- CPU0 enables the GIC distributor. GICD.Enable Non-secure = 1
- CPU0 wakes up CPU1 with clock-domain force wakeup method.
- CPU0 continues it's execution.
[..]
- CPU1 wakes up and start executing ROM code.
[..]
- CPU1 executes "GIC Restoration:"
[..]
- CPU1 swicthes to non-secure mode and jumps to OS resume code.
[...]
- CPU1 is online in OS and start executing.
[...] -
GIC Restoration: /* Common routine for HS and GP devices */
{
if (GICD != 1) { /* This will be true in OSWR state */
if (GIC_SAR_BACKUP_STATE == SAVED)
- CPU restores GIC distributor
else
- reconfigure GIC distributor to boot values.
GICD.Enable secure = 1
}
if (GIC_SAR_BACKUP_STATE == SAVED)
- CPU restore its GIC CPU interface registers if saved.
else
- reconfigure its GIC CPU interface registers to boot
values.
}
...............................................................
So as mentioned in the flow, GICD != 1 condition decides how
the GIC registers are handled in ROM code wakeup path from
OSWR. As evident from the flow, ROM code relies on the entire
GICD register value and not specific register bits.
The assumption was valid till CortexA9 r1pX version since there
was only one banked bit to control secure and non-secure GICD.
Secure view which ROM code sees:
bit 0 == Enable Non-secure
Non-secure view which HLOS sees:
bit 0 == Enable secure
But GICD register has changed between CortexA9 r1pX and r2pX.
On r2pX GICD register is composed of 2 bits.
Secure view which ROM code sees:
bit 1 == Enable Non-secure
bit 0 == Enable secure
Non-secure view which HLOS sees:
bit 0 == Enable Non-secure
Hence on OMAP4460(r2pX) devices, if you go through the
above flow again during CPU1 wakeup, GICD == 3 and hence
ROM code fails to understand the real wakeup power state
and reconfigures GIC distributor to boot values. This is
nasty since you loose the entire interrupt controller
context in a live system.
The ROM code fix done on next OMAP4 device (OMAP4470 - r2px) is to
check "GICD.Enable secure != 1" for GIC restoration in OSWR wakeup path.
Since ROM code can't be fixed on OMAP4460 devices, a work around
needs to be implemented. As evident from the flow, as long as
CPU1 sees GICD == 1 in it's wakeup path from OSWR, the issue
won't happen. Below is the flow with the work-around.
...............................................................
- MPUSS in OSWR state.
- CPU0 wakes up on the event(interrupt) and start executing ROM code.
[..]
- CPU0 executes "GIC Restoration:"
[..]
- CPU0 swicthes to non-secure mode and jumps to OS resume code.
[..]
- CPU0 is online in OS.
- CPU0 does GICD.Enable Non-secure = 0
- CPU0 wakes up CPU1 with clock domain force wakeup method.
- CPU0 waits for GICD.Enable Non-secure = 1
- CPU0 coninues it's execution.
[..]
- CPU1 wakes up and start executing ROM code.
[..]
- CPU1 executes "GIC Restoration:"
[..]
- CPU1 swicthes to non-secure mode and jumps to OS resume code.
[..]
- CPU1 is online in OS
- CPU1 does GICD.Enable Non-secure = 1
- CPU1 start executing
[...]
...............................................................
With this procedure, the GIC configuration done between the
CPU0 wakeup and CPU1 wakeup will not be lost but during this
short windows, the CPU0 will not receive interrupts.
The BUG is applicable to only OMAP4460(r2pX) devices.
OMAP4470 (also r2pX) is not affected by this bug because
ROM code has been fixed.
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/common.h | 2 +
arch/arm/mach-omap2/omap-headsmp.S | 38 +++++++++++++++++++++++++++++
arch/arm/mach-omap2/omap-mpuss-lowpower.c | 9 ++++++-
arch/arm/mach-omap2/omap-smp.c | 28 ++++++++++++++++++++-
arch/arm/mach-omap2/omap4-common.c | 8 +++++-
arch/arm/mach-omap2/pm.h | 2 +
6 files changed, 84 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 7045e4d..70993a9 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -275,6 +275,7 @@ static inline void __iomem *omap4_get_scu_base(void)
#endif
extern void __init gic_init_irq(void);
+extern void gic_dist_disable(void);
extern void omap_smc1(u32 fn, u32 arg);
extern void __iomem *omap4_get_sar_ram_base(void);
extern void omap_do_wfi(void);
@@ -282,6 +283,7 @@ extern void omap_do_wfi(void);
#ifdef CONFIG_SMP
/* Needed for secondary core boot */
extern void omap_secondary_startup(void);
+extern void omap_secondary_startup_4460(void);
extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
extern void omap_auxcoreboot_addr(u32 cpu_addr);
extern u32 omap_read_auxcoreboot0(void);
diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
index 502e313..0ea09fa 100644
--- a/arch/arm/mach-omap2/omap-headsmp.S
+++ b/arch/arm/mach-omap2/omap-headsmp.S
@@ -18,6 +18,8 @@
#include <linux/linkage.h>
#include <linux/init.h>
+#include "omap44xx.h"
+
__CPUINIT
/* Physical address needed since MMU not enabled yet on secondary core */
@@ -64,3 +66,39 @@ hold: ldr r12,=0x103
b secondary_startup
ENDPROC(omap_secondary_startup)
+ENTRY(omap_secondary_startup_4460)
+hold_2: ldr r12,=0x103
+ dsb
+ smc #0 @ read from AuxCoreBoot0
+ mov r0, r0, lsr #9
+ mrc p15, 0, r4, c0, c0, 5
+ and r4, r4, #0x0f
+ cmp r0, r4
+ bne hold_2
+
+ /*
+ * GIC distributor control register has changed between
+ * CortexA9 r1pX and r2pX. The Control Register secure
+ * banked version is now composed of 2 bits:
+ * bit 0 == Secure Enable
+ * bit 1 == Non-Secure Enable
+ * The Non-Secure banked register has not changed
+ * Because the ROM Code is based on the r1pX GIC, the CPU1
+ * GIC restoration will cause a problem to CPU0 Non-Secure SW.
+ * The workaround must be:
+ * 1) Before doing the CPU1 wakeup, CPU0 must disable
+ * the GIC distributor
+ * 2) CPU1 must re-enable the GIC distributor on
+ * it's wakeup path.
+ */
+ ldr r1, =OMAP44XX_GIC_DIST_BASE
+ ldr r0, [r1]
+ orr r0, #1
+ str r0, [r1]
+
+ /*
+ * we've been released from the wait loop,secondary_stack
+ * should now contain the SVC stack for this core
+ */
+ b secondary_startup
+ENDPROC(omap_secondary_startup_4460)
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 13c1249..562fd38 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -67,6 +67,7 @@ struct omap4_cpu_pm_info {
void __iomem *scu_sar_addr;
void __iomem *wkup_sar_addr;
void __iomem *l2x0_sar_addr;
+ void (*secondary_startup)(void);
};
static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
@@ -300,6 +301,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
{
unsigned int cpu_state = 0;
+ struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
if (omap_rev() == OMAP4430_REV_ES1_0)
return -ENXIO;
@@ -309,7 +311,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
clear_cpu_prev_pwrst(cpu);
set_cpu_next_pwrst(cpu, power_state);
- set_cpu_wakeup_addr(cpu, virt_to_phys(omap_secondary_startup));
+ set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
scu_pwrst_prepare(cpu, power_state);
/*
@@ -360,6 +362,11 @@ int __init omap4_mpuss_init(void)
pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
+ if (cpu_is_omap446x())
+ pm_info->secondary_startup = omap_secondary_startup_4460;
+ else
+ pm_info->secondary_startup = omap_secondary_startup;
+
pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
if (!pm_info->pwrdm) {
pr_err("Lookup failed for CPU1 pwrdm\n");
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 4d05fa8..7d9c0e3 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -32,6 +32,7 @@
#include "iomap.h"
#include "common.h"
#include "clockdomain.h"
+#include "pm.h"
#define CPU_MASK 0xff0ffff0
#define CPU_CORTEX_A9 0x410FC090
@@ -118,6 +119,24 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
* 4.3.4.2 Power States of CPU0 and CPU1
*/
if (booted) {
+ /*
+ * GIC distributor control register has changed between
+ * CortexA9 r1pX and r2pX. The Control Register secure
+ * banked version is now composed of 2 bits:
+ * bit 0 == Secure Enable
+ * bit 1 == Non-Secure Enable
+ * The Non-Secure banked register has not changed
+ * Because the ROM Code is based on the r1pX GIC, the CPU1
+ * GIC restoration will cause a problem to CPU0 Non-Secure SW.
+ * The workaround must be:
+ * 1) Before doing the CPU1 wakeup, CPU0 must disable
+ * the GIC distributor
+ * 2) CPU1 must re-enable the GIC distributor on
+ * it's wakeup path.
+ */
+ if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD))
+ gic_dist_disable();
+
clkdm_wakeup(cpu1_clkdm);
clkdm_allow_idle(cpu1_clkdm);
} else {
@@ -138,7 +157,14 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
static void __init wakeup_secondary(void)
{
+ void *startup_addr = omap_secondary_startup;
void __iomem *base = omap_get_wakeupgen_base();
+
+ if (cpu_is_omap446x()) {
+ startup_addr = omap_secondary_startup_4460;
+ pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD;
+ }
+
/*
* Write the address of secondary startup routine into the
* AuxCoreBoot1 where ROM code will jump and start executing
@@ -146,7 +172,7 @@ static void __init wakeup_secondary(void)
* A barrier is added to ensure that write buffer is drained
*/
if (omap_secure_apis_support())
- omap_auxcoreboot_addr(virt_to_phys(omap_secondary_startup));
+ omap_auxcoreboot_addr(virt_to_phys(startup_addr));
else
__raw_writel(virt_to_phys(omap5_secondary_startup),
base + OMAP_AUX_CORE_BOOT_1);
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index e1f2897..72cf396 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -41,6 +41,7 @@ static void __iomem *l2cache_base;
#endif
static void __iomem *sar_ram_base;
+static void __iomem *gic_dist_base_addr;
#ifdef CONFIG_OMAP4_ERRATA_I688
/* Used to implement memory barrier on DRAM path */
@@ -95,7 +96,6 @@ void __init omap_barriers_init(void)
void __init gic_init_irq(void)
{
void __iomem *omap_irq_base;
- void __iomem *gic_dist_base_addr;
/* Static mapping, never released */
gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
@@ -110,6 +110,12 @@ void __init gic_init_irq(void)
gic_init(0, 29, gic_dist_base_addr, omap_irq_base);
}
+void gic_dist_disable(void)
+{
+ if (gic_dist_base_addr)
+ __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
+}
+
#ifdef CONFIG_CACHE_L2X0
void __iomem *omap4_get_l2cache_base(void)
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index f26f2d7..bee3911 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -100,6 +100,8 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
static inline void enable_omap3630_toggle_l2_on_restore(void) { }
#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
+#define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD (1 << 0)
+
#if defined(CONFIG_ARCH_OMAP4)
extern u16 pm44xx_errata;
#define IS_PM44XX_ERRATUM(id) (pm44xx_errata & (id))
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 2/8] ARM: OMAP4: PM: add errata support
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
Added similar PM errata flag support as omap3 has. This should be used
in similar manner, set the flags during init time, and check the flag
values during runtime.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/pm.h | 7 +++++++
arch/arm/mach-omap2/pm44xx.c | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 707e9cb..f26f2d7 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -100,6 +100,13 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
static inline void enable_omap3630_toggle_l2_on_restore(void) { }
#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
+#if defined(CONFIG_ARCH_OMAP4)
+extern u16 pm44xx_errata;
+#define IS_PM44XX_ERRATUM(id) (pm44xx_errata & (id))
+#else
+#define IS_PM44XX_ERRATUM(id) 0
+#endif
+
#ifdef CONFIG_POWER_AVS_OMAP
extern int omap_devinit_smartreflex(void);
extern void omap_enable_smartreflex_on_init(void);
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index ba06300..07e7ef2 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -33,6 +33,7 @@ struct power_state {
};
static LIST_HEAD(pwrst_list);
+u16 pm44xx_errata;
#ifdef CONFIG_SUSPEND
static int omap4_pm_suspend(void)
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 1/8] ARM: OMAP: hwmod: Add support for per hwmod/module context lost count
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350552010-28760-1-git-send-email-t-kristo@ti.com>
From: Rajendra Nayak <rnayak@ti.com>
OMAP4 has module specific context lost registers which makes it now
possible to have module level context loss count, instead of relying
on the powerdomain level context count.
Add 2 private hwmod api's to update/clear the hwmod/module specific
context lost counters/register.
Update the module specific context_lost_counter and clear the hardware
bits just after enabling the module.
omap_hwmod_get_context_loss_count() now returns the hwmod context loss
count them on platforms where they exist (OMAP4), else fall back on
the pwrdm level counters for older platforms.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul at pwsan.com: added function kerneldoc, fixed structure kerneldoc,
rearranged structure to avoid memory waste, marked fns as OMAP4-specific,
prevent fn entry on non-OMAP4 chips, reduced indentation, merged update
and clear, merged patches]
[t-kristo at ti.com: added support for arch specific hwmod ops, and changed
the no context offset indicator to USHRT_MAX]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
[paul at pwsan.com: use NO_CONTEXT_LOSS_BIT flag rather than USHRT_MAX;
convert unsigned context lost counter to int to match the return type;
get rid of hwmod_ops in favor of the existing soc_ops mechanism]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 60 ++++++++++++++++++++++++--
arch/arm/plat-omap/include/plat/omap_hwmod.h | 10 +++-
2 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index b969ab1..d810f85 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -189,6 +189,8 @@ struct omap_hwmod_soc_ops {
int (*is_hardreset_asserted)(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri);
int (*init_clkdm)(struct omap_hwmod *oh);
+ void (*update_context_lost)(struct omap_hwmod *oh);
+ int (*get_context_lost)(struct omap_hwmod *oh);
};
/* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */
@@ -1962,6 +1964,47 @@ static void _reconfigure_io_chain(void)
}
/**
+ * _omap4_update_context_lost - increment hwmod context loss counter if
+ * hwmod context was lost, and clear hardware context loss reg
+ * @oh: hwmod to check for context loss
+ *
+ * If the PRCM indicates that the hwmod @oh lost context, increment
+ * our in-memory context loss counter, and clear the RM_*_CONTEXT
+ * bits. No return value.
+ */
+static void _omap4_update_context_lost(struct omap_hwmod *oh)
+{
+ u32 r;
+
+ if (oh->prcm.omap4.flags & HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT)
+ return;
+
+ r = omap4_prminst_read_inst_reg(oh->clkdm->pwrdm.ptr->prcm_partition,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.context_offs);
+
+ if (!r)
+ return;
+
+ oh->prcm.omap4.context_lost_counter++;
+
+ omap4_prminst_write_inst_reg(r, oh->clkdm->pwrdm.ptr->prcm_partition,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.context_offs);
+}
+
+/**
+ * _omap4_get_context_lost - get context loss counter for a hwmod
+ * @oh: hwmod to get context loss counter for
+ *
+ * Returns the in-memory context loss counter for a hwmod.
+ */
+static int _omap4_get_context_lost(struct omap_hwmod *oh)
+{
+ return oh->prcm.omap4.context_lost_counter;
+}
+
+/**
* _enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
@@ -2044,6 +2087,9 @@ static int _enable(struct omap_hwmod *oh)
if (soc_ops.enable_module)
soc_ops.enable_module(oh);
+ if (soc_ops.update_context_lost)
+ soc_ops.update_context_lost(oh);
+
r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) :
-EINVAL;
if (!r) {
@@ -3852,17 +3898,21 @@ ohsps_unlock:
* omap_hwmod_get_context_loss_count - get lost context count
* @oh: struct omap_hwmod *
*
- * Query the powerdomain of of @oh to get the context loss
- * count for this device.
+ * Returns the context loss count of associated @oh
+ * upon success, or zero if no context loss data is available.
*
- * Returns the context loss count of the powerdomain assocated with @oh
- * upon success, or zero if no powerdomain exists for @oh.
+ * On OMAP4, this queries the per-hwmod context loss register,
+ * assuming one exists. If not, or on OMAP2/3, this queries the
+ * enclosing powerdomain context loss count.
*/
int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
{
struct powerdomain *pwrdm;
int ret = 0;
+ if (soc_ops.get_context_lost)
+ return soc_ops.get_context_lost(oh);
+
pwrdm = omap_hwmod_get_pwrdm(oh);
if (pwrdm)
ret = pwrdm_get_context_loss_count(pwrdm);
@@ -3980,6 +4030,8 @@ void __init omap_hwmod_init(void)
soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
soc_ops.init_clkdm = _init_clkdm;
+ soc_ops.update_context_lost = _omap4_update_context_lost;
+ soc_ops.get_context_lost = _omap4_get_context_lost;
} else {
WARN(1, "omap_hwmod: unknown SoC type\n");
}
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index b3349f7..8590f62 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -2,7 +2,7 @@
* omap_hwmod macros, structures
*
* Copyright (C) 2009-2011 Nokia Corporation
- * Copyright (C) 2012 Texas Instruments, Inc.
+ * Copyright (C) 2011-2012 Texas Instruments, Inc.
* Paul Walmsley
*
* Created in collaboration with (alphabetical order): Beno?t Cousson,
@@ -395,12 +395,15 @@ struct omap_hwmod_omap2_prcm {
/**
* struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
- * @clkctrl_reg: PRCM address of the clock control register
- * @rstctrl_reg: address of the XXX_RSTCTRL register located in the PRM
+ * @clkctrl_offs: offset of the PRCM clock control register
+ * @rstctrl_offs: offset of the XXX_RSTCTRL register located in the PRM
+ * @context_offs: offset of the RM_*_CONTEXT register
* @lostcontext_mask: bitmask for selecting bits from RM_*_CONTEXT register
* @rstst_reg: (AM33XX only) address of the XXX_RSTST register in the PRM
* @submodule_wkdep_bit: bit shift of the WKDEP range
* @flags: PRCM register capabilities for this IP block
+ * @modulemode: allowable modulemodes
+ * @context_lost_counter: Count of module level context lost
*
* If @lostcontext_mask is not defined, context loss check code uses
* whole register without masking. @lostcontext_mask should only be
@@ -416,6 +419,7 @@ struct omap_hwmod_omap4_prcm {
u8 submodule_wkdep_bit;
u8 modulemode;
u8 flags;
+ int context_lost_counter;
};
--
1.7.4.1
^ permalink raw reply related
* [PATCHv9 0/8] ARM: OMAP4: core retention support
From: Tero Kristo @ 2012-10-18 9:20 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
Changes compared to previous version:
- rebased on top of 3.7-rc1
- applies on top of latest func pwrst code (v6)
- added back patch #1 to this set (it wasn't queued yet after all)
- added patch #7 for fixing a bug in the functional pwrst code
- added patch #8 for fixing a regression with MUSB PHY power handling
(not quite sure if this is the correct way to fix this or not)
Tested with omap4460 gp panda + omap4430 emu blaze boards, with cpuidle +
suspend.
Branch also available here:
git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.7-rc1-omap4-ret-v9
Branch contains also the local timer fix patch from Tony, otherwise
cpuidle does not work properly.
-Tero
^ permalink raw reply
* [PATCH] dma: add new DMA control commands
From: Huang Shijie @ 2012-10-18 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201210181049.21556.marex@denx.de>
? 2012?10?18? 16:49, Marek Vasut ??:
> Dear Huang Shijie,
>
>> ? 2012?10?18? 16:16, Marek Vasut ??:
>>> So we can't stream data from the chip? About time to adjust the MTD
>>> framework to allow that. Maybe implement a command queue?
>> IMHO, it's not possible. Because the READ-PAGE(00h-30h) command needs to
>> check the busy status
>> which means we have to stop in the middle, so we can not chain the all
>> the read-pages DMA commands.
> Can the DMA not branch?
it's too complicated to the MTD layer, as well as the gpmi driver.
Best Regards
Huang Shijie
^ permalink raw reply
* [RESEND] [PATCH 3.6.0- 3/6] ARM/pxa: use module_platform_driver macro
From: Haojian Zhuang @ 2012-10-18 9:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <507D3E16.2050901@compulab.co.il>
On Tue, Oct 16, 2012 at 6:59 PM, Igor Grinberg <grinberg@compulab.co.il> wrote:
> On 10/12/12 09:11, Srinivas KANDAGATLA wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>
>> This patch removes some code duplication by using
>> module_platform_driver.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>
> Acked-by: Igor Grinberg <grinberg@compulab.co.il>
>
Applied
Thanks
Haojian
^ permalink raw reply
* [PATCH] dma: add new DMA control commands
From: Huang Shijie @ 2012-10-18 9:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121018085208.GR21164@n2100.arm.linux.org.uk>
? 2012?10?18? 16:52, Russell King - ARM Linux ??:
> On Thu, Oct 18, 2012 at 02:45:41PM +0800, Huang Shijie wrote:
>> ? 2012?10?18? 14:18, Vinod Koul ??:
>>> Why cant you do start (prepare clock etc) when you submit the descriptor
>>> to dmaengine. Can be done in tx_submit callback.
>>> Similarly remove the clock when dma transaction gets completed.
>> I ever thought this method too.
>>
>> But it will become low efficient in the following case:
>>
>> Assuming the gpmi-nand driver has to read out 1024 pages in one
>> _SINGLE_ read operation.
>> The gpmi-nand will submit the descriptor to dmaengine per page. So with
>> your method,
>> the system will repeat the enable/disable dma clock 1024 time. At every
>> enable/disable dma clock,
>> the system has to enable the clock chain and it's parents ...
> And what if you stop using clk_prepare_enable(), and prepare the clock
> when the channel is requested and only use clk_enable() in the tx_submit
yes. it's a little better.
There is nearly no difference between the clk_prepare_enable() and
clk_enable() in actually.
the clk_gate2_ops does not have any @->prepare.
thanks
Huang Shijie
> method?
>
^ permalink raw reply
* [PATCH 10/10] document: devicetree: bind pinconf in pinctrl single
From: Haojian Zhuang @ 2012-10-18 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Add comments with pinconf & gpio range in the document of
pinctrl-single.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
.../devicetree/bindings/pinctrl/pinctrl-single.txt | 43 ++++++++++++++++++++
1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index 5187f0d..b0e5059 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -15,6 +15,49 @@ Optional properties:
available and same for all registers; if not specified, disabling of
pin functions is ignored
+- pinctrl-single,gpio-mask : mask of enabling gpio function register
+
+- pinctrl-single,gpio-ranges : gpio range list
+
+- pinctrl-single,gpio : array with gpio range start, size & register
+ offset
+
+- pinctrl-single,gpio-enable : value of enabling gpio function
+
+- pinctrl-single,gpio-disable : value of disabling gpio function
+
+- pinctrl-single,power-source-mask : mask of setting power source in
+ the pinmux register
+
+- pinctrl-single,power-source-shift : shift of power source field in
+ the pinmux register
+
+- pinctrl-single,power-source : value of setting power source field
+ in the pinmux register
+
+- pinctrl-single,bias-mask : mask of setting bias value in the pinmux
+ register
+
+- pinctrl-single,bias-shift : shift of setting bias value in the
+ pinmux register
+
+- pinctrl-single,bias-disable : value of disabling bias in the pinmux
+ register
+
+- pinctrl-single,bias-pull-down : value of setting bias pull down in
+ the pinmux register
+
+- pinctrl-single,bias-pull-up : value of setting bias pull up in the
+ pinmux register
+
+- pinctrl-single,bias : value of setting bias in the pinmux register
+
+- pinctrl-single,input-schmitt-mask : mask of setting input schmitt
+ in the pinmux register
+
+- pinctrl-single,input-schmitt-shift : shift of setting input schmitt
+ in the pinmux register
+
This driver assumes that there is only one register for each pin,
and uses the common pinctrl bindings as specified in the pinctrl-bindings.txt
document in this directory.
--
1.7.0.4
^ permalink raw reply related
* [PATCH 09/10] ARM: dts: support pinctrl single in pxa910
From: Haojian Zhuang @ 2012-10-18 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Add pinctrl-single support with device tree in pxa910 dkb platform.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
arch/arm/boot/dts/pxa910-dkb.dts | 187 +++++++++++++++++++++++++++++++++++++-
arch/arm/boot/dts/pxa910.dtsi | 81 ++++++++++++++++
2 files changed, 267 insertions(+), 1 deletions(-)
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
index e92be5a..2ad0a98 100644
--- a/arch/arm/boot/dts/pxa910-dkb.dts
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -24,10 +24,195 @@
soc {
apb at d4000000 {
- uart1: uart at d4017000 {
+ pmx: pinmux at d401e000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&board_pins>;
+
+ board_pins: pinmux_board_pins {
+ /* pins not owned by device driver */
+ };
+ uart1_pins: pinmux_uart1_pins {
+ pinctrl-single,pins = <
+ 0x198 0x6 /* GPIO47_UART1_RXD */
+ 0x19c 0x6 /* GPIO48_UART1_TXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0x6>;
+ };
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ 0x150 0x4 /* GPIO29_UART2_CTS */
+ 0x154 0x4 /* GPIO30_UART2_RTS */
+ 0x158 0x4 /* GPIO31_UART2_TXD */
+ 0x15c 0x4 /* GPIO32_UART2_RXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ uart3_pins: pinmux_uart3_pins {
+ pinctrl-single,pins = <
+ 0x188 0x7 /* GPIO43_UART3_RXD */
+ 0x18c 0x7 /* GPIO44_UART3_TXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ twsi1_pins: pinmux_twsi1_pins {
+ pinctrl-single,pins = <
+ 0x1b0 0x2 /* GPIO53_TWSI_SCL */
+ 0x1b4 0x2 /* GPIO54_TWSI_SDA */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ nand_pins: pinmux_nand_pins {
+ pinctrl-single,pins = <
+ 0x040 0x0 /* ND_IO0 */
+ 0x03c 0x0 /* ND_IO1 */
+ 0x038 0x0 /* ND_IO2 */
+ 0x034 0x0 /* ND_IO3 */
+ 0x030 0x0 /* ND_IO4 */
+ 0x02c 0x0 /* ND_IO5 */
+ 0x028 0x0 /* ND_IO6 */
+ 0x024 0x0 /* ND_IO7 */
+ 0x020 0x0 /* ND_IO8 */
+ 0x01c 0x0 /* ND_IO9 */
+ 0x018 0x0 /* ND_IO10 */
+ 0x014 0x0 /* ND_IO11 */
+ 0x010 0x0 /* ND_IO12 */
+ 0x00c 0x0 /* ND_IO13 */
+ 0x008 0x0 /* ND_IO14 */
+ 0x004 0x0 /* ND_IO15 */
+ 0x044 0x0 /* ND_nCS0 */
+ 0x060 0x1 /* ND_ALE */
+ 0x05c 0x0 /* ND_CLE */
+ 0x054 0x1 /* ND_nWE */
+ 0x058 0x1 /* ND_nRE */
+ 0x068 0x0 /* ND_RDY0 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_ldata_pins: pinmux_mmc1_ldata_pins {
+ pinctrl-single,pins = <
+ 0x0a0 0x0 /* MMC1_DATA0 */
+ 0x09c 0x0 /* MMC1_DATA1 */
+ 0x098 0x0 /* MMC1_DATA2 */
+ 0x094 0x0 /* MMC1_DATA3 */
+ >;
+ pinctrl-single,power-source = <0x3>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_hdata_pins: pinmux_mmc1_hdata_pins {
+ pinctrl-single,pins = <
+ 0x090 0x0 /* MMC1_DATA4 */
+ 0x08c 0x0 /* MMC1_DATA5 */
+ 0x088 0x0 /* MMC1_DATA6 */
+ 0x084 0x0 /* MMC1_DATA7 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_clk_pins: pinmux_mmc1_clk_pins {
+ pinctrl-single,pins = <
+ 0x0a4 0x0 /* MMC1_CMD */
+ 0x0a8 0x0 /* MMC1_CLK */
+ >;
+ pinctrl-single,power-source = <0x3>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_cd_pins: pinmux_mmc1_cd_pins {
+ pinctrl-single,pins = <
+ 0x0ac 0x0 /* MMC1_CD */
+ 0x0b0 0x0 /* MMC1_WP */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc2_pins: pinmux_mmc2_pins {
+ pinctrl-single,pins = <
+ 0x180 0x1 /* MMC2_CMD */
+ 0x184 0x1 /* MMC2_CLK */
+ 0x17c 0x1 /* MMC2_DATA0 */
+ 0x178 0x1 /* MMC2_DATA1 */
+ 0x174 0x1 /* MMC2_DATA2 */
+ 0x170 0x1 /* MMC2_DATA3 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ w1_pins: pinmux_w1_pins {
+ pinctrl-single,pins = <
+ 0x0cc 0x2 /* CLK_REQ_W1 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ ssp1_pins: pinmux_ssp1_pins {
+ pinctrl-single,pins = <
+ 0x130 0x1 /* GPIO21_SSP1_SCLK */
+ 0x134 0x1 /* GPIO22_SSP1_FRM */
+ 0x138 0x1 /* GPIO23_SSP1_TXD */
+ 0x13c 0x1 /* GPIO24_SSP1_RXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ keypad_pins: pinmux_keypad_pins {
+ pinctrl-single,pins = <
+ 0x0dc 0x1 /* GPIO0_MKIN0 */
+ 0x0e0 0x1 /* GPIO1_MKOUT0 */
+ 0x0e4 0x1 /* GPIO2_MKIN1 */
+ 0x0e8 0x1 /* GPIO3_MKOUT1 */
+ 0x0ec 0x1 /* GPIO4_MKIN2 */
+ 0x0f0 0x1 /* GPIO5_MKOUT2 */
+ 0x0f4 0x1 /* GPIO6_MKIN3 */
+ 0x0f8 0x1 /* GPIO7_MKOUT3 */
+ 0x0fc 0x1 /* GPIO8_MKIN4 */
+ 0x100 0x1 /* GPIO9_MKOUT4 */
+ 0x10c 0x1 /* GPIO12_MKIN6 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ nfc_pins: pinmux_nfc_pins {
+ pinctrl-single,pins = <
+ 0x120 0x0 /* GPIO17 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ wlan_pins: pinmux_wlan_pins {
+ pinctrl-single,pins = <
+ 0x114 0x0 /* GPIO14 */
+ 0x12c 0x0 /* GPIO20 */
+ 0x160 0x0 /* GPIO33 */
+ 0x164 0x0 /* GPIO34 */
+ 0x168 0x0 /* GPIO35 */
+ 0x16c 0x0 /* GPIO36 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ };
+ uart1: uart at d4017000 { /* FFUART */
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "okay";
+ };
+ uart2: uart at d4018000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+ };
+ uart3: uart at d4036000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
status = "okay";
};
twsi1: i2c at d4011000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&twsi1_pins>;
status = "okay";
};
rtc: rtc at d4010000 {
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index aebf32d..d3f5205 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -49,6 +49,87 @@
reg = <0xd4000000 0x00200000>;
ranges;
+ pmx: pinmux at d401e000 {
+ compatible = "pinctrl-single";
+ reg = <0xd401e000 0x0330>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <7>;
+ pinctrl-single,gpio-mask = <7>;
+ pinctrl-single,gpio-ranges = <&gpiorange0 &gpiorange1
+ &gpiorange2 &gpiorange3
+ &gpiorange4 &gpiorange5
+ &gpiorange6 &gpiorange7
+ &gpiorange8 &gpiorange9
+ &gpiorange10>;
+ pinctrl-single,power-source-mask = <0x1800>;
+ pinctrl-single,power-source-shift = <11>;
+ pinctrl-single,bias-mask = <0xe000>;
+ pinctrl-single,bias-shift = <13>;
+ pinctrl-single,bias-disable = <0>;
+ pinctrl-single,bias-pull-down = <0xa000>;
+ pinctrl-single,bias-pull-up = <0xc000>;
+ pinctrl-single,input-schmitt-mask = <0x70>;
+ pinctrl-single,input-schmitt-shift = <4>;
+
+ gpiorange0: gpiorange at d401e0dc {
+ /* GPIO0 ~ GPIO54 */
+ pinctrl-single,gpio = <0 55 0x0dc>;
+ pinctrl-single,gpio-enable = <0x0dc 0>;
+ };
+ gpiorange1: gpiorange at d401e2f0 {
+ /* GPIO55 ~ GPIO59 */
+ pinctrl-single,gpio = <55 5 0x2f0>;
+ pinctrl-single,gpio-enable = <0x2f0 1>;
+ };
+ gpiorange2: gpiorange at d401e304 {
+ /* GPIO60 ~ GPIO66 */
+ pinctrl-single,gpio = <60 7 0x304>;
+ pinctrl-single,gpio-enable = <0x304 0>;
+ };
+ gpiorange3: gpiorange at d401e1b8 {
+ /* GPIO67 ~ GPIO109 */
+ pinctrl-single,gpio = <67 43 0x1b8>;
+ pinctrl-single,gpio-enable = <0x1b8 0>;
+ };
+ gpiorange4: gpiorange at d401e298 {
+ /* GPIO110 ~ GPIO116 */
+ pinctrl-single,gpio = <110 7 0x298>;
+ pinctrl-single,gpio-enable = <0x298 0>;
+ };
+ gpiorange5: gpiorange at d401e0b4 {
+ /* GPIO117 ~ GPIO120 */
+ pinctrl-single,gpio = <117 4 0x0b4>;
+ pinctrl-single,gpio-enable = <0x0b4 1>;
+ };
+ gpiorange6: gpiorange at d401e32c {
+ /* GPIO121 */
+ pinctrl-single,gpio = <121 1 0x32c>;
+ pinctrl-single,gpio-enable = <0x32c 0>;
+ };
+ gpiorange7: gpiorange at d401e0c8 {
+ /* GPIO122 ~ GPIO123 */
+ pinctrl-single,gpio = <122 2 0x0c8>;
+ pinctrl-single,gpio-enable = <0x0c8 1>;
+ };
+ gpiorange8: gpiorange at d401e0d0 {
+ /* GPIO124 */
+ pinctrl-single,gpio = <124 1 0x0d0>;
+ pinctrl-single,gpio-enable = <0x0d0 0>;
+ };
+ gpiorange9: gpiorange at d401e0d4 {
+ /* GPIO125 */
+ pinctrl-single,gpio = <125 1 0x0d4>;
+ pinctrl-single,gpio-enable = <0x0d4 1>;
+ };
+ gpiorange10: gpiorange at d401e06c {
+ /* GPIO126 ~ GPIO127 */
+ pinctrl-single,gpio = <126 2 0x06c>;
+ pinctrl-single,gpio-enable = <0x06c 0>;
+ };
+ };
+
timer0: timer at d4014000 {
compatible = "mrvl,mmp-timer";
reg = <0xd4014000 0x100>;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 08/10] pinctrl: single: support pinconf generic
From: Haojian Zhuang @ 2012-10-18 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Add pinconf generic support with POWER SOURCE, BIAS PULL.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/Kconfig | 2 +-
drivers/pinctrl/pinctrl-single.c | 286 ++++++++++++++++++++++++++++++++++++--
2 files changed, 274 insertions(+), 14 deletions(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 54e3588..cc2ef20 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -106,7 +106,7 @@ config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
select PINMUX
- select PINCONF
+ select GENERIC_PINCONF
help
This selects the device tree based generic pinctrl driver.
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 02cd412..a396944 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -20,6 +20,7 @@
#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -27,6 +28,9 @@
#define DRIVER_NAME "pinctrl-single"
#define PCS_MUX_NAME "pinctrl-single,pins"
+#define PCS_BIAS_NAME "pinctrl-single,bias"
+#define PCS_POWER_SOURCE_NAME "pinctrl-single,power-source"
+#define PCS_SCHMITT_NAME "pinctrl-single,input-schmitt"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_OFF_DISABLED ~0U
#define PCS_MAX_GPIO_VALUES 3
@@ -137,6 +141,15 @@ struct pcs_name {
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
* @gmask: gpio control mask
+ * @bmask: mask of bias in pinconf
+ * @bshift: offset of bias in pinconf
+ * @bdis: bias disable value in pinconf
+ * @bpullup: bias pull up value in pinconf
+ * @bpulldown: bias pull down value in pinconf
+ * @ismask: mask of input schmitt in pinconf
+ * @isshift: offset of input schmitt in pinconf
+ * @psmask: mask of power source in pinconf
+ * @psshift: offset of power source in pinconf
* @names: array of register names for pins
* @pins: physical pins on the SoC
* @pgtree: pingroup index radix tree
@@ -164,6 +177,15 @@ struct pcs_device {
unsigned foff;
unsigned fmax;
unsigned gmask;
+ unsigned bmask;
+ unsigned bshift;
+ unsigned bdis;
+ unsigned bpullup;
+ unsigned bpulldown;
+ unsigned ismask;
+ unsigned isshift;
+ unsigned psmask;
+ unsigned psshift;
struct pcs_name *names;
struct pcs_data pins;
struct radix_tree_root pgtree;
@@ -268,9 +290,14 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
- unsigned offset)
+ unsigned pin)
{
- seq_printf(s, " " DRIVER_NAME);
+ struct pcs_device *pcs;
+ unsigned offset;
+
+ pcs = pinctrl_dev_get_drvdata(pctldev);
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ seq_printf(s, " register value:0x%x", pcs_readl(pcs->base + offset));
}
static void pcs_dt_free_map(struct pinctrl_dev *pctldev,
@@ -468,28 +495,163 @@ static struct pinmux_ops pcs_pinmux_ops = {
.gpio_disable_free = pcs_disable_gpio,
};
+static void pcs_free_pingroups(struct pcs_device *pcs);
+
static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ unsigned data;
+ u32 offset;
+
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ data = pcs_readl(pcs->base + offset);
+
+ switch (param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ if (pcs->psmask == PCS_OFF_DISABLED
+ || pcs->psshift == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->psmask;
+ data = data >> pcs->psshift;
+ *config = data;
+ return 0;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED
+ || pcs->bdis == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->bmask;
+ *config = 0;
+ if (data == pcs->bdis)
+ return 0;
+ else
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED
+ || pcs->bpullup == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->bmask;
+ *config = 0;
+ if (data == pcs->bpullup)
+ return 0;
+ else
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED
+ || pcs->bpulldown == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->bmask;
+ *config = 0;
+ if (data == pcs->bpulldown)
+ return 0;
+ else
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
return -ENOTSUPP;
}
static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param config_param = pinconf_to_config_param(config);
+ unsigned ret, mask = ~0UL;
+ u32 offset, data;
+
+ switch (config_param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ if (pcs->psmask == PCS_OFF_DISABLED
+ || pcs->psshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->psmask;
+ data = (pinconf_to_config_argument(config) << pcs->psshift)
+ & pcs->psmask;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->bmask;
+ data = (pinconf_to_config_argument(config) << pcs->bshift)
+ & pcs->bmask;
+ break;
+ default:
+ return 0;
+ }
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ ret = pcs_readl(pcs->base + offset) & ~mask;
+ pcs_writel(ret | data, pcs->base + offset);
+ return 0;
}
static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
unsigned group, unsigned long *config)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_pingroup *pins;
+
+ pins = radix_tree_lookup(&pcs->pgtree, group);
+ if (!pins) {
+ dev_err(pcs->dev, "%s could not find pingroup%i\n",
+ __func__, group);
+ return -EINVAL;
+ }
+ return pcs_pinconf_get(pctldev, pins->gpins[0], config);
}
static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param config_param = pinconf_to_config_param(config);
+ struct pcs_pingroup *pins;
+ u32 offset, data;
+ unsigned ret, mask = ~0UL;
+ int i;
+
+ switch (config_param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ if (pcs->psmask == PCS_OFF_DISABLED
+ || pcs->psshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->psmask;
+ data = (pinconf_to_config_argument(config) << pcs->psshift)
+ & pcs->psmask;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->bmask;
+ data = (pinconf_to_config_argument(config) << pcs->bshift)
+ & pcs->bmask;
+ break;
+ default:
+ return 0;
+ }
+
+ pins = radix_tree_lookup(&pcs->pgtree, group);
+ if (!pins) {
+ dev_err(pcs->dev, "%s could not find pingroup%i\n",
+ __func__, group);
+ return -EINVAL;
+ }
+ for (i = 0; i < pins->ngpins; i++) {
+ offset = pins->gpins[i] * (pcs->width / BITS_PER_BYTE);
+ ret = pcs_readl(pcs->base + offset) & ~mask;
+ pcs_writel(ret | data, pcs->base + offset);
+ }
+ return 0;
}
static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
@@ -503,6 +665,7 @@ static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
}
static struct pinconf_ops pcs_pinconf_ops = {
+ .is_generic = true,
.pin_config_get = pcs_pinconf_get,
.pin_config_set = pcs_pinconf_set,
.pin_config_group_get = pcs_pinconf_group_get,
@@ -720,12 +883,16 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
struct device_node *np,
struct pinctrl_map **map,
+ unsigned num_configs,
const char **pgnames)
{
struct pcs_func_vals *vals;
+ struct pinctrl_map *p = *map;
const __be32 *mux;
int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
struct pcs_function *function;
+ unsigned long *config;
+ u32 value;
mux = of_get_property(np, PCS_MUX_NAME, &size);
if ((!mux) || (size < sizeof(*mux) * 2)) {
@@ -773,12 +940,42 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
if (res < 0)
goto free_function;
- (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
- (*map)->data.mux.group = np->name;
- (*map)->data.mux.function = np->name;
+ p->type = PIN_MAP_TYPE_MUX_GROUP;
+ p->data.mux.group = np->name;
+ p->data.mux.function = np->name;
+
+ if (!num_configs)
+ return 0;
+ config = devm_kzalloc(pcs->dev, sizeof(*config) * num_configs,
+ GFP_KERNEL);
+ if (!config) {
+ res = -ENOMEM;
+ goto free_pingroup;
+ }
+ index = 0;
+ if (!of_property_read_u32(np, PCS_SCHMITT_NAME, &value))
+ config[index++] =
+ pinconf_to_config_packed(PIN_CONFIG_INPUT_SCHMITT,
+ value & 0xffff);
+ if (!of_property_read_u32(np, PCS_BIAS_NAME, &value))
+ config[index++] =
+ pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE,
+ value & 0xffff);
+ if (!of_property_read_u32(np, PCS_POWER_SOURCE_NAME, &value))
+ config[index++] =
+ pinconf_to_config_packed(PIN_CONFIG_POWER_SOURCE,
+ value & 0xffff);
+ p++;
+ p->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ p->data.configs.group_or_pin = np->name;
+ p->data.configs.configs = config;
+ p->data.configs.num_configs = num_configs;
return 0;
+free_pingroup:
+ pcs_free_pingroups(pcs);
+
free_function:
pcs_remove_function(pcs, function);
@@ -790,6 +987,29 @@ free_vals:
return res;
}
+
+static int pcs_dt_check_maps(struct device_node *np, unsigned *num_maps,
+ unsigned *num_configs)
+{
+ unsigned size;
+
+ *num_maps = 0;
+ *num_configs = 0;
+ if (of_get_property(np, PCS_MUX_NAME, &size))
+ (*num_maps)++;
+ if (of_get_property(np, PCS_SCHMITT_NAME, &size))
+ (*num_configs)++;
+ if (of_get_property(np, PCS_BIAS_NAME, &size))
+ (*num_configs)++;
+ if (of_get_property(np, PCS_POWER_SOURCE_NAME, &size))
+ (*num_configs)++;
+ if (*num_configs)
+ (*num_maps)++;
+ if (!(*num_maps))
+ return -EINVAL;
+ return 0;
+}
+
/**
* pcs_dt_node_to_map() - allocates and parses pinctrl maps
* @pctldev: pinctrl instance
@@ -803,29 +1023,32 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
{
struct pcs_device *pcs;
const char **pgnames;
+ unsigned num_configs;
int ret;
pcs = pinctrl_dev_get_drvdata(pctldev);
- *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
+ ret = pcs_dt_check_maps(np_config, num_maps, &num_configs);
+ if (ret)
+ return ret;
+
+ *map = devm_kzalloc(pcs->dev, sizeof(**map) * (*num_maps), GFP_KERNEL);
if (!map)
return -ENOMEM;
- *num_maps = 0;
-
pgnames = devm_kzalloc(pcs->dev, sizeof(*pgnames), GFP_KERNEL);
if (!pgnames) {
ret = -ENOMEM;
goto free_map;
}
- ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames);
+ ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+ num_configs, pgnames);
if (ret < 0) {
dev_err(pcs->dev, "no pins entries for %s\n",
np_config->name);
goto free_pgnames;
}
- *num_maps = 1;
return 0;
@@ -1015,6 +1238,43 @@ static int __devinit pcs_probe(struct platform_device *pdev)
if (ret)
pcs->foff = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,power-source-mask",
+ &pcs->psmask);
+ if (ret)
+ pcs->psmask = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,power-source-shift",
+ &pcs->psshift);
+ if (ret)
+ pcs->psshift = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-mask",
+ &pcs->bmask);
+ if (ret)
+ pcs->bmask = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-shift",
+ &pcs->bshift);
+ if (ret)
+ pcs->bshift = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-disable",
+ &pcs->bdis);
+ if (ret)
+ pcs->bdis = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-pull-up",
+ &pcs->bpullup);
+ if (ret)
+ pcs->bpullup = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-pull-down",
+ &pcs->bpulldown);
+ if (ret)
+ pcs->bpulldown = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,input-schmitt-mask",
+ &pcs->ismask);
+ if (ret)
+ pcs->ismask = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,input-schmitt-shift",
+ &pcs->isshift);
+ if (ret)
+ pcs->isshift = PCS_OFF_DISABLED;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(pcs->dev, "could not get resource\n");
--
1.7.0.4
^ permalink raw reply related
* [PATCH 07/10] pinctrl: remove mutex lock in groups show
From: Haojian Zhuang @ 2012-10-18 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Mutex is locked duplicatly by pinconf_groups_show() and
pin_config_group_get(). It results dead lock. So avoid to lock mutex
in pinconf_groups_show().
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/pinconf.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index 43f474c..baee2cc 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -537,8 +537,6 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
seq_puts(s, "Pin config settings per pin group\n");
seq_puts(s, "Format: group (name): configs\n");
- mutex_lock(&pinctrl_mutex);
-
while (selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev, selector);
@@ -549,8 +547,6 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
selector++;
}
- mutex_unlock(&pinctrl_mutex);
-
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 06/10] pinctrl: single: support gpio request and free
From: Haojian Zhuang @ 2012-10-18 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Marvell's PXA/MMP silicon also match the behavior of pinctrl-single.
Each pin binds to one register. A lot of pins could be configured
as gpio.
Now add three properties in below.
pinctrl-single,gpio-mask: mask of enable/disable value of gpio
pinctrl-single,gpio-ranges: gpio range array
pinctrl-single,gpio: <gpio base, npins in range, pin base>
pinctrl-single,gpio-enable: <gpio enable register offset, enable
value>
pinctrl-single,gpio-disable: <gpio disable register offset, disable
value>
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/pinctrl-single.c | 140 +++++++++++++++++++++++++++++++++++++-
1 files changed, 138 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 64d109a..02cd412 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -29,6 +29,7 @@
#define PCS_MUX_NAME "pinctrl-single,pins"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_OFF_DISABLED ~0U
+#define PCS_MAX_GPIO_VALUES 3
/**
* struct pcs_pingroup - pingroups for a function
@@ -75,6 +76,26 @@ struct pcs_function {
};
/**
+ * struct pcs_gpio_range - pinctrl gpio range
+ * @range: subrange of the GPIO number space
+ * @reg_en: register of enabling gpio function
+ * @reg_dis: register of disabling gpio function
+ * @val_en: enable value on gpio function
+ * @val_dis: disable value on gpio function
+ * @need_en: need to handle enable value on gpio function
+ * @need_dis: need to handle disable value on gpio function
+ */
+struct pcs_gpio_range {
+ struct pinctrl_gpio_range range;
+ u32 reg_en;
+ u32 reg_dis;
+ int val_en;
+ int val_dis;
+ unsigned need_en:1;
+ unsigned need_dis:1;
+};
+
+/**
* struct pcs_data - wrapper for data needed by pinctrl framework
* @pa: pindesc array
* @cur: index to current element
@@ -115,14 +136,17 @@ struct pcs_name {
* @fshift: function register shift
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
+ * @gmask: gpio control mask
* @names: array of register names for pins
* @pins: physical pins on the SoC
* @pgtree: pingroup index radix tree
* @ftree: function index radix tree
* @pingroups: list of pingroups
* @functions: list of functions
+ * @ranges: list of gpio ranges
* @ngroups: number of pingroups
* @nfuncs: number of functions
+ * @nranges: number of gpio ranges
* @desc: pin controller descriptor
* @read: register read function to use
* @write: register write function to use
@@ -139,14 +163,17 @@ struct pcs_device {
unsigned fshift;
unsigned foff;
unsigned fmax;
+ unsigned gmask;
struct pcs_name *names;
struct pcs_data pins;
struct radix_tree_root pgtree;
struct radix_tree_root ftree;
struct list_head pingroups;
struct list_head functions;
+ struct list_head ranges;
unsigned ngroups;
unsigned nfuncs;
+ unsigned nranges;
struct pinctrl_desc desc;
unsigned (*read)(void __iomem *reg);
void (*write)(unsigned val, void __iomem *reg);
@@ -387,9 +414,48 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
}
static int pcs_request_gpio(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range, unsigned offset)
+ struct pinctrl_gpio_range *range, unsigned offset)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_gpio_range *gpio = NULL;
+ int end;
+ unsigned data;
+
+ gpio = container_of(range, struct pcs_gpio_range, range);
+ if (!gpio->need_en)
+ return 0;
+ end = range->pin_base + range->npins - 1;
+ if (offset < range->pin_base || offset > end) {
+ dev_err(pctldev->dev, "offset %d isn't in the range of "
+ "%d to %d\n", offset, range->pin_base, end);
+ return -EINVAL;
+ }
+ data = pcs_readl((void __iomem *)gpio->reg_en) & ~pcs->gmask;
+ data |= gpio->val_en;
+ pcs_writel(data, (void __iomem *)gpio->reg_en);
+ return 0;
+}
+
+static void pcs_disable_gpio(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_gpio_range *gpio = NULL;
+ int end;
+ unsigned data;
+
+ gpio = container_of(range, struct pcs_gpio_range, range);
+ if (!gpio->need_dis)
+ return;
+ end = range->pin_base + range->npins - 1;
+ if (offset < range->pin_base || offset > end) {
+ dev_err(pctldev->dev, "offset %d isn't in the range of "
+ "%d to %d\n", offset, range->pin_base, end);
+ return;
+ }
+ data = pcs_readl((void __iomem *)gpio->reg_dis) & ~pcs->gmask;
+ data |= gpio->val_dis;
+ pcs_writel(data, (void __iomem *)gpio->reg_dis);
}
static struct pinmux_ops pcs_pinmux_ops = {
@@ -399,6 +465,7 @@ static struct pinmux_ops pcs_pinmux_ops = {
.enable = pcs_enable,
.disable = pcs_disable,
.gpio_request_enable = pcs_request_gpio,
+ .gpio_disable_free = pcs_disable_gpio,
};
static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
@@ -848,6 +915,70 @@ static void pcs_free_resources(struct pcs_device *pcs)
static struct of_device_id pcs_of_match[];
+static int __devinit pcs_add_gpio_range(struct device_node *node,
+ struct pcs_device *pcs)
+{
+ struct pcs_gpio_range *gpio;
+ struct device_node *np;
+ const __be32 *list;
+ const char list_name[] = "pinctrl-single,gpio-ranges";
+ const char name[] = "pinctrl-single";
+ u32 gpiores[PCS_MAX_GPIO_VALUES];
+ int ret, size, i, mux_bytes = 0;
+
+ ret = of_property_read_u32(node, "pinctrl-single,gpio-mask",
+ &pcs->gmask);
+ if (ret < 0)
+ return 0;
+ list = of_get_property(node, list_name, &size);
+ if (!list)
+ return -ENOENT;
+ size = size / sizeof(*list);
+ for (i = 0; i < size; i++) {
+ np = of_parse_phandle(node, list_name, i);
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32_array(np, "pinctrl-single,gpio",
+ gpiores, PCS_MAX_GPIO_VALUES);
+ if (ret < 0)
+ return -ENOENT;
+ gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio) {
+ dev_err(pcs->dev, "failed to allocate pcs gpio\n");
+ return -ENOMEM;
+ }
+ gpio->range.id = i;
+ gpio->range.base = gpiores[0];
+ gpio->range.npins = gpiores[1];
+ gpio->range.name = kmemdup(name, sizeof(name), GFP_KERNEL);
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ gpio->range.pin_base = gpiores[2] / mux_bytes;
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32_array(np,
+ "pinctrl-single,gpio-enable", gpiores, 2);
+ if (!ret) {
+ gpio->reg_en = (u32)pcs->base + gpiores[0];
+ gpio->val_en = gpiores[1];
+ gpio->need_en = 1;
+ }
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32_array(np,
+ "pinctrl-single,gpio-disable", gpiores, 2);
+ if (!ret) {
+ gpio->reg_dis = (u32)pcs->base + gpiores[0];
+ gpio->val_dis = gpiores[1];
+ gpio->need_dis = 1;
+ }
+
+ mutex_lock(&pcs->mutex);
+ list_add_tail(&gpio->range.node, &pcs->ranges);
+ pcs->nranges++;
+ mutex_unlock(&pcs->mutex);
+
+ pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
+ }
+ return 0;
+}
+
static int __devinit pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -869,6 +1000,7 @@ static int __devinit pcs_probe(struct platform_device *pdev)
mutex_init(&pcs->mutex);
INIT_LIST_HEAD(&pcs->pingroups);
INIT_LIST_HEAD(&pcs->functions);
+ INIT_LIST_HEAD(&pcs->ranges);
PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
"register width not specified\n");
@@ -941,6 +1073,10 @@ static int __devinit pcs_probe(struct platform_device *pdev)
goto free;
}
+ ret = pcs_add_gpio_range(np, pcs);
+ if (ret < 0)
+ return ret;
+
dev_info(pcs->dev, "%i pins at pa %p size %u\n",
pcs->desc.npins, pcs->base, pcs->size);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 05/10] i2c: pxa: use devm_kzalloc
From: Haojian Zhuang @ 2012-10-18 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Use devm_kzalloc & add checking in probe() function.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/i2c/busses/i2c-pxa.c | 26 ++++++++++----------------
1 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index cd66ec2..5f96310 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1083,6 +1083,8 @@ static int i2c_pxa_probe_pdata(struct platform_device *pdev,
struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
const struct platform_device_id *id = platform_get_device_id(pdev);
+ if (!id)
+ return -EINVAL;
*i2c_types = id->driver_data;
if (plat) {
i2c->use_pio = plat->use_pio;
@@ -1099,29 +1101,23 @@ static int i2c_pxa_probe(struct platform_device *dev)
struct resource *res = NULL;
int ret, irq;
- i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
- if (!i2c) {
- ret = -ENOMEM;
- goto emalloc;
- }
+ i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
if (ret > 0)
ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
if (ret < 0)
- goto eclk;
+ return ret;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
irq = platform_get_irq(dev, 0);
- if (res == NULL || irq < 0) {
- ret = -ENODEV;
- goto eclk;
- }
+ if (res == NULL || irq < 0)
+ return -ENODEV;
- if (!request_mem_region(res->start, resource_size(res), res->name)) {
- ret = -ENOMEM;
- goto eclk;
- }
+ if (!request_mem_region(res->start, resource_size(res), res->name))
+ return -ENOMEM;
i2c->adap.owner = THIS_MODULE;
i2c->adap.retries = 5;
@@ -1214,8 +1210,6 @@ ereqirq:
eremap:
clk_put(i2c->clk);
eclk:
- kfree(i2c);
-emalloc:
release_mem_region(res->start, resource_size(res));
return ret;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 04/10] i2c: pxa: configure pins
From: Haojian Zhuang @ 2012-10-18 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Configure pins by pinctrl driver.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/i2c/busses/i2c-pxa.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 1034d93..cd66ec2 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -32,6 +32,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -1051,6 +1052,7 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
enum pxa_i2c_types *i2c_types)
{
struct device_node *np = pdev->dev.of_node;
+ struct pinctrl *pinctrl;
const struct of_device_id *of_id =
of_match_device(i2c_pxa_dt_ids, &pdev->dev);
int ret;
@@ -1063,6 +1065,9 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
return ret;
}
pdev->id = ret;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return 1;
if (of_get_property(np, "mrvl,i2c-polling", NULL))
i2c->use_pio = 1;
if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
--
1.7.0.4
^ permalink raw reply related
* [PATCH 03/10] tty: pxa: configure pin
From: Haojian Zhuang @ 2012-10-18 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Configure pins by pinctrl driver.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/tty/serial/pxa.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 5847a4b..ee6118a 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -795,6 +796,7 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
struct uart_pxa_port *sport)
{
struct device_node *np = pdev->dev.of_node;
+ struct pinctrl *pinctrl;
int ret;
if (!np)
@@ -805,6 +807,12 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return ret;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ return ret;
+ }
+
sport->port.line = ret;
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 02/10] ARM: mmp: select pinctrl driver
From: Haojian Zhuang @ 2012-10-18 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350551224-12857-1-git-send-email-haojian.zhuang@gmail.com>
Pinctrl driver is necessary for MMP DT & MMP2 DT platforms.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
arch/arm/mach-mmp/Kconfig | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 7fddd01..c70c787 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -89,6 +89,7 @@ config MACH_MMP_DT
select CPU_PXA168
select CPU_PXA910
select USE_OF
+ select PINCTRL
help
Include support for Marvell MMP2 based platforms using
the device tree. Needn't select any other machine while
@@ -99,6 +100,7 @@ config MACH_MMP2_DT
depends on !CPU_MOHAWK
select CPU_MMP2
select USE_OF
+ select PINCTRL
help
Include support for Marvell MMP2 based platforms using
the device tree.
--
1.7.0.4
^ permalink raw reply related
* [PATCH 01/10] pinctrl: use postcore_initcall
From: Haojian Zhuang @ 2012-10-18 9:06 UTC (permalink / raw)
To: linux-arm-kernel
Since pins are configured in device driver, pinctrl driver should be
loaded by those device driver. module_platform_driver() only declares
pinctrl driver is in module_initcall privilege. Use postcore_initcall
privilege instead.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/pinctrl-single.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 76a4260..64d109a 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -980,7 +980,17 @@ static struct platform_driver pcs_driver = {
},
};
-module_platform_driver(pcs_driver);
+static int __init pcs_driver_init(void)
+{
+ return platform_driver_register(&pcs_driver);
+}
+postcore_initcall(pcs_driver_init);
+
+static void __exit pcs_driver_exit(void)
+{
+ platform_driver_unregister(&pcs_driver);
+}
+module_exit(pcs_driver_exit);
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
MODULE_DESCRIPTION("One-register-per-pin type device tree based pinctrl driver");
--
1.7.0.4
^ permalink raw reply related
* [PATCH] dma: add new DMA control commands
From: Russell King - ARM Linux @ 2012-10-18 8:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <507FA595.4020507@freescale.com>
On Thu, Oct 18, 2012 at 02:45:41PM +0800, Huang Shijie wrote:
> ? 2012?10?18? 14:18, Vinod Koul ??:
>> Why cant you do start (prepare clock etc) when you submit the descriptor
>> to dmaengine. Can be done in tx_submit callback.
>> Similarly remove the clock when dma transaction gets completed.
> I ever thought this method too.
>
> But it will become low efficient in the following case:
>
> Assuming the gpmi-nand driver has to read out 1024 pages in one
> _SINGLE_ read operation.
> The gpmi-nand will submit the descriptor to dmaengine per page. So with
> your method,
> the system will repeat the enable/disable dma clock 1024 time. At every
> enable/disable dma clock,
> the system has to enable the clock chain and it's parents ...
And what if you stop using clk_prepare_enable(), and prepare the clock
when the channel is requested and only use clk_enable() in the tx_submit
method?
^ permalink raw reply
* [PATCH] dma: add new DMA control commands
From: Marek Vasut @ 2012-10-18 8:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <507FC290.10205@freescale.com>
Dear Huang Shijie,
> ? 2012?10?18? 16:16, Marek Vasut ??:
> > So we can't stream data from the chip? About time to adjust the MTD
> > framework to allow that. Maybe implement a command queue?
>
> IMHO, it's not possible. Because the READ-PAGE(00h-30h) command needs to
> check the busy status
> which means we have to stop in the middle, so we can not chain the all
> the read-pages DMA commands.
Can the DMA not branch?
> thanks
> Huang Shijie
Best regards,
Marek Vasut
^ permalink raw reply
* [PATCH] dma: add new DMA control commands
From: Huang Shijie @ 2012-10-18 8:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201210181016.06782.marex@denx.de>
? 2012?10?18? 16:16, Marek Vasut ??:
> So we can't stream data from the chip? About time to adjust the MTD framework to
> allow that. Maybe implement a command queue?
>
IMHO, it's not possible. Because the READ-PAGE(00h-30h) command needs to
check the busy status
which means we have to stop in the middle, so we can not chain the all
the read-pages DMA commands.
thanks
Huang Shijie
^ permalink raw reply
* OMAP baseline test results for v3.7-rc1
From: Santosh Shilimkar @ 2012-10-18 8:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350549436.2143.47.camel@sokoban>
Tero, paul,
On Thursday 18 October 2012 02:07 PM, Tero Kristo wrote:
> On Thu, 2012-10-18 at 06:48 +0000, Paul Walmsley wrote:
>> On Thu, 18 Oct 2012, Paul Walmsley wrote:
>>
>>> Here are some basic OMAP test results for Linux v3.7-rc1.
>>> Logs and other details at http://www.pwsan.com/omap/testlogs/test_v3.7-rc1/
>>
>> A few additional observations missing from the original message.
>>
>>> Failing tests: needing investigation
>>> ------------------------------------
>>>
>>> Boot tests:
>>>
>>> * 2420n800: boot hangs during UART initialization
>>> - http://lkml.org/lkml/2012/9/11/454
>>> - Various attempts at fixes posted; etiology known; issue still unresolved
>>>
>>> * CM-T3517: L3 in-band error with IPSS during boot
>>> - Cause unknown but see http://marc.info/?l=linux-omap&m=134833869730129&w=2
>>> - Longstanding issue; does not occur on the 3517EVM
>>>
>>> * 3517EVM & CM-T3517: boot hangs with NFS root
>>> - Likely some Kconfig, board file, and PM issues with EMAC
>>>
>>> * CM-T3517: boot hangs with MMC boot
>>> - Due to missing MMC setup in board file
>>
>> * 4430es2panda: clockevents problems early in boot
>> - boots with dummy_timer
>> - no one-shot mode so no-HZ is likely to fail
>
> I have a fix for this problem, however I am seeing this on omap4460
> panda. The root cause seems to be that local timer init for OMAP is
> using wrong interrupt number. It adds a wrong offset to the interrupt
> (OMAP_INTC_START) which should be omitted. Will send a patch soon along
> with a new version of core ret set.
>
This one is already fixed by [1] and Tony has sent pull request[1] to
arm-soc maintainers for 3.7-rc1 which includes the fix.
regards
santosh
[1] https://patchwork.kernel.org/patch/1587621/
[2] http://www.mail-archive.com/linux-omap at vger.kernel.org/msg78045.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox