* [PATCH v2 0/7] clock/dpll autoidle support
From: Paul Walmsley @ 2011-02-13 1:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297329400-5936-1-git-send-email-rnayak@ti.com>
Hi Rajendra
On Thu, 10 Feb 2011, Rajendra Nayak wrote:
> OMAP has various clock nodes and dpll's
> which support hardware level autoidle.
> Enabling hardware level autoidle provides
> better power savings without much software
> intervention.
>
> This series does the following to help enable
> hardware level autoidling using clock framework
> for some of these nodes on OMAP3 and OMAP4
>
> -1- Adds support for providing function pointers
> for enabling/disabling autoidle in clkops
> -2- Populates these in clkops for all OMAP3/4 dplls
> -3- Enables all dpll autoidle late in boot on OMAP3 and OMAP4
> -4- Adds support for mx postdivider autoidle (present
> only on OMAP4) and enables it late in OMAP4 boot
I've reviewed and commented on all of these, asked a few questions, made a
few changes, and queued the results for 2.6.39 in two branches of
git://git.pwsan.com/linux-2.6:
clk_a_2.6.39 (for the autoidle-independent fixes)
clk_autoidle_a_2.6.39 (for the autoidle-specific code and data changes)
Both branches have been added to the 'integration-2.6.39' branch of
git://git.pwsan.com/linux-integration, and are available as part of the
tag "integration-2.6.39-20110212-004".
thanks,
- Paul
^ permalink raw reply
* [PATCH v2 7/7] omap4: dpll: Enable auto gate control for all MX postdividers
From: Paul Walmsley @ 2011-02-13 1:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297329400-5936-8-git-send-email-rnayak@ti.com>
On Thu, 10 Feb 2011, Rajendra Nayak wrote:
> Enable hardware gate control for all dpll MX and X2 postdividers.
> This requires the allow_idle/deny_idle functions to be
> populated for all clock nodes (mx/x2 post dividers) in
> clkops.
>
> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Thanks, queued for 2.6.39 in the 'clk_autoidle_a_2.6.39' branch. Has the
OMAP4 clock data autogenerator script been updated?
- Paul
^ permalink raw reply
* [PATCH v2 6/7] omap4: dpll: Add dpll api to control GATE_CTRL
From: Paul Walmsley @ 2011-02-13 1:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297329400-5936-7-git-send-email-rnayak@ti.com>
On Thu, 10 Feb 2011, Rajendra Nayak wrote:
> On OMAP4, the dpll post divider outputs (MX outputs)
> along with clockout_x2 output provide a way to allow/deny
> hardware level autogating.
> Allowing autoidle would mean that the hw would autogate
> this clock when there is no dependency for it.
> Denying idle would mean that this clock output will be
> forced to stay enabled.
>
> Add dpll api's to read/allow/deny idle control
> for these dpll mx postdividers.
>
> NOTE: The gatectrl bit set to 0 allows gatectrl,
> and the bit set to 1 denies gatectrl.
>
> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Thanks, I moved the OMAP4-specific code to a file that is only compiled in
on OMAP4, and added some documentation, and queued it for 2.6.39 in the
'clk_autoidle_a_2.6.39' branch here. Updated version follows.
- Paul
From: Rajendra Nayak <rnayak@ti.com>
Date: Thu, 10 Feb 2011 14:46:39 +0530
Subject: [PATCH] OMAP4: DPLL: Add dpll api to control GATE_CTRL
On OMAP4, the dpll post divider outputs (MX outputs)
along with clockout_x2 output provide a way to allow/deny
hardware level autogating.
Allowing autoidle would mean that the hw would autogate
this clock when there is no dependency for it.
Denying idle would mean that this clock output will be
forced to stay enabled.
Add dpll api's to read/allow/deny idle control
for these dpll mx postdividers.
NOTE: The gatectrl bit set to 0 allows gatectrl,
and the bit set to 1 denies gatectrl.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul at pwsan.com: moved OMAP4-specific DPLL control code to
mach-omap2/dpll44xx.c; added some documentation for CLOCK_CLKOUTX2]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/Makefile | 2 +-
arch/arm/mach-omap2/clock.h | 3 +
arch/arm/mach-omap2/dpll44xx.c | 78 +++++++++++++++++++++++++++++++
arch/arm/plat-omap/include/plat/clock.h | 14 +++++-
4 files changed, 95 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/mach-omap2/dpll44xx.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 9eeabaf..c21b3ae 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -120,7 +120,7 @@ obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \
clock3517.o clock36xx.o \
dpll3xxx.o clock3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \
- dpll3xxx.o
+ dpll3xxx.o dpll44xx.o
# OMAP2 clock rate set data (old "OPP" data)
obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 2a939e5..c450d69 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -65,6 +65,9 @@ u32 omap3_dpll_autoidle_read(struct clk *clk);
int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate);
int omap3_noncore_dpll_enable(struct clk *clk);
void omap3_noncore_dpll_disable(struct clk *clk);
+int omap4_dpllmx_gatectrl_read(struct clk *clk);
+void omap4_dpllmx_allow_gatectrl(struct clk *clk);
+void omap4_dpllmx_deny_gatectrl(struct clk *clk);
#ifdef CONFIG_OMAP_RESET_CLOCKS
void omap2_clk_disable_unused(struct clk *clk);
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
new file mode 100644
index 0000000..94a3592
--- /dev/null
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -0,0 +1,78 @@
+/*
+ * OMAP4-specific DPLL control functions
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Rajendra Nayak
+ *
+ * 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/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include <plat/cpu.h>
+#include <plat/clock.h>
+
+#include "clock.h"
+#include "cm-regbits-44xx.h"
+
+/* Supported only on OMAP4 */
+int omap4_dpllmx_gatectrl_read(struct clk *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg || !cpu_is_omap44xx())
+ return -EINVAL;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = __raw_readl(clk->clksel_reg);
+ v &= mask;
+ v >>= __ffs(mask);
+
+ return v;
+}
+
+void omap4_dpllmx_allow_gatectrl(struct clk *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg || !cpu_is_omap44xx())
+ return;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = __raw_readl(clk->clksel_reg);
+ /* Clear the bit to allow gatectrl */
+ v &= ~mask;
+ __raw_writel(v, clk->clksel_reg);
+}
+
+void omap4_dpllmx_deny_gatectrl(struct clk *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg || !cpu_is_omap44xx())
+ return;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = __raw_readl(clk->clksel_reg);
+ /* Set the bit to deny gatectrl */
+ v |= mask;
+ __raw_writel(v, clk->clksel_reg);
+}
diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index 8534f71..dd09e61 100644
--- a/arch/arm/plat-omap/include/plat/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
@@ -175,12 +175,24 @@ struct dpll_data {
#endif
-/* struct clk.flags possibilities */
+/*
+ * struct clk.flags possibilities
+ *
+ * XXX document the rest of the clock flags here
+ *
+ * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL
+ * bits share the same register. This flag allows the
+ * omap4_dpllmx*() code to determine which GATE_CTRL bit field
+ * should be used. This is a temporary solution - a better approach
+ * would be to associate clock type-specific data with the clock,
+ * similar to the struct dpll_data approach.
+ */
#define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */
#define CLOCK_IDLE_CONTROL (1 << 1)
#define CLOCK_NO_IDLE_PARENT (1 << 2)
#define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */
#define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */
+#define CLOCK_CLKOUTX2 (1 << 5)
/**
* struct clk - OMAP struct clk
--
1.7.2.3
^ permalink raw reply related
* [PATCH v2 5/7] omap: dpll: Enable all OMAP3/4 dpll autoidle late at boot
From: Paul Walmsley @ 2011-02-13 0:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297329400-5936-6-git-send-email-rnayak@ti.com>
On Thu, 10 Feb 2011, Rajendra Nayak wrote:
> Enable all dpll autoidle for OMAP4 and OMAP3 (OMAP3
> already had dpll autoidle turned on, but was done
> using low level cm accessor apis).
> On OMAP3, replace the cm accessor apis doing this
> with the now available support for doing this in
> clock framework, using omap_clk_enable_autoidle().
I propose this patch instead. What do you think? Care to reply with a
Reviewed-by: and/or Tested-by: ?
- Paul
From: Paul Walmsley <paul@pwsan.com>
Date: Sat, 12 Feb 2011 17:36:38 -0600
Subject: [PATCH] OMAP2+: clock: autoidle as many clocks as possible in OMAP2+-common PM code
Attempt to enable autoidle for as many clocks as possible in the
OMAP2+-common PM code. Currently, this only enables DPLL autoidle for
OMAP3/4 DPLLs; but it should also eventually enable autoidle for other
clocks and the OMAP2 DPLL/APLLs.
Based on a patch by Rajendra Nayak <rnayak@ti.com> that did this in
the pm34xx.c/pm44xx.c code, rather than the common PM code.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/pm.c | 8 ++++++++
arch/arm/mach-omap2/pm34xx.c | 17 -----------------
2 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d5a102c..b507702 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -262,6 +262,14 @@ static int __init omap2_common_pm_late_init(void)
/* Smartreflex device init */
omap_devinit_smartreflex();
+ /*
+ * Set all OMAP3/4 DPLLs to autoidle.
+ * XXX TODO: Add all the iclk autoidles in here as well,
+ * the OMAP2 DPLL, the OMAP2 APLLs, and the AUTOEXTCLKMODE
+ * control here too.
+ */
+ omap_clk_enable_autoidle_all();
+
return 0;
}
late_initcall(omap2_common_pm_late_init);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 2f864e4..1fe2e73 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -814,23 +814,6 @@ static void __init prcm_setup_regs(void)
omap_ctrl_writel(OMAP3430_AUTOIDLE_MASK, OMAP2_CONTROL_SYSCONFIG);
/*
- * Set all plls to autoidle. This is needed until autoidle is
- * enabled by clockfw
- */
- omap2_cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
- OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
- omap2_cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
- MPU_MOD,
- CM_AUTOIDLE2);
- omap2_cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
- (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
- PLL_MOD,
- CM_AUTOIDLE);
- omap2_cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
- PLL_MOD,
- CM_AUTOIDLE2);
-
- /*
* Enable control of expternal oscillator through
* sys_clkreq. In the long run clock framework should
* take care of this.
--
1.7.2.3
^ permalink raw reply related
* [PATCH v2 4/7] omap: dpll: Add allow_idle/deny_idle support for all DPLL's
From: Paul Walmsley @ 2011-02-13 0:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297329400-5936-5-git-send-email-rnayak@ti.com>
On Thu, 10 Feb 2011, Rajendra Nayak wrote:
> All OMAP3/4 dpll's support hardware level autogating.
> Populate allow_idle/deny_idle function pointers for all
> DPLL's in clkops.
>
> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Thanks, queued for 2.6.39. Two questions though. Was the OMAP4
autogeneration script updated? Also, any technical reason why you didn't
add the OMAP2 DPLL?
- Paul
^ permalink raw reply
* [PATCH v2 3/7] omap: clock: Add allow_idle/deny_idle support in clkops
From: Paul Walmsley @ 2011-02-13 0:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1102121643250.21991@utopia.booyaka.com>
On Sat, 12 Feb 2011, Paul Walmsley wrote:
> On Thu, 10 Feb 2011, Rajendra Nayak wrote:
>
> > diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
> > index fc62fb5..6889c5a 100644
> > --- a/arch/arm/plat-omap/clock.c
> > +++ b/arch/arm/plat-omap/clock.c
> > @@ -335,6 +335,32 @@ struct clk *omap_clk_get_by_name(const char *name)
> > return ret;
> > }
> >
> > +void omap_clk_enable_autoidle(void)
I also renamed these functions to
omap_clk_enable_autoidle_all()
omap_clk_disable_autoidle_all()
since they operate on all clocks. Updated patch follows.
- Paul
From: Rajendra Nayak <rnayak@ti.com>
Date: Thu, 10 Feb 2011 14:46:36 +0530
Subject: [PATCH] OMAP: clock: Add allow_idle/deny_idle support in clkops
On OMAP various clock nodes (dpll's, mx post dividers, interface clocks)
support hardware level autogating which can be controlled from
software.
Support such functionality by adding two new function pointer
allow_idle and deny_idle in the clkops structure.
These function pointers can be populated for any clock
node which supports hardware level autogating.
Also add 2 new functions (omap_clk_enable_autoidle_all and
omap_clk_disable_autoidle_all) which can be called from
architecture specific PM core code, if hardware level
autogating (for all supported clock nodes) is to be
enabled or disabled.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul at pwsan.com: use spinlock rather than mutex due to race; renamed functions]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/plat-omap/clock.c | 28 ++++++++++++++++++++++++++++
arch/arm/plat-omap/include/plat/clock.h | 6 ++++++
2 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index fc62fb5..585533a 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -335,6 +335,34 @@ struct clk *omap_clk_get_by_name(const char *name)
return ret;
}
+void omap_clk_enable_autoidle_all(void)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ list_for_each_entry(c, &clocks, node)
+ if (c->ops->allow_idle)
+ c->ops->allow_idle(c);
+
+ spin_lock_irqrestore(&clockfw_lock, flags);
+}
+
+void omap_clk_disable_autoidle_all(void)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ list_for_each_entry(c, &clocks, node)
+ if (c->ops->deny_idle)
+ c->ops->deny_idle(c);
+
+ spin_lock_irqrestore(&clockfw_lock, flags);
+}
+
/*
* Low level helpers
*/
diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index 8eb0ada..8534f71 100644
--- a/arch/arm/plat-omap/include/plat/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
@@ -25,6 +25,8 @@ struct clockdomain;
* @disable: fn ptr that enables the current clock in hardware
* @find_idlest: function returning the IDLEST register for the clock's IP blk
* @find_companion: function returning the "companion" clk reg for the clock
+ * @allow_idle: fn ptr that enables autoidle for the current clock in hardware
+ * @deny_idle: fn ptr that disables autoidle for the current clock in hardware
*
* A "companion" clk is an accompanying clock to the one being queried
* that must be enabled for the IP module connected to the clock to
@@ -42,6 +44,8 @@ struct clkops {
u8 *, u8 *);
void (*find_companion)(struct clk *, void __iomem **,
u8 *);
+ void (*allow_idle)(struct clk *);
+ void (*deny_idle)(struct clk *);
};
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -292,6 +296,8 @@ extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
#endif
extern struct clk *omap_clk_get_by_name(const char *name);
+extern void omap_clk_enable_autoidle_all(void);
+extern void omap_clk_disable_autoidle_all(void);
extern const struct clkops clkops_null;
--
1.7.2.3
^ permalink raw reply related
* MMC quirks relating to performance/lifetime.
From: Andrei Warkentin @ 2011-02-13 0:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201102121937.24933.arnd@arndb.de>
On Sat, Feb 12, 2011 at 12:37 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 11 February 2011 23:27:51 Andrei Warkentin wrote:
>>
>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
>> index 7054fd5..3b32329 100644
>> --- a/drivers/mmc/card/block.c
>> +++ b/drivers/mmc/card/block.c
>> @@ -312,6 +316,157 @@ out:
>> ? ? ? return err ? 0 : 1;
>> ?}
>>
>> +/*
>> + * Workaround for Toshiba eMMC performance. ?If the request is less than two
>> + * flash pages in size, then we want to split the write into one or two
>> + * page-aligned writes to take advantage of faster buffering. ?Here we can
>> + * adjust the size of the MMC request and let the block layer request handler
>> + * deal with generating another MMC request.
>> + */
>> +#define TOSHIBA_MANFID 0x11
>> +#define TOSHIBA_PAGE_SIZE 16 ? ? ? ? /* sectors */
>> +#define TOSHIBA_ADJUST_THRESHOLD 24 ?/* sectors */
>> +static bool mmc_adjust_toshiba_write(struct mmc_card *card,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct mmc_request *mrq)
>> +{
>> + ? ? if (mmc_card_mmc(card) && card->cid.manfid == TOSHIBA_MANFID &&
>> + ? ? ? ? mrq->data->blocks <= TOSHIBA_ADJUST_THRESHOLD) {
>> + ? ? ? ? ? ? int sectors_in_page = TOSHIBA_PAGE_SIZE -
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (mrq->cmd->arg % TOSHIBA_PAGE_SIZE);
>> + ? ? ? ? ? ? if (mrq->data->blocks > sectors_in_page) {
>> + ? ? ? ? ? ? ? ? ? ? mrq->data->blocks = sectors_in_page;
>> + ? ? ? ? ? ? ? ? ? ? return true;
>> + ? ? ? ? ? ? }
>> + ? ? }
>> +
>> + ? ? return false;
>> +}
>
> This part might make sense in general, though it's hard to know the
> page size in the general case. For many SD cards, writing naturally
> aligned 64 KB blocks was the ideal case in my testing, but some need
> larger alignment or can deal well with smaller blocks.
>
...which is why I believe this should be a boot per-card parameter,
and that it really only makes sense for embedded parts, where you know
nothing else is going to be used as, say, mmcblk0.
>> +/*
>> + * This is another strange workaround to try to close the gap on Toshiba eMMC
>> + * performance when compared to other vendors. ?In order to take advantage
>> + * of certain optimizations and assumptions in those cards, we will look for
>> + * multiblock write transfers below a certain size and we do the following:
>> + *
>> + * - Break them up into seperate page-aligned (8k flash pages) transfers.
>> + * - Execute the transfers in reverse order.
>> + * - Use "reliable write" transfer mode.
>> + *
>> + * Neither the block I/O layer nor the scatterlist design seem to lend them-
>> + * selves well to executing a block request out of order. ?So instead we let
>> + * mmc_blk_issue_rq() setup the MMC request for the entire transfer and then
>> + * break it up and reorder it here. ?This also requires that we put the data
>> + * into a bounce buffer and send it as individual sg's.
>> + */
>
> A lot of the SD cards I've seen will react very badly to reverse order,
> so that is definitely a dangerous thing to put into the code.
>
> Also, the "reliable write" seems like a really interesting thing to
> rely on for performance. I believe what the card is trying to do here
> is to optimize FAT32 directory updates. By using the small blocks in
> unpredictable order (anything but linear), you tell the card to treat
> this as part of a directory, so it probably gets written in a different
> way, but that might mean that it will try to turn the current erase
> block group into a special small write mode.
>
> I could imagine that this will cause problems on your eMMC once you
> write small blocks to more than erase block group, because that probably
> causes it to start garbage collection -- it makes sense for the cards
> to know that something is a directory, but it can only know about
> a small number of directories, so it will turn the segment into a regular
> one as soon something else becomes a directory.
>
It's difficult for me to argue one way or another. The code provided
is implementing Toshiba's suggestions for mitigating excessive wear.
Basically, as far as certain Android products are concerned, Motorola
created some "typical usage" cases, and collected data logs. These
logs were analyzed by Toshiba, which reported an approx x16
multiplication factor for writes.
Analysis of data written showed that there were many random accesses
with 16KB or 32KB, meaning they go into buffer B. According to T, that
means extra GC and PE cycle. I'm guessing per write.
So T suggested for random data to better go into buffer A. How? Two suggestions.
1) Split smaller accesses into 8KB and write with reliable write.
2) Split smaller accesses into 8KB and write in reverse.
The patch does both and I am verifying if that is really necessary. I
need to go see the mmc spec and what it says about reliable write.
Basically, whatever behavior you choose is going to be wrong some set
of cards. Which is why tuning it probably only makes sense for eMMC
parts, and should be a set of runtime/compile-time quirks. What do you
think?
^ permalink raw reply
* [PATCH v2 3/7] omap: clock: Add allow_idle/deny_idle support in clkops
From: Paul Walmsley @ 2011-02-13 0:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297329400-5936-4-git-send-email-rnayak@ti.com>
Hi Rajendra
On Thu, 10 Feb 2011, Rajendra Nayak wrote:
> diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
> index fc62fb5..6889c5a 100644
> --- a/arch/arm/plat-omap/clock.c
> +++ b/arch/arm/plat-omap/clock.c
> @@ -335,6 +335,32 @@ struct clk *omap_clk_get_by_name(const char *name)
> return ret;
> }
>
> +void omap_clk_enable_autoidle(void)
> +{
> + struct clk *c;
> +
> + mutex_lock(&clocks_mutex);
With the current OMAP clock code, it isn't sufficient to use a mutex here.
Your underlying functions have to read, modify, and write a register that
is also touched by clock functions like clk_set_rate(), which take the
clockfw spinlock and not the mutex. This is potentially racy and could
result in inconsistencies between the internal clock tree data and the
hardware settings.
While it is true that these functions are currently only called during PM
init, I'd rather not commit code that is subject to known races into the
tree.
So, before applying this patch, the mutexes have been converted into
spinlocks. I would appreciate it if you could help test this. Updated
patch follows, which has been queued for 2.6.39 as part of the
'clk_autoidle_a_2.6.39' branch of git://git.pwsan.com/linux-2.6.
- Paul
From: Rajendra Nayak <rnayak@ti.com>
Date: Thu, 10 Feb 2011 14:46:36 +0530
Subject: [PATCH] omap: clock: Add allow_idle/deny_idle support in clkops
On OMAP various clock nodes (dpll's, mx post dividers, interface clocks)
support hardware level autogating which can be controlled from
software.
Support such functionality by adding two new function pointer
allow_idle and deny_idle in the clkops structure.
These function pointers can be populated for any clock
node which supports hardware level autogating.
Also add 2 new functions (omap_clk_enable_auotidle and
omap_clk_disable_autoidle) which can be called from
architecture specific PM core code, if hardware level
autogating (for all supported clock nodes) is to be
enabled or disabled.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul at pwsan.com: use spinlock rather than mutex due to race]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/plat-omap/clock.c | 28 ++++++++++++++++++++++++++++
arch/arm/plat-omap/include/plat/clock.h | 6 ++++++
2 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index fc62fb5..0cdac8d 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -335,6 +335,34 @@ struct clk *omap_clk_get_by_name(const char *name)
return ret;
}
+void omap_clk_enable_autoidle(void)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ list_for_each_entry(c, &clocks, node)
+ if (c->ops->allow_idle)
+ c->ops->allow_idle(c);
+
+ spin_lock_irqrestore(&clockfw_lock, flags);
+}
+
+void omap_clk_disable_autoidle(void)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ list_for_each_entry(c, &clocks, node)
+ if (c->ops->deny_idle)
+ c->ops->deny_idle(c);
+
+ spin_lock_irqrestore(&clockfw_lock, flags);
+}
+
/*
* Low level helpers
*/
diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index 8eb0ada..167f1e0f 100644
--- a/arch/arm/plat-omap/include/plat/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
@@ -25,6 +25,8 @@ struct clockdomain;
* @disable: fn ptr that enables the current clock in hardware
* @find_idlest: function returning the IDLEST register for the clock's IP blk
* @find_companion: function returning the "companion" clk reg for the clock
+ * @allow_idle: fn ptr that enables autoidle for the current clock in hardware
+ * @deny_idle: fn ptr that disables autoidle for the current clock in hardware
*
* A "companion" clk is an accompanying clock to the one being queried
* that must be enabled for the IP module connected to the clock to
@@ -42,6 +44,8 @@ struct clkops {
u8 *, u8 *);
void (*find_companion)(struct clk *, void __iomem **,
u8 *);
+ void (*allow_idle)(struct clk *);
+ void (*deny_idle)(struct clk *);
};
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -292,6 +296,8 @@ extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
#endif
extern struct clk *omap_clk_get_by_name(const char *name);
+extern void omap_clk_enable_autoidle(void);
+extern void omap_clk_disable_autoidle(void);
extern const struct clkops clkops_null;
--
1.7.2.3
^ permalink raw reply related
* [PATCH 2/7] omap3: dpll: Populate clkops for dpll1_ck
From: Paul Walmsley @ 2011-02-12 23:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297159838-30282-3-git-send-email-rnayak@ti.com>
On Tue, 8 Feb 2011, Rajendra Nayak wrote:
> DPLL1 on omap3 is very similar to the rest of
> the non-core dpll's.
> Hence populate clkops_omap3_noncore_dpll_ops
> as the clkops for it, instead of the
> currently populated clkops_null.
>
> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Thanks, queued in branch 'clk_a_2.6.39' of git://git.pwsan.com/linux-2.6.
This patch is integrated as part of the tag
'tmp-integration-2.6.39-20110212-003' and the branch 'integration-2.6.39'
of git://git.pwsan.com/linux-integration.
- Paul
^ permalink raw reply
* [PATCH 3/5] ARM: l2x0: Errata fix for flush by Way operation can cause data corruption
From: Andrei Warkentin @ 2011-02-12 23:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <13596bec9184b117d6a1d02da8e017bf@mail.gmail.com>
On Sat, Feb 12, 2011 at 11:59 AM, Santosh Shilimkar
<santosh.shilimkar@ti.com> wrote:
>> -----Original Message-----
>> From: Andrei Warkentin [mailto:andreiw at motorola.com]
>> Sent: Saturday, February 12, 2011 11:20 PM
>> To: Santosh Shilimkar
>> Cc: linux-omap at vger.kernel.org; khilman at ti.com; tony at atomide.com;
>> linux-arm-kernel at lists.infradead.org; Catalin Marinas
>> Subject: Re: [PATCH 3/5] ARM: l2x0: Errata fix for flush by Way
>> operation can cause data corruption
>>
> [....]
>
>>
>> Can these PL310 errata fixes be made more generic? PL310 is present
>> in
>> non-OMAP platforms too, which lack the TI hypervisor. And these
>> platforms might have the same PL310 rev, and suffer the same
>> glitches.
>> While ideally there is some kind of hypervisor_ops to modify the
>> protected register, at the very least there should be the generic
>> debug_write handling the ?"I ?can write all PL310 regs" case. If
>> you're interested I have a patch someplace that tried to do this,
>> hopefully I can still find it.
>
> They are kind of generic. If you look at it, the only change
> Which is arch specific is the implementation of "debug_writel" function.
> Today this code is not in generic PL310 code, but
> OMAP specific.
>
> May be we can make this as exported function pointer, which
> arch's can populate.
>
> Will that work for you ?
>
> Regards,
> Santosh
>
Ie something like the following.... what do you think???
#define L2X0_DCR (0xF40)
static void debug_writel(unsigned long val)
{
#ifdef CONFIG_ARCH_OMAP4
omap_smc1(0x100, val);
#else
writel_relaxed(val, l2x0_base + L2X0_DCR);
#endif
}
...
...
/* clean all ways */
spin_lock_irqsave(&l2x0_lock, flags);
#ifdef CONFIG_PL310_ERRATA_727915
debug_writel(DCR_DWB | DCR_DCL); <---- not 0x3, but self-documenting
#endif
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
cache_sync();
#ifdef CONFIG_PL310_ERRATA_727915
debug_writel(0x00);
#endif
spin_unlock_irqrestore(&l2x0_lock, flags);
^ permalink raw reply
* [PATCH 1/7] omap: clock: Check for enable/disable ops support
From: Paul Walmsley @ 2011-02-12 23:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297159838-30282-2-git-send-email-rnayak@ti.com>
On Tue, 8 Feb 2011, Rajendra Nayak wrote:
> Check if enable/disable operations are supported for a given
> clock node before attempting to call them.
>
> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Thanks, queued in branch 'clk_a_2.6.39' of git://git.pwsan.com/linux-2.6.
This patch is integrated as part of the tag
'tmp-integration-2.6.39-20110212-003' and the branch 'integration-2.6.39'
of git://git.pwsan.com/linux-integration.
- Paul
^ permalink raw reply
* [PATCH 3/3] OMAP4: clockdomain: Add wkup/sleep dependency support
From: Paul Walmsley @ 2011-02-12 23:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <478620b0abf7ff99cb41192dd4ee9e6d@mail.gmail.com>
Here's the updated OMAP4 version.
The stable integration tag with this change is
'integration-2.6.39-20110212-002' of git://git.pwsan.com/linux-integration
- Paul
From: Rajendra Nayak <rnayak@ti.com>
Date: Sat, 12 Feb 2011 15:32:47 -0700
Subject: [PATCH] OMAP4: clockdomain: Add wkup/sleep dependency support
Add OMAP4 platform specific implementation to support clkdm
wkup and sleep dependencies a.k.a static dependencies.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul at pwsan.com: removed comment about PRM; zero-prefixed STATICDEP
register offset; fixed loop termination condition in
omap4_clkdm_clear_all_wkup_sleep_deps(); thanks to Kevin Hilman for finding
and helping fix this bug]
Cc: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/clockdomain44xx.c | 60 +++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/cm44xx.h | 1 +
2 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
index c0ccc47..a1a4ecd 100644
--- a/arch/arm/mach-omap2/clockdomain44xx.c
+++ b/arch/arm/mach-omap2/clockdomain44xx.c
@@ -12,8 +12,60 @@
* published by the Free Software Foundation.
*/
+#include <linux/kernel.h>
#include "clockdomain.h"
#include "cminst44xx.h"
+#include "cm44xx.h"
+
+static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->prcm_partition,
+ clkdm1->cm_inst, clkdm1->clkdm_offs +
+ OMAP4_CM_STATICDEP);
+ return 0;
+}
+
+static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->prcm_partition,
+ clkdm1->cm_inst, clkdm1->clkdm_offs +
+ OMAP4_CM_STATICDEP);
+ return 0;
+}
+
+static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
+ clkdm1->cm_inst, clkdm1->clkdm_offs +
+ OMAP4_CM_STATICDEP,
+ (1 << clkdm2->dep_bit));
+}
+
+static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
+{
+ struct clkdm_dep *cd;
+ u32 mask = 0;
+
+ for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (!cd->clkdm)
+ continue; /* only happens if data is erroneous */
+
+ mask |= 1 << cd->clkdm->dep_bit;
+ atomic_set(&cd->wkdep_usecount, 0);
+ }
+
+ omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs +
+ OMAP4_CM_STATICDEP);
+ return 0;
+}
static int omap4_clkdm_sleep(struct clockdomain *clkdm)
{
@@ -68,6 +120,14 @@ static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
}
struct clkdm_ops omap4_clkdm_operations = {
+ .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
+ .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
+ .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
+ .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
+ .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
+ .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
+ .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
+ .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
.clkdm_sleep = omap4_clkdm_sleep,
.clkdm_wakeup = omap4_clkdm_wakeup,
.clkdm_allow_idle = omap4_clkdm_allow_idle,
diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h
index 48fc3f4..0b87ec8 100644
--- a/arch/arm/mach-omap2/cm44xx.h
+++ b/arch/arm/mach-omap2/cm44xx.h
@@ -21,6 +21,7 @@
#include "cm.h"
#define OMAP4_CM_CLKSTCTRL 0x0000
+#define OMAP4_CM_STATICDEP 0x0004
/* Function prototypes */
# ifndef __ASSEMBLER__
--
1.7.2.3
^ permalink raw reply related
* [PATCH 3/3] OMAP4: clockdomain: Add wkup/sleep dependency support
From: Paul Walmsley @ 2011-02-12 22:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <478620b0abf7ff99cb41192dd4ee9e6d@mail.gmail.com>
On Fri, 11 Feb 2011, Rajendra Nayak wrote:
> > Does that sound okay to you?
>
> Yep, that sounds better.
Here's an updated patch for the main code and the OMAP2/3 implementation.
Comments, testing welcome.
The stable integration tag with this change is
'integration-2.6.39-20110212-001' of git://git.pwsan.com/linux-integration
- Paul
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 8 Feb 2011 14:25:34 -0700
Subject: [PATCH] OMAP: clockdomain: Arch specific funcs to handle deps
Define the following architecture specific funtions for omap2/3
.clkdm_add_wkdep
.clkdm_del_wkdep
.clkdm_read_wkdep
.clkdm_clear_all_wkdeps
.clkdm_add_sleepdep
.clkdm_del_sleepdep
.clkdm_read_sleepdep
.clkdm_clear_all_sleepdeps
Convert the platform-independent framework to call these functions.
With this also move the clkdm lookups for all wkdep_srcs and
sleepdep_srcs at clkdm_init.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul at pwsan.com: fixed loop termination conditions in omap*_clkdm_clear_all_*();
thanks to Kevin Hilman for finding and helping fix those bugs; also
avoid re-resolving clockdomains during init; abstracted out clkdm_dep walk]
Cc: Kevin Hilman <khilman@ti.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/Makefile | 2 +
arch/arm/mach-omap2/clockdomain.c | 177 ++++++++++++----------
arch/arm/mach-omap2/clockdomain.h | 6 +-
arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 130 ++++++++++++++++
arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c | 9 +-
arch/arm/mach-omap2/io.c | 6 +-
6 files changed, 246 insertions(+), 84 deletions(-)
create mode 100644 arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 1c0c2b0..6b2824d 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -102,8 +102,10 @@ obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \
# PRCM clockdomain control
obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \
+ clockdomain2xxx_3xxx.o \
clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \
+ clockdomain2xxx_3xxx.o \
clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \
clockdomains44xx_data.o
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index f70b06a..895c153 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -287,6 +287,32 @@ static void _disable_hwsup(struct clockdomain *clkdm)
BUG();
}
+/**
+ * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
+ * @clkdm: clockdomain that we are resolving dependencies for
+ * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
+ *
+ * Iterates through @clkdm_deps, looking up the struct clockdomain named by
+ * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
+ * No return value.
+ */
+static void _resolve_clkdm_deps(struct clockdomain *clkdm,
+ struct clkdm_dep *clkdm_deps)
+{
+ struct clkdm_dep *cd;
+
+ for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (cd->clkdm)
+ continue;
+ cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
+ WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
+ clkdm->name, cd->clkdm_name);
+ }
+}
+
/* Public functions */
/**
@@ -333,7 +359,10 @@ void clkdm_init(struct clockdomain **clkdms,
else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
omap2_clkdm_deny_idle(clkdm);
+ _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
clkdm_clear_all_wkdeps(clkdm);
+
+ _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
clkdm_clear_all_sleepdeps(clkdm);
}
}
@@ -430,6 +459,7 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ int ret = 0;
if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
@@ -441,21 +471,26 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
pr_debug("clockdomain: hardware will wake up %s when %s wakes "
"up\n", clkdm1->name, clkdm2->name);
- omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -471,6 +506,7 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ int ret = 0;
if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
@@ -482,21 +518,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
pr_debug("clockdomain: hardware will no longer wake up %s "
"after %s wakes up\n", clkdm1->name, clkdm2->name);
- omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -516,6 +557,7 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
@@ -527,15 +569,20 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
}
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
/* XXX It's faster to return the atomic wkdep_usecount */
- return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
- (1 << clkdm2->dep_bit));
+ return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
}
/**
@@ -550,9 +597,6 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
*/
int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
{
- struct clkdm_dep *cd;
- u32 mask = 0;
-
if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
pr_err("clockdomain: %s: %s: not yet implemented\n",
clkdm->name, __func__);
@@ -562,21 +606,10 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
if (!clkdm)
return -EINVAL;
- for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
- if (!omap_chip_is(cd->omap_chip))
- continue;
-
- if (!cd->clkdm && cd->clkdm_name)
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
- /* PRM accesses are slow, so minimize them */
- mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->wkdep_usecount, 0);
- }
-
- omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
+ return -EINVAL;
- return 0;
+ return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
}
/**
@@ -594,31 +627,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear sleep "
"dependency affecting %s from %s\n", clkdm1->name,
clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
pr_debug("clockdomain: will prevent %s from sleeping if %s "
"is active\n", clkdm1->name, clkdm2->name);
- omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP);
+ ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -636,19 +671,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear sleep "
"dependency affecting %s from %s\n", clkdm1->name,
clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
@@ -656,12 +695,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
"sleeping if %s is active\n", clkdm1->name,
clkdm2->name);
- omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP);
+ ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -683,25 +720,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear sleep "
"dependency affecting %s from %s\n", clkdm1->name,
clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
/* XXX It's faster to return the atomic sleepdep_usecount */
- return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP,
- (1 << clkdm2->dep_bit));
+ return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
}
/**
@@ -716,31 +755,13 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
*/
int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
{
- struct clkdm_dep *cd;
- u32 mask = 0;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
-
if (!clkdm)
return -EINVAL;
- for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
- if (!omap_chip_is(cd->omap_chip))
- continue;
-
- if (!cd->clkdm && cd->clkdm_name)
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
- /* PRM accesses are slow, so minimize them */
- mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->sleepdep_usecount, 0);
- }
-
- omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP);
+ if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
+ return -EINVAL;
- return 0;
+ return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
}
/**
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index 71ad265..90b6d6a 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -176,7 +176,11 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm);
int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
-extern void __init omap2_clockdomains_init(void);
+extern void __init omap2xxx_clockdomains_init(void);
+extern void __init omap3xxx_clockdomains_init(void);
extern void __init omap44xx_clockdomains_init(void);
+extern struct clkdm_ops omap2_clkdm_operations;
+extern struct clkdm_ops omap3_clkdm_operations;
+
#endif
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
new file mode 100644
index 0000000..a1fd6fd
--- /dev/null
+++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
@@ -0,0 +1,130 @@
+/*
+ * OMAP2 and OMAP3 clockdomain control
+ *
+ * Copyright (C) 2008-2010 Texas Instruments, Inc.
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
+ * Rajendra Nayak <rnayak@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/types.h>
+#include <plat/prcm.h>
+#include "prm.h"
+#include "prm2xxx_3xxx.h"
+#include "cm.h"
+#include "cm2xxx_3xxx.h"
+#include "cm-regbits-24xx.h"
+#include "cm-regbits-34xx.h"
+#include "clockdomain.h"
+
+static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ return 0;
+}
+
+static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ return 0;
+}
+
+static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
+ PM_WKDEP, (1 << clkdm2->dep_bit));
+}
+
+static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
+{
+ struct clkdm_dep *cd;
+ u32 mask = 0;
+
+ for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (!cd->clkdm)
+ continue; /* only happens if data is erroneous */
+
+ /* PRM accesses are slow, so minimize them */
+ mask |= 1 << cd->clkdm->dep_bit;
+ atomic_set(&cd->wkdep_usecount, 0);
+ }
+
+ omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
+ PM_WKDEP);
+ return 0;
+}
+
+static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP);
+ return 0;
+}
+
+static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP);
+ return 0;
+}
+
+static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit));
+}
+
+static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
+{
+ struct clkdm_dep *cd;
+ u32 mask = 0;
+
+ for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (!cd->clkdm)
+ continue; /* only happens if data is erroneous */
+
+ /* PRM accesses are slow, so minimize them */
+ mask |= 1 << cd->clkdm->dep_bit;
+ atomic_set(&cd->sleepdep_usecount, 0);
+ }
+ omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP);
+ return 0;
+}
+
+struct clkdm_ops omap2_clkdm_operations = {
+ .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
+ .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
+ .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
+ .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
+};
+
+struct clkdm_ops omap3_clkdm_operations = {
+ .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
+ .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
+ .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
+ .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
+ .clkdm_add_sleepdep = omap3_clkdm_add_sleepdep,
+ .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep,
+ .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep,
+ .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps,
+};
diff --git a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
index 8cab07a..f85de72 100644
--- a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
+++ b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
@@ -854,7 +854,12 @@ static struct clockdomain *clockdomains_omap2[] __initdata = {
NULL,
};
-void __init omap2_clockdomains_init(void)
+void __init omap2xxx_clockdomains_init(void)
{
- clkdm_init(clockdomains_omap2, clkdm_autodeps, NULL);
+ clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap2_clkdm_operations);
+}
+
+void __init omap3xxx_clockdomains_init(void)
+{
+ clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap3_clkdm_operations);
}
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index c203204..89cbba2 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -337,15 +337,15 @@ void __init omap2_init_common_infrastructure(void)
if (cpu_is_omap242x()) {
omap2xxx_powerdomains_init();
- omap2_clockdomains_init();
+ omap2xxx_clockdomains_init();
omap2420_hwmod_init();
} else if (cpu_is_omap243x()) {
omap2xxx_powerdomains_init();
- omap2_clockdomains_init();
+ omap2xxx_clockdomains_init();
omap2430_hwmod_init();
} else if (cpu_is_omap34xx()) {
omap3xxx_powerdomains_init();
- omap2_clockdomains_init();
+ omap3xxx_clockdomains_init();
omap3xxx_hwmod_init();
} else if (cpu_is_omap44xx()) {
omap44xx_powerdomains_init();
--
1.7.2.3
^ permalink raw reply related
* [PATCHv3] mx31: add support for the bugbase 1.3 from buglabs
From: Denis 'GNUtoo' Carikli @ 2011-02-12 21:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110211213348.GJ27982@pengutronix.de>
This work was based on bug-linux-2.6.30.patch that can be found
in buglabs's svn here:
svn://bugcamp.net/bug/branches/izzy/experimental
Note that the hardware schematics and documentations can be obtained
here: http://www.bugcommunity.com/wiki/index.php/BUGbase
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
---
arch/arm/mach-mx3/Kconfig | 9 ++++
arch/arm/mach-mx3/Makefile | 1 +
arch/arm/mach-mx3/mach-bug.c | 66 +++++++++++++++++++++++++++
arch/arm/plat-mxc/include/mach/uncompress.h | 4 ++
4 files changed, 80 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-mx3/mach-bug.c
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
index de80d98..4f57f13 100644
--- a/arch/arm/mach-mx3/Kconfig
+++ b/arch/arm/mach-mx3/Kconfig
@@ -199,6 +199,15 @@ config MACH_KZM_ARM11_01
Include support for KZM-ARM11-01. This includes specific
configurations for the board and its peripherals.
+config MACH_BUG
+ bool "Support Buglabs BUGBase platform"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_UART
+ default y
+ help
+ Include support for BUGBase 1.3 platform. This includes specific
+ configurations for the board and its peripherals.
+
config MACH_EUKREA_CPUIMX35
bool "Support Eukrea CPUIMX35 Platform"
select SOC_IMX35
diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile
index bc7294f..37d968b 100644
--- a/arch/arm/mach-mx3/Makefile
+++ b/arch/arm/mach-mx3/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o
obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o
obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o
obj-$(CONFIG_MACH_KZM_ARM11_01) += mach-kzm_arm11_01.o
+obj-$(CONFIG_MACH_BUG) += mach-bug.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o
obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd-baseboard.o
obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
diff --git a/arch/arm/mach-mx3/mach-bug.c b/arch/arm/mach-mx3/mach-bug.c
new file mode 100644
index 0000000..d974173
--- /dev/null
+++ b/arch/arm/mach-mx3/mach-bug.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2002 Shane Nay (shane at minirl.com)
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <mach/iomux-mx3.h>
+#include <mach/imx-uart.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include "devices-imx31.h"
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static const unsigned int bug_pins[] __initconst = {
+ MX31_PIN_PC_RST__CTS5,
+ MX31_PIN_PC_VS2__RTS5,
+ MX31_PIN_PC_BVD2__TXD5,
+ MX31_PIN_PC_BVD1__RXD5,
+};
+
+static void __init bug_board_init(void)
+{
+ mxc_iomux_setup_multiple_pins(bug_pins,
+ ARRAY_SIZE(bug_pins), "uart-4");
+ imx31_add_imx_uart4(&uart_pdata);
+
+}
+
+static void __init bug_timer_init(void)
+{
+ mx31_clocks_init(26000000);
+}
+
+static struct sys_timer bug_timer = {
+ .init = bug_timer_init,
+};
+
+MACHINE_START(BUG, "BugLabs BUGBase")
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &bug_timer,
+ .init_machine = bug_board_init,
+MACHINE_END
diff --git a/arch/arm/plat-mxc/include/mach/uncompress.h b/arch/arm/plat-mxc/include/mach/uncompress.h
index e634d6c..b45f534 100644
--- a/arch/arm/plat-mxc/include/mach/uncompress.h
+++ b/arch/arm/plat-mxc/include/mach/uncompress.h
@@ -62,6 +62,7 @@ static inline void flush(void)
#define MX2X_UART1_BASE_ADDR 0x1000a000
#define MX3X_UART1_BASE_ADDR 0x43F90000
#define MX3X_UART2_BASE_ADDR 0x43F94000
+#define MX3X_UART5_BASE_ADDR 0x43FB4000
#define MX51_UART1_BASE_ADDR 0x73fbc000
#define MX50_UART1_BASE_ADDR 0x53fbc000
#define MX53_UART1_BASE_ADDR 0x53fbc000
@@ -102,6 +103,9 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
case MACH_TYPE_MAGX_ZN5:
uart_base = MX3X_UART2_BASE_ADDR;
break;
+ case MACH_TYPE_BUG:
+ uart_base = MX3X_UART5_BASE_ADDR;
+ break;
case MACH_TYPE_MX51_BABBAGE:
case MACH_TYPE_EUKREA_CPUIMX51SD:
case MACH_TYPE_MX51_3DS:
--
1.7.0.4
^ permalink raw reply related
* The p2v branch
From: Nicolas Pitre @ 2011-02-12 21:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110212184138.GD22402@n2100.arm.linux.org.uk>
On Sat, 12 Feb 2011, Russell King - ARM Linux wrote:
> On Sat, Feb 12, 2011 at 01:32:48PM -0500, Nicolas Pitre wrote:
>
> > 3ecf8ba5 ARM: P2V: eliminate head.S use of PHYS_OFFSET for !XIP_KERNEL
> > Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> >
> > 5e8e98cd ARM: P2V: introduce phys_to_virt/virt_to_phys runtime patching
> > Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> > Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> >
> > 1929d11e ARM: P2V: extend to 16-bit translation offsets
> > Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> > Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> > (forced it on with non-msm targets for testing)
> >
> > b7a0fbb4 ARM: 6648/1: map ATAGs when not in first 1MB of RAM
> > Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
>
> Added.
I've rebased my 2 patches on top of your latest p2v branch. You may
pull them from:
git://git.linaro.org/people/nico/linux p2v
Or if you prefer I can put them in the patch system.
Nicolas
^ permalink raw reply
* [PATCH] mx31: add support for the bugbase 1.3 from buglabs
From: Denis 'GNUtoo' Carikli @ 2011-02-12 20:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4D55AA65.2020101@pengutronix.de>
On Fri, 2011-02-11 at 22:30 +0100, Marc Kleine-Budde wrote:
> here slipped some spaces in
> > + .init_irq = mx31_init_irq,
> > + .timer = &mx31bug_timer,
>
> dito
Sorry, I looked carefully after such errors at first,
before sending the first patch,
but then I forgot to look after it when fixing what the comments pointed
out.
I'll fix it in the new patch I'll resend, I'll try to find how to make
git-send-email send a v3 too(last time I failed, because I looked for
some command that did it on some wiki that was not very up to date)
Denis.
^ permalink raw reply
* ARM: relocation out of range (when loading a module)
From: Nicolas Pitre @ 2011-02-12 19:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110211144207.GJ23404@n2100.arm.linux.org.uk>
On Fri, 11 Feb 2011, Russell King - ARM Linux wrote:
> On Fri, Feb 11, 2011 at 02:25:28PM +0000, Dave Martin wrote:
> > if we can also move the initramfs somewhere less obstructive in the
> > future, then so much the better.
>
> This may do it, and it might even work. Not particularly well tested
> yet. It'd be loads easier if we didn't have to worry about XIP.
Is anyone actually still using XIP these days? Now that NOR flash is
not that much used anymore, if maintaining XIP support is more trouble
than it is worth we could simply deprecate it. The linker script has
become quite more hairy than it used to be, and from a quick look I'm
not even sure if all the stuff in there is properly located for XIP.
Otherwise, for the __init stuff move:
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Nicolas
^ permalink raw reply
* The p2v branch
From: Nicolas Pitre @ 2011-02-12 18:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110212184138.GD22402@n2100.arm.linux.org.uk>
On Sat, 12 Feb 2011, Russell King - ARM Linux wrote:
> On Sat, Feb 12, 2011 at 01:32:48PM -0500, Nicolas Pitre wrote:
> > I finally was able to complete this series and test it satisfactorily.
> > This required some hacking to the OMAP UART debugging code so it would
> > stop fighting against me and forcefully collaborate.
>
> It should at least build with 6651/1 in place.
Not if you do try to load the kernel somewhere else in memory to
exercize its ability to live with a different phys offset.
> The only fight
> remaining is against the (imho misguided) attempt to select the debug
> port based on the machine ID. I normally end up hard-coding the
> addresses.
That's what I ended up doing too, but something better and IMHO simpler
could be done, which would also be fully position independent.
Nicolas
^ permalink raw reply
* The p2v branch
From: Russell King - ARM Linux @ 2011-02-12 18:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1102121304500.14920@xanadu.home>
On Sat, Feb 12, 2011 at 01:32:48PM -0500, Nicolas Pitre wrote:
> I finally was able to complete this series and test it satisfactorily.
> This required some hacking to the OMAP UART debugging code so it would
> stop fighting against me and forcefully collaborate.
It should at least build with 6651/1 in place. The only fight
remaining is against the (imho misguided) attempt to select the debug
port based on the machine ID. I normally end up hard-coding the
addresses.
> But in the mean time I think you can complete the p2v branch with the
> following:
>
> 3ecf8ba5 ARM: P2V: eliminate head.S use of PHYS_OFFSET for !XIP_KERNEL
> Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
>
> 5e8e98cd ARM: P2V: introduce phys_to_virt/virt_to_phys runtime patching
> Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
>
> 1929d11e ARM: P2V: extend to 16-bit translation offsets
> Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> (forced it on with non-msm targets for testing)
>
> b7a0fbb4 ARM: 6648/1: map ATAGs when not in first 1MB of RAM
> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Added.
^ permalink raw reply
* [PATCH 1/7] mmc: mxs-mmc: add mmc host driver for i.MX23/28
From: Shawn Guo @ 2011-02-12 18:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201102121107.17779.arnd@arndb.de>
On Sat, Feb 12, 2011 at 11:07:17AM +0100, Arnd Bergmann wrote:
> On Saturday 12 February 2011 18:23:58 Shawn Guo wrote:
> > Well, we are removing inclusion of mach/dma.h from mmc driver, but
> > adding it to every mxs based machine code. This makes mmc driver
> > clean but machine code becomes not. For some dma client devices
> > coming later, the platform data could be saved at all, if they do not
> > have any. But with the approach you are suggesting, every single
> > client device will have to get platform data.
>
> Right, unless there is a way to encode it exlusively in the resources,
> which is what I was suggesting at first: If the dma engine driver
> knows about all the channels, you only need to pass the channel number.
>
> If you use a flattened device tree, you can avoid the need for
> platform data by adding the phandle of the dma engine device to
> a property of the mmc driver, along with the channel number inside
> of that device. I think that would be the cleanest approach, but
> some people still need to be convinced that changing drivers to
> use fdt data is the right direction for ARM.
>
Could we keep the current the approach for now and go to the cleanest
way directly when Grant's dt patches get merged?
Regards,
Shawn
^ permalink raw reply
* MMC quirks relating to performance/lifetime.
From: Arnd Bergmann @ 2011-02-12 18:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AANLkTi=a1SbU4cn-m7r2BH2KhNoad3H9e41AcXoViMm7@mail.gmail.com>
On Friday 11 February 2011 23:27:51 Andrei Warkentin wrote:
>
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index 7054fd5..3b32329 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -312,6 +316,157 @@ out:
> return err ? 0 : 1;
> }
>
> +/*
> + * Workaround for Toshiba eMMC performance. If the request is less than two
> + * flash pages in size, then we want to split the write into one or two
> + * page-aligned writes to take advantage of faster buffering. Here we can
> + * adjust the size of the MMC request and let the block layer request handler
> + * deal with generating another MMC request.
> + */
> +#define TOSHIBA_MANFID 0x11
> +#define TOSHIBA_PAGE_SIZE 16 /* sectors */
> +#define TOSHIBA_ADJUST_THRESHOLD 24 /* sectors */
> +static bool mmc_adjust_toshiba_write(struct mmc_card *card,
> + struct mmc_request *mrq)
> +{
> + if (mmc_card_mmc(card) && card->cid.manfid == TOSHIBA_MANFID &&
> + mrq->data->blocks <= TOSHIBA_ADJUST_THRESHOLD) {
> + int sectors_in_page = TOSHIBA_PAGE_SIZE -
> + (mrq->cmd->arg % TOSHIBA_PAGE_SIZE);
> + if (mrq->data->blocks > sectors_in_page) {
> + mrq->data->blocks = sectors_in_page;
> + return true;
> + }
> + }
> +
> + return false;
> +}
This part might make sense in general, though it's hard to know the
page size in the general case. For many SD cards, writing naturally
aligned 64 KB blocks was the ideal case in my testing, but some need
larger alignment or can deal well with smaller blocks.
> +/*
> + * This is another strange workaround to try to close the gap on Toshiba eMMC
> + * performance when compared to other vendors. In order to take advantage
> + * of certain optimizations and assumptions in those cards, we will look for
> + * multiblock write transfers below a certain size and we do the following:
> + *
> + * - Break them up into seperate page-aligned (8k flash pages) transfers.
> + * - Execute the transfers in reverse order.
> + * - Use "reliable write" transfer mode.
> + *
> + * Neither the block I/O layer nor the scatterlist design seem to lend them-
> + * selves well to executing a block request out of order. So instead we let
> + * mmc_blk_issue_rq() setup the MMC request for the entire transfer and then
> + * break it up and reorder it here. This also requires that we put the data
> + * into a bounce buffer and send it as individual sg's.
> + */
A lot of the SD cards I've seen will react very badly to reverse order,
so that is definitely a dangerous thing to put into the code.
Also, the "reliable write" seems like a really interesting thing to
rely on for performance. I believe what the card is trying to do here
is to optimize FAT32 directory updates. By using the small blocks in
unpredictable order (anything but linear), you tell the card to treat
this as part of a directory, so it probably gets written in a different
way, but that might mean that it will try to turn the current erase
block group into a special small write mode.
I could imagine that this will cause problems on your eMMC once you
write small blocks to more than erase block group, because that probably
causes it to start garbage collection -- it makes sense for the cards
to know that something is a directory, but it can only know about
a small number of directories, so it will turn the segment into a regular
one as soon something else becomes a directory.
Arnd
^ permalink raw reply
* [PATCH 2/2] P2V: Thumb2 support
From: Nicolas Pitre @ 2011-02-12 18:33 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Pitre <nicolas.pitre@linaro.org>
Adding Thumb2 support to the runtime patching of the virt_to_phys and
phys_to_virt opcodes.
Tested both the 8-bit and the 16-bit fixups, using different placements
in memory to exercize all code paths.
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
---
arch/arm/Kconfig | 4 ++--
arch/arm/kernel/head.S | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d5eb308..8d5643d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -194,13 +194,13 @@ config VECTORS_BASE
config ARM_PATCH_PHYS_VIRT
bool "Patch physical to virtual translations at runtime (EXPERIMENTAL)"
depends on EXPERIMENTAL
- depends on !XIP_KERNEL && !THUMB2_KERNEL && MMU
+ depends on !XIP_KERNEL && MMU
depends on !ARCH_REALVIEW || !SPARSEMEM
help
Patch phys-to-virt translation functions at runtime according to
the position of the kernel in system memory.
- This can only be used with non-XIP, non-Thumb2, MMU kernels where
+ This can only be used with non-XIP with MMU kernels where
the base of physical memory is at a 16MB boundary.
config ARM_PATCH_PHYS_VIRT_16BIT
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 8f96ca0..575bb3e 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -475,7 +475,8 @@ __fixup_pv_table:
sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
add r4, r4, r3 @ adjust table start address
add r5, r5, r3 @ adjust table end address
- str r8, [r7, r3]! @ save computed PHYS_OFFSET to __pv_phys_offset
+ add r7, r7, r3 @ adjust __pv_phys_offset address
+ str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset
#ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
mov r6, r3, lsr #24 @ constant for add/sub instructions
teq r3, r6, lsl #24 @ must be 16MiB aligned
@@ -483,6 +484,7 @@ __fixup_pv_table:
mov r6, r3, lsr #16 @ constant for add/sub instructions
teq r3, r6, lsl #16 @ must be 64kiB aligned
#endif
+THUMB( it ne @ cross section branch )
bne __error
str r6, [r7, #4] @ save to __pv_offset
b __fixup_a_pv_table
@@ -496,6 +498,49 @@ ENDPROC(__fixup_pv_table)
.text
__fixup_a_pv_table:
+#ifdef CONFIG_THUMB2_KERNEL
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+ lsls r0, r6, #24
+ lsr r6, #8
+ beq 1f
+ clz r7, r0
+ lsrs r0, #24
+ lsls r0, r7
+ bic r0, 0x0080
+ lsrs r7, #1
+ orrcs r0, #0x0080
+ orr r0, r0, r7, lsl #12
+#endif
+1: lsls r6, #24
+ beq 4f
+ clz r7, r6
+ lsrs r6, #24
+ lsls r6, r7
+ bic r6, #0x0080
+ lsrs r7, #1
+ orrcs r6, #0x0080
+ orr r6, r6, r7, lsl #12
+ orr r6, #0x4000
+ b 4f
+2: add r7, r3
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+ ldrh ip, [r7]
+ tst ip, 0x0400 @ the i bit tells us LS or MS byte
+ beq 3f
+ cmp r0, #0 @ set C flag, and ...
+ biceq ip, 0x0400 @ immediate zero value has a special encoding
+ streqh ip, [r7] @ that requires the i bit cleared
+#endif
+3: ldrh ip, [r7, #2]
+ and ip, 0x8f00
+ orrcc ip, r6 @ mask in offset bits 31-24
+ orrcs ip, r0 @ mask in offset bits 23-16
+ strh ip, [r7, #2]
+4: cmp r4, r5
+ ldrcc r7, [r4], #4 @ use branch for delay slot
+ bcc 2b
+ bx lr
+#else
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
and r0, r6, #255 @ offset bits 23-16
mov r6, r6, lsr #8 @ offset bits 31-24
@@ -513,6 +558,7 @@ __fixup_a_pv_table:
ldrcc r7, [r4], #4 @ use branch for delay slot
bcc 2b
mov pc, lr
+#endif
ENDPROC(__fixup_a_pv_table)
ENTRY(fixup_pv_table)
--
1.7.4
^ permalink raw reply related
* [PATCH 1/2] ARM: ignore mdesc->boot_params if out of range
From: Nicolas Pitre @ 2011-02-12 18:33 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Pitre <nicolas.pitre@linaro.org>
The initial MMU table created in head.S contains a 1 MB mapping at the
start of memory to let the early kernel boot code access the boot params
specified by mdesc->boot_params.
When using CONFIG_ARM_PATCH_PHYS_VIRT it is possible for the kernel to
have a different idea of where the start of memory is at run time, making
the compile-time determined mdesc->boot_params pointing to a memory area
which is not mapped. Any access to the boot params in that case will
fault and silently hang the kernel at that point. It is therefore a
better idea to simply ignore mdesc->boot_params in that case and give
the kernel a chance to print some diagnostic on the console later.
If the bootloader provides a valid pointer in r2 to the kernel then this
is used instead of mdesc->boot_params, and an explicit mapping is already
created in the initial MMU table for it. It is therefore a good idea to
use that facility when using a relocated kernel.
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
---
arch/arm/kernel/setup.c | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 056bf18..729994c 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -853,8 +853,25 @@ void __init setup_arch(char **cmdline_p)
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);
- else if (mdesc->boot_params)
- tags = phys_to_virt(mdesc->boot_params);
+ else if (mdesc->boot_params) {
+#ifdef CONFIG_MMU
+ /*
+ * We still are executing with a minimal MMU mapping created
+ * with the presumption that the machine default for this
+ * is located in the first MB of RAM. Anything else will
+ * fault and silently hang the kernel at this point.
+ */
+ if (mdesc->boot_params < PHYS_OFFSET ||
+ mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
+ printk(KERN_WARNING
+ "Default boot params at physical 0x%08lx out of reach\n",
+ mdesc->boot_params);
+ } else
+#endif
+ {
+ tags = phys_to_virt(mdesc->boot_params);
+ }
+ }
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
/*
--
1.7.4
^ permalink raw reply related
* The p2v branch
From: Nicolas Pitre @ 2011-02-12 18:32 UTC (permalink / raw)
To: linux-arm-kernel
I finally was able to complete this series and test it satisfactorily.
This required some hacking to the OMAP UART debugging code so it would
stop fighting against me and forcefully collaborate.
Now that I've got a PandaBoard I'm getting rather grumpy with some of
that code... Some patches touching that area from me are to be expected
in the near future.
But in the mean time I think you can complete the p2v branch with the
following:
3ecf8ba5 ARM: P2V: eliminate head.S use of PHYS_OFFSET for !XIP_KERNEL
Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
5e8e98cd ARM: P2V: introduce phys_to_virt/virt_to_phys runtime patching
Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
1929d11e ARM: P2V: extend to 16-bit translation offsets
Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
(forced it on with non-msm targets for testing)
b7a0fbb4 ARM: 6648/1: map ATAGs when not in first 1MB of RAM
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
I also have 2 additional patches for this branch to follow:
[PATCH 1/2] ARM: ignore mdesc->boot_params if out of range
[PATCH 2/2] ARM: P2V: Thumb2 support
Nicolas
^ permalink raw reply
* MMC quirks relating to performance/lifetime.
From: Arnd Bergmann @ 2011-02-12 18:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AANLkTikxMKm-Xy5du2+MzrD2eLuvfO9hXrSzBKmAkdBm@mail.gmail.com>
On Saturday 12 February 2011 18:33:10 Andrei Warkentin wrote:
> On Sat, Feb 12, 2011 at 11:05 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Friday 11 February 2011 23:33:42 Andrei Warkentin wrote:
> >> On Wed, Feb 9, 2011 at 3:13 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> >
> >> Yes, this is a Toshiba card. I've sent the patch as a reply to Linus' email.
> >>
> >> cid - 02010053454d3332479070cc51451d00
> >> csd - d00f 0032 0f59 03ff ffffffff92404000
> >> erase_size - 524288
> >> fwrev - 0x0
> >> hwrev - 0x0
> >> manfid - 0x000002
> >> name - SEM32G
> >> oemid - 0x0100
> >> preferred_erase_size - 2097152
> >
>
> This is a Toshiba eMMC part. It is 32GB as far as the OS can see and access.
Ah, right, that explains all the values, which make sense for eMMC4
but not for SDHC ;-)
Arnd
^ 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