* [PATCH] ARM: setup_mm_for_reboot(): use flush_cache_louis()
From: Will Deacon @ 2012-11-07 18:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1211071035220.21033@xanadu.home>
On Wed, Nov 07, 2012 at 06:03:40PM +0000, Nicolas Pitre wrote:
> On Wed, 7 Nov 2012, Will Deacon wrote:
> > On Wed, Nov 07, 2012 at 09:56:35AM +0000, Russell King - ARM Linux wrote:
> > > On Wed, Nov 07, 2012 at 09:51:06AM +0000, Will Deacon wrote:
> > > > Wouldn't the L2 flush in this case be included with the code that turns off
> > > > caching? For reboot, that's currently done in __sort_restart -- the cache
> > > > flush in setup_mm_for_reboot is just to ensure that the idmap tables are
> > > > visible to the hardware walker iirc.
> > >
> > > Good point - but it does raise another issue. Why do we do this flush and
> > > TLB invalidate afterwards in setup_mm_for_reboot() ? It makes sense if
> > > we change existing page tables, but we don't anymore, we're just switching
> > > them, and cpu_switch_mm() will do whatever's necessary to make the new
> > > page tables visible. So I think we can get rid of that flusing in there.
> >
> > Hmm, I'm not sure about that. Looking at cpu_v7_switch_mm (the 2-level
> > version) for example, we set the ASID and then set the new TTBR. There's no
> > flushing of page tables like we get in set_pte and no TLB flushing either.
> >
> > Now, given that the idmap_pgd is populated as an early_initcall, I really
> > doubt we need that flush_cache_all but the TLB invalidate is surely
> > required?
>
> Why wouldn't cpu_switch_mm() take care of that already if that is
> necessary? Hmmm, I suppose the asid of the init task isn't associated
> with the idmap in any way, hence the need for flushing the tlbs.
Yes, cpu_switch_mm can't know about whether tables are visible or an ASID is
dirty so all it can do is defer that to the caller or do the cleaning and
invalidation every time.
> I'd not rely on the early_initcall to assume the new page table is moved
> out of the cache though.
Yeah, it's not nice, I was just pointing out that it's all hanging off an
initcall now (before it was created ad-hoc by its users).
> What about this alternate patch:
>
> diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
> index ab88ed4f8e..1ab429761c 100644
> --- a/arch/arm/mm/idmap.c
> +++ b/arch/arm/mm/idmap.c
> @@ -92,6 +92,9 @@ static int __init init_static_idmap(void)
> (long long)idmap_start, (long long)idmap_end);
> identity_mapping_add(idmap_pgd, idmap_start, idmap_end);
>
> + /* Flush L1 for the hardware to see this page table content */
> + flush_cache_louis();
> +
> return 0;
> }
Yep, we can do this now. Good thinking! At some point I'll get around to
making this conditional, as I don't think it's needed on A5, A7, A9 or A15.
> early_initcall(init_static_idmap);
> @@ -103,12 +106,12 @@ early_initcall(init_static_idmap);
> */
> void setup_mm_for_reboot(void)
> {
> - /* Clean and invalidate L1. */
> - flush_cache_all();
> -
> /* Switch to the identity mapping. */
> cpu_switch_mm(idmap_pgd, &init_mm);
>
> - /* Flush the TLB. */
> + /*
> + * On ARMv7, the ASID of the init task is not associated with
> + * this mapping. TLBs must be flushed.
> + */
> local_flush_tlb_all();
> }
Can we change this comment slightly please? Basically, we don't have a clean
ASID for the identity mapping, which may clash with virtual addresses of the
previous page tables and therefore potentially in the TLB. That's why
we need the invalidation: so that we don't hit stale entries from before.
Other than that, looks good to me:
Acked-by: Will Deacon <will.deacon@arm.com>
Cheers,
Will
^ permalink raw reply
* [PATCH 0/3] ARM: OMAP4: Clock fixes
From: Jon Hunter @ 2012-11-07 18:42 UTC (permalink / raw)
To: linux-arm-kernel
Fixes included, fixing up timer clock aliases for v3.8 and working
around ABE DPLL issue seen with latest u-boot bootloader (v2012.10).
Testing includes:
- Boot testing on OMAP3430 Beagle, OMAP4430 Panda and OMAP4460 Panda
- Boot tested with device-tree on OMAP4430 Panda and OMAP4460 Panda
and validated that all timers are working.
- Suspend testing on OMAP3430 Beagle and OMAP4430 Panda (suspend not
functional on OMAP4460 Panda prior to this series and so could not
be tested).
- Core retention validated on OMAP3430 Beagle.
Jon Hunter (3):
ARM: OMAP4: Update timer clock aliases
ARM: OMAP4: Enhance support for DPLLs with 4X multiplier
ARM: OMAP4460: Workaround ABE DPLL failing to turn-on
arch/arm/mach-omap2/clock44xx_data.c | 32 ++++++++++++++--
arch/arm/mach-omap2/dpll3xxx.c | 46 +++++++++++++++-------
arch/arm/mach-omap2/dpll44xx.c | 63 ++++++++++++++++++++++++++-----
arch/arm/plat-omap/include/plat/clock.h | 10 +++++
4 files changed, 124 insertions(+), 27 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH 1/3] ARM: OMAP4: Update timer clock aliases
From: Jon Hunter @ 2012-11-07 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352313782-21602-1-git-send-email-jon-hunter@ti.com>
Commit "ARM: dts: OMAP4: Update timer addresses" updated the device-tree
names of the OMAP4 timers 5-7 because the default address for the timers
was changed from the L3 address to the MPU private address. When booting
with device-tree, this introduces a regression when attempting to set
the parent clock of timers 5-7 to the sys_clk_div_ck. Therefore, update
the clock aliases for timer 5-7 to reflect the updated device-tree name
for the timers.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
This change is needed for v3.8 as the patch [1] to update the default
timer addresses is queued for that release.
[1] http://marc.info/?l=linux-omap&m=135178500008690&w=2
arch/arm/mach-omap2/clock44xx_data.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 6efc30c..8f197eb 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3341,10 +3341,10 @@ static struct omap_clk omap44xx_clks[] = {
CLK("4803e000.timer", "timer_sys_ck", &sys_clkin_ck, CK_443X),
CLK("48086000.timer", "timer_sys_ck", &sys_clkin_ck, CK_443X),
CLK("48088000.timer", "timer_sys_ck", &sys_clkin_ck, CK_443X),
- CLK("49038000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
- CLK("4903a000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
- CLK("4903c000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
- CLK("4903e000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
+ CLK("40138000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
+ CLK("4013a000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
+ CLK("4013c000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
+ CLK("4013e000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
CLK(NULL, "cpufreq_ck", &dpll_mpu_ck, CK_443X),
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/3] ARM: OMAP4: Enhance support for DPLLs with 4X multiplier
From: Jon Hunter @ 2012-11-07 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352313782-21602-1-git-send-email-jon-hunter@ti.com>
On OMAP4 devices, the ABE DPLL has an internal 4X multiplier that can
be enabled or disabled in addition to the standard configurable
multiplier (M) for OMAP DPLLs. When configuring the ABE DPLL the 4X
multiplier is accounted for by checking to see whether it is enabled or
not. However, when calculating a new rate we only check to see if the
rate can be achieved with the current setting for the 4X multiplier.
Enhance the round_rate() function for such DPLLs to see if the rate
can be achieved with the 4X multiplier if it cannot be achieved without
the 4X multiplier.
This change is necessary, because when using the 32kHz clock as the
source clock for the ABE DPLL, the default DPLL frequency for the ABE
DPLL cannot be achieved without enabling the 4X multiplier.
When using the 32kHz clock as the source clock for the ABE DPLL and
attempting to lock the DPLL to 98.304MHz (default frequency), it was
found that the DPLL would fail to lock if the low-power mode for the DPLL
was not enabled. From reviewing boot-loader settings that configure the
ABE DPLL it was found that the low-power mode is enabled when using the
32kHz clock source, however, the documentation for OMAP does not state
that this is a requirement. Therefore, introduce a new function for
OMAP4 devices to see if low-power mode can be enabled when calculating a
new rate to ensure the DPLL will lock.
New variables for the last calculated 4X multiplier and low-power
setting have been added to the dpll data structure as well as variables
defining the bit mask for enabling these features via the DPLL's
control_reg. It is possible that we could eliminate these bit masks from
the dpll data structure as these bit masks are not unique to OMAP4, if
it is preferred.
The function omap3_noncore_program_dpll() has been updated to avoid
passing the calculated values for the multiplier (M) and divider (N) as
these are stored in the clk structure.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/clock44xx_data.c | 2 +
arch/arm/mach-omap2/dpll3xxx.c | 46 +++++++++++++++-------
arch/arm/mach-omap2/dpll44xx.c | 63 ++++++++++++++++++++++++++-----
arch/arm/plat-omap/include/plat/clock.h | 10 +++++
4 files changed, 98 insertions(+), 23 deletions(-)
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 8f197eb..8a9cbad 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -226,6 +226,8 @@ static struct dpll_data dpll_abe_dd = {
.enable_mask = OMAP4430_DPLL_EN_MASK,
.autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK,
.idlest_mask = OMAP4430_ST_DPLL_CLK_MASK,
+ .m4xen_mask = OMAP4430_DPLL_REGM4XEN_MASK,
+ .lpmode_mask = OMAP4430_DPLL_LPMODE_EN_MASK,
.max_multiplier = 2047,
.max_divider = 128,
.min_divider = 1,
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index 814e180..8a0259e 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -17,7 +17,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
@@ -292,15 +291,13 @@ static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n)
/*
* _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
- * @clk: struct clk * of DPLL to set
- * @m: DPLL multiplier to set
- * @n: DPLL divider to set
- * @freqsel: FREQSEL value to set
+ * @clk: struct clk * of DPLL to set
+ * @freqsel: FREQSEL value to set
*
- * Program the DPLL with the supplied M, N values, and wait for the DPLL to
- * lock.. Returns -EINVAL upon error, or 0 upon success.
+ * Program the DPLL with the last M, N values calculated, and wait for
+ * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
*/
-static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
+static int omap3_noncore_dpll_program(struct clk *clk, u16 freqsel)
{
struct dpll_data *dd = clk->dpll_data;
u8 dco, sd_div;
@@ -323,23 +320,45 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
/* Set DPLL multiplier, divider */
v = __raw_readl(dd->mult_div1_reg);
v &= ~(dd->mult_mask | dd->div1_mask);
- v |= m << __ffs(dd->mult_mask);
- v |= (n - 1) << __ffs(dd->div1_mask);
+ v |= dd->last_rounded_m << __ffs(dd->mult_mask);
+ v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
/* Configure dco and sd_div for dplls that have these fields */
if (dd->dco_mask) {
- _lookup_dco(clk, &dco, m, n);
+ _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
v &= ~(dd->dco_mask);
v |= dco << __ffs(dd->dco_mask);
}
if (dd->sddiv_mask) {
- _lookup_sddiv(clk, &sd_div, m, n);
+ _lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
+ dd->last_rounded_n);
v &= ~(dd->sddiv_mask);
v |= sd_div << __ffs(dd->sddiv_mask);
}
__raw_writel(v, dd->mult_div1_reg);
+ /* Set 4X multiplier and low-power mode */
+ if (dd->m4xen_mask || dd->lpmode_mask) {
+ v = __raw_readl(dd->control_reg);
+
+ if (dd->m4xen_mask) {
+ if (dd->last_rounded_m4xen)
+ v |= dd->m4xen_mask;
+ else
+ v &= ~dd->m4xen_mask;
+ }
+
+ if (dd->lpmode_mask) {
+ if (dd->last_rounded_lpmode)
+ v |= dd->lpmode_mask;
+ else
+ v &= ~dd->lpmode_mask;
+ }
+
+ __raw_writel(v, dd->control_reg);
+ }
+
/* We let the clock framework set the other output dividers later */
/* REVISIT: Set ramp-up delay? */
@@ -487,8 +506,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
pr_debug("clock: %s: set rate: locking rate to %lu.\n",
__clk_get_name(clk), rate);
- ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
- dd->last_rounded_n, freqsel);
+ ret = omap3_noncore_dpll_program(clk, freqsel);
if (!ret)
new_parent = dd->clk_ref;
}
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index 09d0ccc..8c40780 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -22,6 +22,15 @@
#include "clock44xx.h"
#include "cm-regbits-44xx.h"
+/*
+ * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that
+ * can supported when using the DPLL low-power mode. Frequencies are
+ * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control,
+ * Status, and Low-Power Operation Mode".
+ */
+#define OMAP4_DPLL_LP_FINT_MAX 1000000
+#define OMAP4_DPLL_LP_FOUT_MAX 100000000
+
/* Supported only on OMAP4 */
int omap4_dpllmx_gatectrl_read(struct clk *clk)
{
@@ -84,6 +93,31 @@ const struct clkops clkops_omap4_dpllmx_ops = {
};
/**
+ * omap4_dpll_lpmode_recalc - compute DPLL low-power setting
+ * @dd: pointer to the dpll data structure
+ *
+ * Calculates if low-power mode can be enabled based upon the last
+ * multiplier and divider values calculated. If low-power mode can be
+ * enabled, then the bit to enable low-power mode is stored in the
+ * last_rounded_lpmode variable. This implementation is based upon the
+ * criteria for enabling low-power mode as described in the OMAP4430/60
+ * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power
+ * Operation Mode".
+ */
+static void omap4_dpll_lpmode_recalc(struct dpll_data *dd)
+{
+ long fint, fout;
+
+ fint = __clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1);
+ fout = fint * dd->last_rounded_m;
+
+ if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX))
+ dd->last_rounded_lpmode = 1;
+ else
+ dd->last_rounded_lpmode = 0;
+}
+
+/**
* omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
* @clk: struct clk * of the DPLL to compute the rate for
*
@@ -127,7 +161,6 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk)
*/
long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate)
{
- u32 v;
struct dpll_data *dd;
long r;
@@ -136,18 +169,30 @@ long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate)
dd = clk->dpll_data;
- /* regm4xen adds a multiplier of 4 to DPLL calculations */
- v = __raw_readl(dd->control_reg) & OMAP4430_DPLL_REGM4XEN_MASK;
-
- if (v)
- target_rate = target_rate / OMAP4430_REGM4XEN_MULT;
+ dd->last_rounded_m4xen = 0;
+ /*
+ * First try to compute the DPLL configuration for
+ * target rate without using the 4X multiplier.
+ */
r = omap2_dpll_round_rate(clk, target_rate);
+ if (r != ~0)
+ goto out;
+
+ /*
+ * If we did not find a valid DPLL configuration, try again, but
+ * this time see if using the 4X multiplier can help. Enabling the
+ * 4X multiplier is equivalent to dividing the target rate by 4.
+ */
+ r = omap2_dpll_round_rate(clk, target_rate / OMAP4430_REGM4XEN_MULT);
if (r == ~0)
return r;
- if (v)
- clk->dpll_data->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
+ dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
+ dd->last_rounded_m4xen = 1;
+
+out:
+ omap4_dpll_lpmode_recalc(dd);
- return clk->dpll_data->last_rounded_rate;
+ return dd->last_rounded_rate;
}
diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index e2e2d04..16654a3 100644
--- a/arch/arm/plat-omap/include/plat/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
@@ -118,6 +118,10 @@ struct clksel {
* @enable_mask: mask of the DPLL mode bitfield in @control_reg
* @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
* @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
+ * @last_rounded_m4xen: cache of the last M4X result of
+ * omap4_dpll_regm4xen_round_rate()
+ * @last_rounded_lpmode: cache of the last lpmode result of
+ * omap4_dpll_lpmode_recalc()
* @max_multiplier: maximum valid non-bypass multiplier value (actual)
* @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
* @min_divider: minimum valid non-bypass divider value (actual)
@@ -128,6 +132,8 @@ struct clksel {
* @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg
* @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg
* @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg
+ * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg
+ * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg
* @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg
* @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs
* @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs
@@ -156,6 +162,8 @@ struct dpll_data {
u32 enable_mask;
unsigned long last_rounded_rate;
u16 last_rounded_m;
+ u8 last_rounded_m4xen;
+ u8 last_rounded_lpmode;
u16 max_multiplier;
u8 last_rounded_n;
u8 min_divider;
@@ -168,6 +176,8 @@ struct dpll_data {
u32 idlest_mask;
u32 dco_mask;
u32 sddiv_mask;
+ u32 lpmode_mask;
+ u32 m4xen_mask;
u8 auto_recal_bit;
u8 recal_en_bit;
u8 recal_st_bit;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/3] ARM: OMAP4460: Workaround ABE DPLL failing to turn-on
From: Jon Hunter @ 2012-11-07 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352313782-21602-1-git-send-email-jon-hunter@ti.com>
With the latest mainline u-boot bootloader (v2012.10), timers (5-8) in
the ABE power domain are failing to turn-on. The timers never come out
of the disabled state when setting the module-mode field to enable.
The problem was exposed when u-boot was updated to NOT configure and
lock the ABE DPLL on start-up. If the ABE DPLL is configured and locked
by u-boot the problem does not occur. However, if the ABE DPLL is in the
idle low-power bypass state and we attempt to enable a timer in the ABE
power domain, it remains stuck in the disabled state. It appears to be a
problem the timer interface clock as this comes from the ABE DPLL.
If we place the ABE DPLL in the MN-bypass state and not the idle
low-power state, then this problem is not seen.
This problem only appears to occur on OMAP4460 and not OMAP4430.
Workaround this problem by locking the ABE DPLL for OMAP4460 in the
kernel on boot. By locking the ABE DPLL, when clocks from the ABE DPLL
are not being requested the DPLL will transition into a low-power stop
mode.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/clock44xx_data.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 8a9cbad..1844661 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -46,6 +46,14 @@
#define OMAP4430_MODULEMODE_HWCTRL 0
#define OMAP4430_MODULEMODE_SWCTRL 1
+/*
+ * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
+ * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
+ * must be set to 196.608 MHz" and hence, the DPLL locked frequency is
+ * half of this value.
+ */
+#define OMAP4_DPLL_ABE_DEFFREQ 98304000
+
/* Root clocks */
static struct clk extalt_clkin_ck = {
@@ -3354,6 +3362,7 @@ int __init omap4xxx_clk_init(void)
{
struct omap_clk *c;
u32 cpu_clkflg;
+ int rc;
if (cpu_is_omap443x()) {
cpu_mask = RATE_IN_4430;
@@ -3400,5 +3409,18 @@ int __init omap4xxx_clk_init(void)
*/
clk_enable_init_clocks();
+ /*
+ * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
+ * state when turning the ABE clock domain. Workaround this by
+ * locking the ABE DPLL on boot.
+ */
+ if (cpu_is_omap446x()) {
+ rc = clk_set_parent(&abe_dpll_refclk_mux_ck, &sys_32k_ck);
+ if (!rc)
+ rc = clk_set_rate(&dpll_abe_ck, OMAP4_DPLL_ABE_DEFFREQ);
+ if (rc)
+ pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+ }
+
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
From: Rajanikanth H V @ 2012-11-07 18:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <509291FF.6090500@gmail.com>
On Thu, 1 Nov 2012, Francesco Lavra wrote:
[...]
>> + btech = of_get_property(np_bat_supply,
>> + "stericsson,battery-type", NULL);
>> + if (!btech) {
>> + dev_warn(dev, "missing property battery-name/type\n");
>> + strcpy(bat_tech, "UNKNOWN");
>> + } else {
>> + strcpy(bat_tech, btech);
>> + }
>
> I don't get the point of declaring the char array and copying the string
> in it, when you could simply use just the pointer returned by
> of_get_property().
I am considering a corner case where in 'battery-type' property is not
present and battery is connected.In this case i promote battery to
UNKNOWN from null.
FYI: Further, btemp driver will identify the connected battery based on
resistance value and decide to use.
Ref: ab8500_btemp_id(...) ab8500_btemp.c
> Anyway, if the string property is longer than 8 characters, you are
> writing past the size of the destination array.
i believe it is safe as power_supply.h comprises defines having battery
technology type in 4 characters length which is normally the case and
7 chars length being "UNKNOWN" seldom referred
^ permalink raw reply
* [PATCH V2 00/14] ARM: OMAP: DMTIMER fixes
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
This series includes several fixes for the OMAP DMTIMER driver. This is
based upon 3.7-rc4 with the two series adding device-tree support for
DMTIMERs [1] and the 32kHz Counter [2]
Tested on OMAP5912 OSK, OMAP2420 H4, OMAP3430 Beagle and OMAP4430 Panda.
Testing includes ...
1. Booting kernel on above boards
2. Set date and ensuring time of day is correct after 24 hours
3. Checking the timer counter is incrementing when configuring and starting
a timer
4. Checking the timer overflow interrupt when timer expires.
5. Using different clock sources to operate the timer with.
6. Running a loop test overnight that continually runs test #3 and #4 for
each available timer
This has also been boot tested on the AM335x Beagle Bone.
[1] http://marc.info/?l=linux-omap&m=135065875808614&w=2
[2] http://marc.info/?l=linux-omap&m=135119308123513&w=2
Jon Hunter (14):
ARM: OMAP: Add DMTIMER definitions for posted mode
ARM: OMAP2+: Disable posted mode for the clocksource timer
ARM: OMAP3+: Implement timer workaround for errata i103 and i767
ARM: OMAP: Fix timer posted mode support
ARM: OMAP3: Correct HWMOD DMTIMER SYSC register declarations
ARM: OMAP2/3: Define HWMOD software reset status for DMTIMERs
ARM: OMAP2+: Don't use __omap_dm_timer_reset()
ARM: OMAP: Fix dmtimer reset for timer1
ARM: OMAP: Don't restore of DMTIMER TISTAT register
ARM: OMAP: Don't restore DMTIMER interrupt status register
ARM: OMAP: Fix spurious interrupts when using timer match feature
ARM: OMAP: Add dmtimer interrupt disable function
ARM: OMAP: Remove unnecessary call to clk_get()
ARM: OMAP: Remove __omap_dm_timer_set_source function
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 15 ++-
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 41 +++---
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 +
arch/arm/mach-omap2/timer.c | 73 ++++++++---
arch/arm/plat-omap/dmtimer.c | 132 +++++++++++++++-----
arch/arm/plat-omap/include/plat/dmtimer.h | 47 ++++---
6 files changed, 215 insertions(+), 97 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH V2 01/14] ARM: OMAP: Add DMTIMER definitions for posted mode
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
For OMAP2+ devices, when using DMTIMERs for system timers (clock-events and
clock-source) the posted mode configuration of the timers is used. To allow
the compiler to optimise the functions for configuring and reading the system
timers, the posted flag variable is hard-coded with the value 1. To make it
clear that posted mode is being used add some definitions so that it is more
readable.
Add separate definitions for the clock-events and clock-source timers so that
we can change the posted mode of clock-events and clock-source independently.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/timer.c | 26 +++++++++++++++++++-------
arch/arm/plat-omap/include/plat/dmtimer.h | 4 ++++
2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 0758bae..28c6078 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -82,6 +82,13 @@
#define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14
#define NUMERATOR_DENUMERATOR_MASK 0xfffff000
+/*
+ * For clock-events timer, always use posted mode to
+ * minimise CPU overhead for configuring the timer.
+ */
+#define OMAP_CLKEVT_POSTEDMODE OMAP_TIMER_POSTED
+#define OMAP_CLKSRC_POSTEDMODE OMAP_TIMER_POSTED
+
/* Clockevent code */
static struct omap_dm_timer clkev;
@@ -107,7 +114,7 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
__omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
- 0xffffffff - cycles, 1);
+ 0xffffffff - cycles, OMAP_CLKEVT_POSTEDMODE);
return 0;
}
@@ -117,7 +124,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
{
u32 period;
- __omap_dm_timer_stop(&clkev, 1, clkev.rate);
+ __omap_dm_timer_stop(&clkev, OMAP_CLKEVT_POSTEDMODE, clkev.rate);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
@@ -125,10 +132,12 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
period -= 1;
/* Looks like we need to first set the load value separately */
__omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
- 0xffffffff - period, 1);
+ 0xffffffff - period,
+ OMAP_CLKEVT_POSTEDMODE);
__omap_dm_timer_load_start(&clkev,
OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
- 0xffffffff - period, 1);
+ 0xffffffff - period,
+ OMAP_CLKEVT_POSTEDMODE);
break;
case CLOCK_EVT_MODE_ONESHOT:
break;
@@ -358,7 +367,8 @@ static bool use_gptimer_clksrc;
*/
static cycle_t clocksource_read_cycles(struct clocksource *cs)
{
- return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
+ return (cycle_t)__omap_dm_timer_read_counter(&clksrc,
+ OMAP_CLKSRC_POSTEDMODE);
}
static struct clocksource clocksource_gpt = {
@@ -372,7 +382,8 @@ static struct clocksource clocksource_gpt = {
static u32 notrace dmtimer_read_sched_clock(void)
{
if (clksrc.reserved)
- return __omap_dm_timer_read_counter(&clksrc, 1);
+ return __omap_dm_timer_read_counter(&clksrc,
+ OMAP_CLKSRC_POSTEDMODE);
return 0;
}
@@ -454,7 +465,8 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
BUG_ON(res);
__omap_dm_timer_load_start(&clksrc,
- OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+ OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0,
+ OMAP_CLKSRC_POSTEDMODE);
setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 348f855..835c3bdf 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -55,6 +55,10 @@
#define OMAP_TIMER_TRIGGER_OVERFLOW 0x01
#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
+/* posted mode types */
+#define OMAP_TIMER_NONPOSTED 0x00
+#define OMAP_TIMER_POSTED 0x01
+
/* timer capabilities used in hwmod database */
#define OMAP_TIMER_SECURE 0x80000000
#define OMAP_TIMER_ALWON 0x40000000
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 02/14] ARM: OMAP2+: Disable posted mode for the clocksource timer
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
When using a DMTIMER as the clock-source timer, posted mode configuration of
the DMTIMER is used. Posted mode is only benefical when configuring timers as
it allows writes to be posted and does not stall the CPU until the write is
complete. The clock-source timer is only configured once on boot and so using
posted mode has no benefit. In fact, by using posted mode, it adds overhead
to reading the timer. Therefore, by default disable posted mode for DMTIMERs
used for clock-source.
Using objdump this change reduces the function clocksource_read_cycles()
function from a total of 15 instructions (including 3 branches and 7 loads)
to 5 instructions (including 1 branch and 3 loads). Please note that before
the minimum number of instructions that would be executed when calling
clocksource_read_cycles() would be 9 instructions (including 2 branches and 5
loads) where as now it will always be 5 instructions.
This change also reduces the function dmtimer_read_sched_clock() function from
a total of 17 instructions (including 4 branches and 8 loads) to 6 instructions
(including 1 branch and 4 loads). Please note that before the minimum number of
instructions that would be executed when calling dmtimer_read_sched_clock()
would be 11 instructions (including 2 branches and 6 loads) where as now it
will always be 6 instructions.
This change removes the configuration of posted mode from the
__omap_dm_timer_reset() function and adds a new function called
omap_dm_timer_enable_posted() for enabling posted mode. Hence, call
omap_dm_timer_enable_posted() where ever we are calling __omap_dm_timer_reset().
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/timer.c | 28 ++++++++++++++++++++--------
arch/arm/plat-omap/dmtimer.c | 23 ++++++++++++++++++++++-
arch/arm/plat-omap/include/plat/dmtimer.h | 5 +----
3 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 28c6078..78b7712 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -83,11 +83,19 @@
#define NUMERATOR_DENUMERATOR_MASK 0xfffff000
/*
- * For clock-events timer, always use posted mode to
- * minimise CPU overhead for configuring the timer.
+ * For the clock-events timer, always use posted mode to
+ * minimise CPU overhead for configuring the timer. This timer
+ * is never read and so overhead of reading the timer in posted
+ * mode is not applicable.
*/
#define OMAP_CLKEVT_POSTEDMODE OMAP_TIMER_POSTED
-#define OMAP_CLKSRC_POSTEDMODE OMAP_TIMER_POSTED
+
+/*
+ * For the clock-source timer, always use non-posted mode to
+ * minimise CPU overhead for reading the timer. This timer is
+ * only configured once and so using posted mode has no benefit.
+ */
+#define OMAP_CLKSRC_POSTEDMODE OMAP_TIMER_NONPOSTED
/* Clockevent code */
@@ -233,7 +241,8 @@ void __init omap_dmtimer_init(void)
static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
int gptimer_id,
const char *fck_source,
- const char *property)
+ const char *property,
+ int posted)
{
char name[10]; /* 10 = sizeof("gptXX_Xck0") */
const char *oh_name;
@@ -319,10 +328,11 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
}
__omap_dm_timer_init_regs(timer);
__omap_dm_timer_reset(timer, 1, 1);
- timer->posted = 1;
- timer->rate = clk_get_rate(timer->fclk);
+ if (posted)
+ omap_dm_timer_enable_posted(timer);
+ timer->rate = clk_get_rate(timer->fclk);
timer->reserved = 1;
return res;
@@ -334,7 +344,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
{
int res;
- res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property);
+ res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property,
+ OMAP_CLKEVT_POSTEDMODE);
BUG_ON(res);
omap2_gp_timer_irq.dev_id = &clkev;
@@ -461,7 +472,8 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
{
int res;
- res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL);
+ res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL,
+ OMAP_CLKSRC_POSTEDMODE);
BUG_ON(res);
__omap_dm_timer_load_start(&clksrc,
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index b09e556..699570b 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -131,8 +131,8 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
}
__omap_dm_timer_reset(timer, 0, 0);
+ omap_dm_timer_enable_posted(timer);
omap_dm_timer_disable(timer);
- timer->posted = 1;
}
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
@@ -176,6 +176,27 @@ int omap_dm_timer_reserve_systimer(int id)
return 0;
}
+/**
+ * omap_dm_timer_enable_posted - enables write posted mode
+ * @timer: pointer to timer instance handle
+ *
+ * Enables the write posted mode for the timer. When posted mode is enabled
+ * writes to certain timer registers are immediately acknowledged by the
+ * internal bus and hence prevents stalling the CPU waiting for the write to
+ * complete. Enabling this feature can improve performance for writing to the
+ * timer registers.
+ */
+void omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
+{
+ if (timer->posted)
+ return;
+
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+ OMAP_TIMER_CTRL_POSTED);
+ timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
+ timer->posted = OMAP_TIMER_POSTED;
+}
+
struct omap_dm_timer *omap_dm_timer_request(void)
{
struct omap_dm_timer *timer = NULL, *t;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 835c3bdf..2d0228f 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -101,6 +101,7 @@ struct dmtimer_platform_data {
};
int omap_dm_timer_reserve_systimer(int id);
+void omap_dm_timer_enable_posted(struct omap_dm_timer *timer);
struct omap_dm_timer *omap_dm_timer_request(void);
struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);
@@ -342,10 +343,6 @@ static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
l |= 1 << 2;
__raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
-
- /* Match hardware reset default of posted mode */
- __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
- OMAP_TIMER_CTRL_POSTED, 0);
}
static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 03/14] ARM: OMAP3+: Implement timer workaround for errata i103 and i767
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
For drivers using the timers that do not read the counter or capture registers
and wish to use posted mode, can override the errata and enable posted mode by
making the following function calls.
omap_dm_timer_override_errata(timer, OMAP_TIMER_ERRATA_I103_I767);
omap_dm_timer_enable_posted(timer);
Both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Please note that now calls to omap_dm_timer_enable_posted() may not able posted
mode if the device is impacted by this errata. Therefore, for system-timers
check to see if the intended posted mode matches the actual. If it does not then
there is a configuration error in the system timers posted configuration.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/timer.c | 15 ++++++++++++
arch/arm/plat-omap/dmtimer.c | 36 +++++++++++++++++++++++++++++
arch/arm/plat-omap/include/plat/dmtimer.h | 14 +++++++++++
3 files changed, 65 insertions(+)
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 78b7712..8b0068c 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -332,6 +332,10 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
if (posted)
omap_dm_timer_enable_posted(timer);
+ /* Check that the intended posted configuration matches the actual */
+ if (posted != timer->posted)
+ return -EINVAL;
+
timer->rate = clk_get_rate(timer->fclk);
timer->reserved = 1;
@@ -344,6 +348,15 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
{
int res;
+ omap_dm_timer_populate_errata(&clkev);
+
+ /*
+ * For clock-event timers we never read the timer counter and
+ * so we are not impacted by errata i103 and i767. Therefore,
+ * we can safely ignore this errata for clock-event timers.
+ */
+ omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
+
res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property,
OMAP_CLKEVT_POSTEDMODE);
BUG_ON(res);
@@ -472,6 +485,8 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
{
int res;
+ omap_dm_timer_populate_errata(&clksrc);
+
res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL,
OMAP_CLKSRC_POSTEDMODE);
BUG_ON(res);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 699570b..4abbbe5 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -177,6 +177,37 @@ int omap_dm_timer_reserve_systimer(int id)
}
/**
+ * omap_dm_timer_populate_errata - populate errata flags for a timer
+ * @timer: pointer to timer handle
+ *
+ * For a given timer, populate the timer errata flags that are specific to the
+ * OMAP device being used.
+ */
+void omap_dm_timer_populate_errata(struct omap_dm_timer *timer)
+{
+ timer->errata = 0;
+
+ if (cpu_class_is_omap1() || cpu_is_omap24xx())
+ return;
+
+ timer->errata = OMAP_TIMER_ERRATA_I103_I767;
+}
+
+/**
+ * omap_dm_timer_override_errata - override errata flags for a timer
+ * @timer: pointer to timer handle
+ * @errata: errata flags to be ignored
+ *
+ * For a given timer, override a timer errata by clearing the flags specified
+ * by the errata argument. A specific erratum should only be overridden for a
+ * timer if the timer is used in such a way the erratum has no impact.
+ */
+void omap_dm_timer_override_errata(struct omap_dm_timer *timer, u32 errata)
+{
+ timer->errata &= ~errata;
+}
+
+/*
* omap_dm_timer_enable_posted - enables write posted mode
* @timer: pointer to timer instance handle
*
@@ -191,6 +222,9 @@ void omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
if (timer->posted)
return;
+ if (timer->errata & OMAP_TIMER_ERRATA_I103_I767)
+ return;
+
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
OMAP_TIMER_CTRL_POSTED);
timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
@@ -824,6 +858,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
timer->irq = irq->start;
timer->pdev = pdev;
+ omap_dm_timer_populate_errata(timer);
+
/* Skip pm_runtime_enable for OMAP1 */
if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
pm_runtime_enable(dev);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 2d0228f..ef93017 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -36,6 +36,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <plat/cpu.h>
#ifndef __ASM_ARCH_DMTIMER_H
#define __ASM_ARCH_DMTIMER_H
@@ -66,6 +67,16 @@
#define OMAP_TIMER_NEEDS_RESET 0x10000000
#define OMAP_TIMER_HAS_DSP_IRQ 0x08000000
+/*
+ * timer errata flags
+ *
+ * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This
+ * errata prevents us from using posted mode on these devices, unless the
+ * timer counter register is never read. For more details please refer to
+ * the OMAP3/4/5 errata documents.
+ */
+#define OMAP_TIMER_ERRATA_I103_I767 0x80000000
+
struct omap_timer_capability_dev_attr {
u32 timer_capability;
};
@@ -101,6 +112,8 @@ struct dmtimer_platform_data {
};
int omap_dm_timer_reserve_systimer(int id);
+void omap_dm_timer_populate_errata(struct omap_dm_timer *timer);
+void omap_dm_timer_override_errata(struct omap_dm_timer *timer, u32 errata);
void omap_dm_timer_enable_posted(struct omap_dm_timer *timer);
struct omap_dm_timer *omap_dm_timer_request(void);
struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
@@ -272,6 +285,7 @@ struct omap_dm_timer {
int ctx_loss_count;
int revision;
u32 capability;
+ u32 errata;
struct platform_device *pdev;
struct list_head node;
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 04/14] ARM: OMAP: Fix timer posted mode support
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
Currently the dmtimer posted mode is being enabled when the function
omap_dm_timer_enable_posted() is called. This function is only being called
for OMAP1 timers and OMAP2+ timers that are being used as system timers. Hence,
for OMAP2+ timers that are NOT being used as a system timer, posted mode is
not enabled but the "timer->posted" variable is still set (incorrectly) in
the omap_dm_timer_prepare() function.
This is a regression introduced by commit 3392cdd3 (ARM: OMAP: dmtimer:
switch-over to platform device driver) which was before the
omap_dm_timer_enable_posted() function was introduced. Although this is a
regression from the original code it only impacts performance and so is not
needed for stable.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 4abbbe5..bf484aa 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -124,21 +124,16 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
- omap_dm_timer_enable(timer);
if (timer->pdev->id != 1) {
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
omap_dm_timer_wait_for_reset(timer);
}
__omap_dm_timer_reset(timer, 0, 0);
- omap_dm_timer_enable_posted(timer);
- omap_dm_timer_disable(timer);
}
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
{
- int ret;
-
/*
* FIXME: OMAP1 devices do not use the clock framework for dmtimers so
* do not call clk_get() for these devices.
@@ -152,13 +147,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
}
}
+ omap_dm_timer_enable(timer);
+
if (timer->capability & OMAP_TIMER_NEEDS_RESET)
omap_dm_timer_reset(timer);
- ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+ omap_dm_timer_enable_posted(timer);
+ omap_dm_timer_disable(timer);
- timer->posted = 1;
- return ret;
+ return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
}
static inline u32 omap_dm_timer_reserved_systimer(int id)
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 05/14] ARM: OMAP3: Correct HWMOD DMTIMER SYSC register declarations
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
Currently, the OMAP3 HWMOD data defines two TIOCP_CFG register structures
(referred to as the SYSC register in the HWMOD data) where timers 1, 2 and 10
use one of the defintions and the other timers use the other definition. For
OMAP3 devices the structure of the DMTIMER TIOCP_CFG register is the same for
all 12 instances of the DMTIMER. Please note that this is a difference between
OMAP3 and OMAP4 and could be the source of the confusion.
For OMAP3 devices, the DMTIMER TIOCP_CFG register has the fields,
clock-activity, emufree, idlemode, enwakeup, softreset and autoidle for all
12 timers. Therefore, remove one of the SYSC register definitions for the
DMTIMERs and ensure the appropriate register fields are defined for all
DMTIMERs.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index f67b7ee..679c0ec 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -149,28 +149,13 @@ static struct omap_hwmod omap3xxx_debugss_hwmod = {
};
/* timer class */
-static struct omap_hwmod_class_sysconfig omap3xxx_timer_1ms_sysc = {
- .rev_offs = 0x0000,
- .sysc_offs = 0x0010,
- .syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
- SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
- .sysc_fields = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap3xxx_timer_1ms_hwmod_class = {
- .name = "timer",
- .sysc = &omap3xxx_timer_1ms_sysc,
-};
-
static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
.rev_offs = 0x0000,
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
- SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -220,7 +205,7 @@ static struct omap_hwmod omap3xxx_timer1_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .class = &omap3xxx_timer_1ms_hwmod_class,
+ .class = &omap3xxx_timer_hwmod_class,
};
/* timer2 */
@@ -237,7 +222,7 @@ static struct omap_hwmod omap3xxx_timer2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
},
},
- .class = &omap3xxx_timer_1ms_hwmod_class,
+ .class = &omap3xxx_timer_hwmod_class,
};
/* timer3 */
@@ -379,7 +364,7 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .class = &omap3xxx_timer_1ms_hwmod_class,
+ .class = &omap3xxx_timer_hwmod_class,
};
/* timer11 */
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 06/14] ARM: OMAP2/3: Define HWMOD software reset status for DMTIMERs
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
For OMAP2/3 devices, the HWMOD data does not define a software reset status
field for the DMTIMERs. Therefore, when HWMOD performs a soft-reset of the
DMTIMER we don't check and wait for the reset to complete. For OMAP2/3 devices,
the software reset status for a DMTIMER can be read from bit 0 of the DMTIMER
TISTAT register (referred to as the SYSS register in HWMOD). Add the
appropriate HWMOD definitions so that HWMOD will check the software reset
status when performing a software reset of the DMTIMER.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 2 +-
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index bd9220e..8c3b3f0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -58,7 +58,7 @@ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = {
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 679c0ec..306c627 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -155,7 +155,8 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 07/14] ARM: OMAP2+: Don't use __omap_dm_timer_reset()
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
Currently OMAP2+ devices are using the function __omap_dm_timer_reset() to
configure the clock-activity, idle, wakeup-enable and auto-idle fields in the
timer OCP_CFG register. The name of the function is mis-leading because this
function does not actually perform a reset of the timer.
For OMAP2+ devices, HWMOD is responsible for reseting and configuring the
timer OCP_CFG register. Therefore, do not use __omap_dm_timer_reset() for
OMAP2+ devices and rely on HWMOD. Furthermore, some timer instances do not
have the fields clock-activity, wakeup-enable and auto-idle and so this
function could configure the OCP_CFG register incorrectly.
Currently HWMOD is not configuring the clock-activity field in the OCP_CFG
register for timers that have this field. Commit 0f0d080 (ARM: OMAP: DMTimer:
Use posted mode) configures the clock-activity field to keep the f-clk enabled
so that the wake-up capability is enabled. Therefore, add the appropriate flags
to the timer HWMOD structures to configure this field in the same way.
For OMAP2/3 devices all dmtimers have the clock-activity field, where as for
OMAP4 devices, only dmtimer 1, 2 and 10 have the clock-activity field.
Verified on OMAP2420 H4, OMAP3430 Beagle and OMAP4430 Panda that HWMOD is
configuring the dmtimer OCP_CFG register as expected for clock-events timer.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 13 +++++++++++++
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 13 +++++++++++++
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 ++++
arch/arm/mach-omap2/timer.c | 1 -
4 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 8c3b3f0..043b952 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -60,6 +60,7 @@ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = {
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .clockact = CLOCKACT_TEST_ICLK,
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -268,6 +269,7 @@ struct omap_hwmod omap2xxx_timer1_hwmod = {
},
.dev_attr = &capability_alwon_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer2 */
@@ -286,6 +288,7 @@ struct omap_hwmod omap2xxx_timer2_hwmod = {
},
},
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer3 */
@@ -304,6 +307,7 @@ struct omap_hwmod omap2xxx_timer3_hwmod = {
},
},
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer4 */
@@ -322,6 +326,7 @@ struct omap_hwmod omap2xxx_timer4_hwmod = {
},
},
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer5 */
@@ -341,6 +346,7 @@ struct omap_hwmod omap2xxx_timer5_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer6 */
@@ -360,6 +366,7 @@ struct omap_hwmod omap2xxx_timer6_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer7 */
@@ -379,6 +386,7 @@ struct omap_hwmod omap2xxx_timer7_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer8 */
@@ -398,6 +406,7 @@ struct omap_hwmod omap2xxx_timer8_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer9 */
@@ -417,6 +426,7 @@ struct omap_hwmod omap2xxx_timer9_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer10 */
@@ -436,6 +446,7 @@ struct omap_hwmod omap2xxx_timer10_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer11 */
@@ -455,6 +466,7 @@ struct omap_hwmod omap2xxx_timer11_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer12 */
@@ -474,6 +486,7 @@ struct omap_hwmod omap2xxx_timer12_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap2xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* wd_timer2 */
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 306c627..9cdbd3c 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -158,6 +158,7 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE |
SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .clockact = CLOCKACT_TEST_ICLK,
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -207,6 +208,7 @@ static struct omap_hwmod omap3xxx_timer1_hwmod = {
},
.dev_attr = &capability_alwon_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer2 */
@@ -224,6 +226,7 @@ static struct omap_hwmod omap3xxx_timer2_hwmod = {
},
},
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer3 */
@@ -241,6 +244,7 @@ static struct omap_hwmod omap3xxx_timer3_hwmod = {
},
},
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer4 */
@@ -258,6 +262,7 @@ static struct omap_hwmod omap3xxx_timer4_hwmod = {
},
},
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer5 */
@@ -276,6 +281,7 @@ static struct omap_hwmod omap3xxx_timer5_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer6 */
@@ -294,6 +300,7 @@ static struct omap_hwmod omap3xxx_timer6_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer7 */
@@ -312,6 +319,7 @@ static struct omap_hwmod omap3xxx_timer7_hwmod = {
},
.dev_attr = &capability_dsp_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer8 */
@@ -330,6 +338,7 @@ static struct omap_hwmod omap3xxx_timer8_hwmod = {
},
.dev_attr = &capability_dsp_pwm_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer9 */
@@ -348,6 +357,7 @@ static struct omap_hwmod omap3xxx_timer9_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer10 */
@@ -366,6 +376,7 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer11 */
@@ -384,6 +395,7 @@ static struct omap_hwmod omap3xxx_timer11_hwmod = {
},
.dev_attr = &capability_pwm_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/* timer12 */
@@ -407,6 +419,7 @@ static struct omap_hwmod omap3xxx_timer12_hwmod = {
},
.dev_attr = &capability_secure_dev_attr,
.class = &omap3xxx_timer_hwmod_class,
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
/*
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 652d028..e1f652f 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -3066,6 +3066,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = {
SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .clockact = CLOCKACT_TEST_ICLK,
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -3119,6 +3120,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
.name = "timer1",
.class = &omap44xx_timer_1ms_hwmod_class,
.clkdm_name = "l4_wkup_clkdm",
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_timer1_irqs,
.main_clk = "timer1_fck",
.prcm = {
@@ -3141,6 +3143,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = {
.name = "timer2",
.class = &omap44xx_timer_1ms_hwmod_class,
.clkdm_name = "l4_per_clkdm",
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_timer2_irqs,
.main_clk = "timer2_fck",
.prcm = {
@@ -3315,6 +3318,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
.name = "timer10",
.class = &omap44xx_timer_1ms_hwmod_class,
.clkdm_name = "l4_per_clkdm",
+ .flags = HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_timer10_irqs,
.main_clk = "timer10_fck",
.prcm = {
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 8b0068c..b9b6f21 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -327,7 +327,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
}
}
__omap_dm_timer_init_regs(timer);
- __omap_dm_timer_reset(timer, 1, 1);
if (posted)
omap_dm_timer_enable_posted(timer);
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 08/14] ARM: OMAP: Fix dmtimer reset for timer1
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
In commit e32f7ec2 (ARM: OMAP: Fix 32 kHz timer and modify GP timer to use GPT1)
a fix was added to prevent timer1 being reset in the function
omap_dm_timer_reset() because timer1 was being used as the system timer for
OMAP2 devices. Although timer1 is still used by most OMAP2+ devices as a system
timer, the function omap_dm_timer_reset() is now only being called for OMAP1
devices and OMAP1 does not use timer1 as a system timer. Therefore, remove the
check in omap_dm_timer_reset() so that timer1 is reset for OMAP1 devices.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index bf484aa..5a9f29b 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -124,11 +124,8 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
- if (timer->pdev->id != 1) {
- omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
- omap_dm_timer_wait_for_reset(timer);
- }
-
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
+ omap_dm_timer_wait_for_reset(timer);
__omap_dm_timer_reset(timer, 0, 0);
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 09/14] ARM: OMAP: Don't restore of DMTIMER TISTAT register
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
The timer TISTAT register is a read-only register and therefore restoring the
context is not needed. Furthermore, the context of TISTAT is never saved
anywhere in the current code. The TISTAT register is read-only for all OMAP
devices from OMAP1 to OMAP4. OMAP5 timers no longer have this register.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 3 ---
arch/arm/plat-omap/include/plat/dmtimer.h | 1 -
2 files changed, 4 deletions(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 5a9f29b..a350f12 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -86,9 +86,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
- if (timer->revision == 1)
- __raw_writel(timer->context.tistat, timer->sys_stat);
-
__raw_writel(timer->context.tisr, timer->irq_stat);
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
timer->context.twer);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index ef93017..36b71a5 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -85,7 +85,6 @@ struct omap_dm_timer;
struct timer_regs {
u32 tidr;
- u32 tistat;
u32 tisr;
u32 tier;
u32 twer;
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 10/14] ARM: OMAP: Don't restore DMTIMER interrupt status register
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
Restoring the timer interrupt status is not possible because writing a 1 to any
bit in the register clears that bit if set and writing a 0 has no affect.
Furthermore, if an interrupt is pending when someone attempts to disable a
timer, the timer will fail to transition to the idle state and hence it's
context will not be lost. Users should take care to service all interrupts
before disabling the timer.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 5 +----
arch/arm/plat-omap/include/plat/dmtimer.h | 1 -
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index a350f12..76553fd5 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -86,7 +86,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
- __raw_writel(timer->context.tisr, timer->irq_stat);
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
timer->context.twer);
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -495,7 +494,6 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
*/
timer->context.tclr =
omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
- timer->context.tisr = __raw_readl(timer->irq_stat);
omap_dm_timer_disable(timer);
return 0;
}
@@ -738,8 +736,7 @@ int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
return -EINVAL;
__omap_dm_timer_write_status(timer, value);
- /* Save the context */
- timer->context.tisr = value;
+
return 0;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 36b71a5..af145a9 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -85,7 +85,6 @@ struct omap_dm_timer;
struct timer_regs {
u32 tidr;
- u32 tisr;
u32 tier;
u32 twer;
u32 tclr;
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 11/14] ARM: OMAP: Fix spurious interrupts when using timer match feature
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
The OMAP DMTIMERs can generate an interrupt when the timer counter value
matches the value stored in the timer's match register. When using this
feature spurious interrupts were seen, because the compare logic is being
enabled before the match value is loaded and according to the documentation
the match value must be loaded before the compare logic is enable.
The reset value for the timer counter and match registers is 0 and hence,
by enabling the compare logic before the actual match value is loaded a
spurious interrupt can be generated as the reset values match.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 76553fd5..e7bf0d1 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -638,8 +638,8 @@ int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
l |= OMAP_TIMER_CTRL_CE;
else
l &= ~OMAP_TIMER_CTRL_CE;
- omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
/* Save the context */
timer->context.tclr = l;
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 12/14] ARM: OMAP: Add dmtimer interrupt disable function
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
The OMAP dmtimer driver does not currently have a function to disable the
timer interrupts. For some timer instances the timer interrupt enable
function can be used to disable the interrupts because the same interrupt
enable register is used to disable interrupts. However, some timer instances
have separate interrupt enable/disable registers and so this will not work.
Therefore, add a dedicated function to disable interrupts.
This change is required for OMAP4+ devices. For OMAP4, all timers apart from 1,
2 and 10 need this function and for OMAP5 all timers need this function.
Please note that the interrupt disable function has been written so that it
can be used by all OMAP devices.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 31 +++++++++++++++++++++++++++++
arch/arm/plat-omap/include/plat/dmtimer.h | 3 ++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index e7bf0d1..508a38e 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -715,6 +715,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
+/**
+ * omap_dm_timer_set_int_disable - disable timer interrupts
+ * @timer: pointer to timer handle
+ * @mask: bit mask of interrupts to be disabled
+ *
+ * Disables the specified timer interrupts for a timer.
+ */
+int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
+{
+ u32 l = mask;
+
+ if (unlikely(!timer))
+ return -EINVAL;
+
+ omap_dm_timer_enable(timer);
+
+ if (timer->revision == 1)
+ l = __raw_readl(timer->irq_ena) & ~mask;
+
+ __raw_writel(l, timer->irq_dis);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
+
+ /* Save the context */
+ timer->context.tier &= ~mask;
+ timer->context.twer &= ~mask;
+ omap_dm_timer_disable(timer);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);
+
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
unsigned int l;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index af145a9..14190e8 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -137,6 +137,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, i
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask);
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
@@ -322,7 +323,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
OMAP_TIMER_V1_SYS_STAT_OFFSET;
timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
- timer->irq_dis = NULL;
+ timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
timer->func_base = timer->io_base;
} else {
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 13/14] ARM: OMAP: Remove unnecessary call to clk_get()
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
Whenever we call the function omap_dm_timer_set_source() to set the clock
source of a dmtimer we look-up the dmtimer functional clock source by
calling clk_get(). This is not necessary because on requesting a dmtimer
we look-up the functional clock source and store it in the omap_dm_timer
structure. So instead of looking up the clock again used the clock handle
that stored in the omap_dm_timer structure.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/plat-omap/dmtimer.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 508a38e..191d5e5 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -503,7 +503,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
int ret;
char *parent_name = NULL;
- struct clk *fclk, *parent;
+ struct clk *parent;
struct dmtimer_platform_data *pdata;
if (unlikely(!timer))
@@ -522,11 +522,8 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
if (pdata && pdata->set_timer_src)
return pdata->set_timer_src(timer->pdev, source);
- fclk = clk_get(&timer->pdev->dev, "fck");
- if (IS_ERR_OR_NULL(fclk)) {
- pr_err("%s: fck not found\n", __func__);
+ if (!timer->fclk)
return -EINVAL;
- }
switch (source) {
case OMAP_TIMER_SRC_SYS_CLK:
@@ -545,18 +542,15 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
parent = clk_get(&timer->pdev->dev, parent_name);
if (IS_ERR_OR_NULL(parent)) {
pr_err("%s: %s not found\n", __func__, parent_name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
- ret = clk_set_parent(fclk, parent);
+ ret = clk_set_parent(timer->fclk, parent);
if (IS_ERR_VALUE(ret))
pr_err("%s: failed to set %s as parent\n", __func__,
parent_name);
clk_put(parent);
-out:
- clk_put(fclk);
return ret;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 14/14] ARM: OMAP: Remove __omap_dm_timer_set_source function
From: Jon Hunter @ 2012-11-07 19:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352314890-22224-1-git-send-email-jon-hunter@ti.com>
The __omap_dm_timer_set_source() function is only used by the system timer
(clock-events and clock-source) code for OMAP2+ devices. Therefore, we can
remove this code from the dmtimer driver and move it to the system timer
code for OMAP2+ devices.
The current __omap_dm_timer_set_source() function calls clk_disable() before
calling clk_set_parent() and clk_enable() afterwards. We can avoid these calls
to clk_disable/enable by moving the calls to omap_hwmod_setup_one() and
omap_hwmod_enable() to after the call to clk_set_parent() in
omap_dm_timer_init_one().
The function omap_hwmod_setup_one() will enable the timers functional clock
and therefore increment the use-count of the functional clock to 1.
clk_set_parent() will fail if the use-count is not 0 when called. Hence, if
omap_hwmod_setup_one() is called before clk_set_parent(), we will need to call
clk_disable() before calling clk_set_parent() to decrement the use-count.
Hence, avoid these extra calls to disable and enable the functional clock by
moving the calls to omap_hwmod_setup_one() and omap_hwmod_enable() to after
clk_set_parent().
We can also remove the delay from the __omap_dm_timer_set_source() function
because enabling the clock will now be handled via the HWMOD framework by
calling omap_hwmod_setup_one(). Therefore, by moving the calls to
omap_hwmod_setup_one() and omap_hwmod_enable() to after the call to
clk_set_parent(), we can simply replace __omap_dm_timer_set_source() with
clk_set_parent().
It should be safe to move these hwmod calls to later in the
omap_dm_timer_init_one() because other calls to the hwmod layer that occur
before are just requesting resource information.
Testing includes boot testing on OMAP2420 H4, OMAP3430 SDP and OMAP4430 Blaze
with the following configurations:
1. CONFIG_OMAP_32K_TIMER=y
2. CONFIG_OMAP_32K_TIMER=y and boot parameter "clocksource=gp_timer"
3. CONFIG_OMAP_32K_TIMER not set
4. CONFIG_OMAP_32K_TIMER not set and boot parameter "clocksource=gp_timer"
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
arch/arm/mach-omap2/timer.c | 9 ++++-----
arch/arm/plat-omap/include/plat/dmtimer.h | 19 -------------------
2 files changed, 4 insertions(+), 24 deletions(-)
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index b9b6f21..066a48d 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -277,9 +277,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
oh_name = name;
}
- omap_hwmod_setup_one(oh_name);
oh = omap_hwmod_lookup(oh_name);
-
if (!oh)
return -ENODEV;
@@ -309,8 +307,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
if (IS_ERR(timer->fclk))
return -ENODEV;
- omap_hwmod_enable(oh);
-
/* FIXME: Need to remove hard-coded test on timer ID */
if (gptimer_id != 12) {
struct clk *src;
@@ -319,13 +315,16 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
if (IS_ERR(src)) {
res = -EINVAL;
} else {
- res = __omap_dm_timer_set_source(timer->fclk, src);
+ res = clk_set_parent(timer->fclk, src);
if (IS_ERR_VALUE(res))
pr_warn("%s: %s cannot set source\n",
__func__, oh->name);
clk_put(src);
}
}
+
+ omap_hwmod_setup_one(oh_name);
+ omap_hwmod_enable(oh);
__omap_dm_timer_init_regs(timer);
if (posted)
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 14190e8..24a1c74 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -32,7 +32,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -358,24 +357,6 @@ static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
__raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
}
-static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
- struct clk *parent)
-{
- int ret;
-
- clk_disable(timer_fck);
- ret = clk_set_parent(timer_fck, parent);
- clk_enable(timer_fck);
-
- /*
- * When the functional clock disappears, too quick writes seem
- * to cause an abort. XXX Is this still necessary?
- */
- __delay(300000);
-
- return ret;
-}
-
static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
int posted, unsigned long rate)
{
--
1.7.9.5
^ permalink raw reply related
* [PATCH 05/13] ARM: OMAP2+: PRCM: create SoC-specific chip restart functions
From: Paul Walmsley @ 2012-11-07 20:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1211011151210.26661@utopia.booyaka.com>
Another update on this one to fix a build break that Tony spotted.
- Paul
From: Paul Walmsley <paul@pwsan.com>
Date: Mon, 29 Oct 2012 20:56:07 -0600
Subject: [PATCH] ARM: OMAP2+: PRCM: create SoC-specific chip restart
functions
Split omap_prcm_restart() from mach-omap2/prcm.c into SoC-specific
variants. These functions need to be able to save the reboot reason
into the scratchpad RAM. This implies a dependency on both the PRM
and SCM IP blocks, so they've been moved into their own file. This
will eventually call functions in the PRM and SCM drivers, once those
are created.
Vaibhav Hiremath <hvaibhav@ti.com> identified an unused prototype in
the first version of this patch - now removed. Tony Lindgren
<tony@atomide.com> noted a compile problem with some RMK Kconfigs;
resolved in this patch.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Vaibhav Hiremath <hvaibhav@ti.com>
Tested-by: Vaibhav Hiremath <hvaibhav@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
---
arch/arm/mach-omap2/Makefile | 5 +++
arch/arm/mach-omap2/common.h | 24 +++++++++++++
arch/arm/mach-omap2/omap2-restart.c | 65 +++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/omap3-restart.c | 36 +++++++++++++++++++
arch/arm/mach-omap2/omap4-common.c | 17 +++++++++
5 files changed, 147 insertions(+)
create mode 100644 arch/arm/mach-omap2/omap2-restart.c
create mode 100644 arch/arm/mach-omap2/omap3-restart.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index ae87a3e..1988810 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -50,6 +50,11 @@ AFLAGS_sram242x.o :=-Wa,-march=armv6
AFLAGS_sram243x.o :=-Wa,-march=armv6
AFLAGS_sram34xx.o :=-Wa,-march=armv7-a
+# Restart code (OMAP4/5 currently in omap4-common.c)
+obj-$(CONFIG_SOC_OMAP2420) += omap2-restart.o
+obj-$(CONFIG_SOC_OMAP2430) += omap2-restart.o
+obj-$(CONFIG_ARCH_OMAP3) += omap3-restart.o
+
# Pin multiplexing
obj-$(CONFIG_SOC_OMAP2420) += mux2420.o
obj-$(CONFIG_SOC_OMAP2430) += mux2430.o
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index ed21815..349d015 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -113,6 +113,30 @@ void omap4430_init_late(void);
int omap2_common_pm_late_init(void);
void omap_prcm_restart(char, const char *);
+#if defined(CONFIG_SOC_OMAP2420) || defined(CONFIG_SOC_OMAP2430)
+void omap2xxx_restart(char mode, const char *cmd);
+#else
+static inline void omap2xxx_restart(char mode, const char *cmd)
+{
+}
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+void omap3xxx_restart(char mode, const char *cmd);
+#else
+static inline void omap3xxx_restart(char mode, const char *cmd)
+{
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
+void omap44xx_restart(char mode, const char *cmd);
+#else
+static inline void omap44xx_restart(char mode, const char *cmd)
+{
+}
+#endif
+
/* This gets called from mach-omap2/io.c, do not call this */
void __init omap2_set_globals_tap(u32 class, void __iomem *tap);
diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c
new file mode 100644
index 0000000..be6bc89
--- /dev/null
+++ b/arch/arm/mach-omap2/omap2-restart.c
@@ -0,0 +1,65 @@
+/*
+ * omap2-restart.c - code common to all OMAP2xxx machines.
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include "common.h"
+#include "prm2xxx.h"
+
+/*
+ * reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set
+ * clock and the sys_ck. Used during the reset process
+ */
+static struct clk *reset_virt_prcm_set_ck, *reset_sys_ck;
+
+/* Reboot handling */
+
+/**
+ * omap2xxx_restart - Set DPLL to bypass mode for reboot to work
+ *
+ * Set the DPLL to bypass so that reboot completes successfully. No
+ * return value.
+ */
+void omap2xxx_restart(char mode, const char *cmd)
+{
+ u32 rate;
+
+ rate = clk_get_rate(reset_sys_ck);
+ clk_set_rate(reset_virt_prcm_set_ck, rate);
+
+ /* XXX Should save the cmd argument for use after the reboot */
+
+ omap2xxx_prm_dpll_reset(); /* never returns */
+ while (1);
+}
+
+/**
+ * omap2xxx_common_look_up_clks_for_reset - look up clocks needed for restart
+ *
+ * Some clocks need to be looked up in advance for the SoC restart
+ * operation to work - see omap2xxx_restart(). Returns -EINVAL upon
+ * error or 0 upon success.
+ */
+static int __init omap2xxx_common_look_up_clks_for_reset(void)
+{
+ reset_virt_prcm_set_ck = clk_get(NULL, "virt_prcm_set");
+ if (IS_ERR(reset_virt_prcm_set_ck))
+ return -EINVAL;
+
+ reset_sys_ck = clk_get(NULL, "sys_ck");
+ if (IS_ERR(reset_sys_ck))
+ return -EINVAL;
+
+ return 0;
+}
+core_initcall(omap2xxx_common_look_up_clks_for_reset);
diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c
new file mode 100644
index 0000000..923c582
--- /dev/null
+++ b/arch/arm/mach-omap2/omap3-restart.c
@@ -0,0 +1,36 @@
+/*
+ * omap3-restart.c - Code common to all OMAP3xxx machines.
+ *
+ * Copyright (C) 2009, 2012 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "iomap.h"
+#include "common.h"
+#include "control.h"
+#include "prm3xxx.h"
+
+/* Global address base setup code */
+
+/**
+ * omap3xxx_restart - trigger a software restart of the SoC
+ * @mode: the "reboot mode", see arch/arm/kernel/{setup,process}.c
+ * @cmd: passed from the userspace program rebooting the system (if provided)
+ *
+ * Resets the SoC. For @cmd, see the 'reboot' syscall in
+ * kernel/sys.c. No return value.
+ */
+void omap3xxx_restart(char mode, const char *cmd)
+{
+ omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0));
+ omap3xxx_prm_dpll3_reset(); /* never returns */
+ while (1);
+}
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 6cd7e87..3b13987 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -33,6 +33,7 @@
#include "common.h"
#include "mmc.h"
#include "hsmmc.h"
+#include "prminst44xx.h"
#include "omap4-sar-layout.h"
#include "omap-secure.h"
@@ -281,3 +282,19 @@ int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
return 0;
}
#endif
+
+/**
+ * omap44xx_restart - trigger a software restart of the SoC
+ * @mode: the "reboot mode", see arch/arm/kernel/{setup,process}.c
+ * @cmd: passed from the userspace program rebooting the system (if provided)
+ *
+ * Resets the SoC. For @cmd, see the 'reboot' syscall in
+ * kernel/sys.c. No return value.
+ */
+void omap44xx_restart(char mode, const char *cmd)
+{
+ /* XXX Should save 'cmd' into scratchpad for use after reboot */
+ omap4_prminst_global_warm_sw_reset(); /* never returns */
+ while (1);
+}
+
--
1.7.10.4
^ permalink raw reply related
* [PATCH] ARM: setup_mm_for_reboot(): use flush_cache_louis()
From: Nicolas Pitre @ 2012-11-07 20:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121107184129.GB18293@mudshark.cambridge.arm.com>
On Wed, 7 Nov 2012, Will Deacon wrote:
> On Wed, Nov 07, 2012 at 06:03:40PM +0000, Nicolas Pitre wrote:
> > On Wed, 7 Nov 2012, Will Deacon wrote:
> > > On Wed, Nov 07, 2012 at 09:56:35AM +0000, Russell King - ARM Linux wrote:
> > > > On Wed, Nov 07, 2012 at 09:51:06AM +0000, Will Deacon wrote:
> > > > > Wouldn't the L2 flush in this case be included with the code that turns off
> > > > > caching? For reboot, that's currently done in __sort_restart -- the cache
> > > > > flush in setup_mm_for_reboot is just to ensure that the idmap tables are
> > > > > visible to the hardware walker iirc.
> > > >
> > > > Good point - but it does raise another issue. Why do we do this flush and
> > > > TLB invalidate afterwards in setup_mm_for_reboot() ? It makes sense if
> > > > we change existing page tables, but we don't anymore, we're just switching
> > > > them, and cpu_switch_mm() will do whatever's necessary to make the new
> > > > page tables visible. So I think we can get rid of that flusing in there.
> > >
> > > Hmm, I'm not sure about that. Looking at cpu_v7_switch_mm (the 2-level
> > > version) for example, we set the ASID and then set the new TTBR. There's no
> > > flushing of page tables like we get in set_pte and no TLB flushing either.
> > >
> > > Now, given that the idmap_pgd is populated as an early_initcall, I really
> > > doubt we need that flush_cache_all but the TLB invalidate is surely
> > > required?
> >
> > Why wouldn't cpu_switch_mm() take care of that already if that is
> > necessary? Hmmm, I suppose the asid of the init task isn't associated
> > with the idmap in any way, hence the need for flushing the tlbs.
>
> Yes, cpu_switch_mm can't know about whether tables are visible or an ASID is
> dirty so all it can do is defer that to the caller or do the cleaning and
> invalidation every time.
>
> > I'd not rely on the early_initcall to assume the new page table is moved
> > out of the cache though.
>
> Yeah, it's not nice, I was just pointing out that it's all hanging off an
> initcall now (before it was created ad-hoc by its users).
>
> > What about this alternate patch:
> >
> > diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
> > index ab88ed4f8e..1ab429761c 100644
> > --- a/arch/arm/mm/idmap.c
> > +++ b/arch/arm/mm/idmap.c
> > @@ -92,6 +92,9 @@ static int __init init_static_idmap(void)
> > (long long)idmap_start, (long long)idmap_end);
> > identity_mapping_add(idmap_pgd, idmap_start, idmap_end);
> >
> > + /* Flush L1 for the hardware to see this page table content */
> > + flush_cache_louis();
> > +
> > return 0;
> > }
>
> Yep, we can do this now. Good thinking! At some point I'll get around to
> making this conditional, as I don't think it's needed on A5, A7, A9 or A15.
>
> > early_initcall(init_static_idmap);
> > @@ -103,12 +106,12 @@ early_initcall(init_static_idmap);
> > */
> > void setup_mm_for_reboot(void)
> > {
> > - /* Clean and invalidate L1. */
> > - flush_cache_all();
> > -
> > /* Switch to the identity mapping. */
> > cpu_switch_mm(idmap_pgd, &init_mm);
> >
> > - /* Flush the TLB. */
> > + /*
> > + * On ARMv7, the ASID of the init task is not associated with
> > + * this mapping. TLBs must be flushed.
> > + */
> > local_flush_tlb_all();
> > }
>
> Can we change this comment slightly please? Basically, we don't have a clean
> ASID for the identity mapping, which may clash with virtual addresses of the
> previous page tables and therefore potentially in the TLB. That's why
> we need the invalidation: so that we don't hit stale entries from before.
>
> Other than that, looks good to me:
>
> Acked-by: Will Deacon <will.deacon@arm.com>
Here's my latest version. I made the tlb flush conditional. Please
review again before I add your ACK.
---- >8
From: Nicolas Pitre <nicolas.pitre@linaro.org>
Subject: [PATCH] ARM: idmap: use flush_cache_louis() and flush TLBs only when necessary
Flushing the cache is needed for the hardware to see the idmap table
and therefore can be done at init time. On ARMv7 it is not necessary to
flush L2 so flush_cache_louis() is used here instead.
There is no point flushing the cache in setup_mm_for_reboot() as the
caller should, and already is, taking care of this. If switching the
memory map requires a cache flush, then cpu_switch_mm() already includes
that operation.
What is not done by cpu_switch_mm() on ASID capable CPUs is TLB flushing
as the whole point of the ASID is to tag the TLBs and avoid flushing them
on a context switch. Since we don't have a clean ASID for the identity
mapping, we need to flush the TLB explicitly in that case. Otherwise
this is already performed by cpu_switch_mm().
Signed-off-by: Nicolas Pitre <nico@linaro.org>
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index ab88ed4f8e..99db769307 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -92,6 +92,9 @@ static int __init init_static_idmap(void)
(long long)idmap_start, (long long)idmap_end);
identity_mapping_add(idmap_pgd, idmap_start, idmap_end);
+ /* Flush L1 for the hardware to see this page table content */
+ flush_cache_louis();
+
return 0;
}
early_initcall(init_static_idmap);
@@ -103,12 +106,15 @@ early_initcall(init_static_idmap);
*/
void setup_mm_for_reboot(void)
{
- /* Clean and invalidate L1. */
- flush_cache_all();
-
/* Switch to the identity mapping. */
cpu_switch_mm(idmap_pgd, &init_mm);
- /* Flush the TLB. */
+#ifdef CONFIG_CPU_HAS_ASID
+ /*
+ * We don't have a clean ASID for the identity mapping, which
+ * may clash with virtual addresses of the previous page tables
+ * and therefore potentially in the TLB.
+ */
local_flush_tlb_all();
+#endif
}
^ permalink raw reply related
* [PATCH] pwm: lpc32xx - Add a driver for the motor PWM
From: Thierry Reding @ 2012-11-07 20:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <509A982A.6020401@antcom.de>
On Wed, Nov 07, 2012 at 06:19:38PM +0100, Roland Stigge wrote:
> On 07/11/12 17:30, Alban Bedel wrote:
> > Signed-off-by: Alban Bedel <alban.bedel@avionic-design.de>
> > ---
> > .../devicetree/bindings/pwm/lpc32xx-motor-pwm.txt | 24 ++
> > arch/arm/boot/dts/lpc32xx.dtsi | 7 +
>
> Is all this supposed to go via mach-lpc32xx -> arm-soc.git? Then, I can
> take this into the lpc32xx tree. Otherwise, you can split off the .dtsi
> file and I include it via lpc32xx.
I'd prefer a split between the arch/arm changes and the rest. I'll take
the drivers/pwm and Documentation changes through the PWM tree.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121107/61af1347/attachment.sig>
^ permalink raw reply
* vexpress issues in next-20121029
From: Stephen Warren @ 2012-11-07 20:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <508EE610.9050703@wwwdotorg.org>
On 10/29/2012 02:24 PM, Stephen Warren wrote:
> Pawel,
>
> I see two issues on vexpress in next-20121029:
...
> 2) With those calls commented out, I find that
> vexpress_sysreg_init_leds() is device_initcall, and so executes even
> when not running on vexpress HW. This crashes on Tegra (which I have
> converted to single-zImage locally).
This issue still appears to be present in next-20121107.
^ 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