* [PATCH v2 2/2] OMAP: omap_device: Add a method to build an omap_device from a DT node
From: Kevin Hilman @ 2011-09-21 21:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E77421C.3000202@ti.com>
"Cousson, Benoit" <b-cousson@ti.com> writes:
> On 9/17/2011 6:13 PM, Grant Likely wrote:
>> On Fri, Sep 16, 2011 at 04:43:19PM +0200, Benoit Cousson wrote:
[...]
>>> +}
>>> +
>>> +static int _omap_device_notifier_call(struct notifier_block *nb,
>>> + unsigned long event, void *dev)
>>
>> Nit: Why the preceding underscore? Generally that is only done for
>> 'special' variants of public functions. ie. for a variant that
>> expects a lock to already be held.
>
> Yeah, the convention in this file is not that strict, and it is used
> for internal static helper function as well.
> I'll let Kevin arbitrate that point :-)
The convention in this file is the leading '_' is used for internal
helper functions.
I'd prefer to keep it that way, and if we decide to change the coding
convention to match a coding convention elsewhere, we should do it all
at the same time.
Kevin
^ permalink raw reply
* change_page_attr() implementation for ARM?
From: Vinod Rex @ 2011-09-21 22:10 UTC (permalink / raw)
To: linux-arm-kernel
On Cortex-A9, we have observed stale data being read from write-combine (C=0 B=1) memory regions mapped into userspace which have a duplicate cacheable mapping in the kernel address space (due to the kernel linear mapping).
The issue appears to be due to speculative prefetch on the cacheable kernel linear mapping which gets lines into the L2 cache. When reads are performed on the write-combine mapping for this address range, these reads get the stale data from L2 instead of memory.
As per the Cortex-A9 spec, behavior for double mappings with conflicting page attributes is undefined, so we need a way to make sure all duplicate mappings have the same memory type attributes.
Similar issue on x86 is handled using the change_page_attr()/set_memory_*() functions defined in arch/x86/mm/pageattr.c. ?This function modifies the attributes of the page in kernel linear map to match the corresponding mapping in userspace to avoid having duplicate mappings with different page attributes. It accomplishes this by splitting section (large page) mappings into 4KB page mappings as needed so that the page attribute change is done only for the requested memory region.
Would a similar implementation for ARM be appropriate? We are experimenting with a port of change_page_attr() to ARM that seems to solve our problems.
Other approaches proposed to solve this on ARM, by remapping CMA reserved region using 4KB page mappings will not help us since IOMMU mappings don't use DMA contiguous allocation routines.
^ permalink raw reply
* [PATCH] arm/tegra: Harmony: Configure PMC for low-level interrupts
From: Stephen Warren @ 2011-09-21 22:10 UTC (permalink / raw)
To: linux-arm-kernel
Without this, the PMC continually detects an interrupt when the PMU_IRQ
line is high, causing the tps6686x IRQ handler thread to hog an entire
CPU.
This change was originally written by Wei Ni <wni@nvidia.com> for Seaboard
in the ChromeOS kernel.
Long-term, this should probably be moved into some kind of PMU driver,
or perhaps integrated into the GPIO/IRQ/pinmux system?
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
arch/arm/mach-tegra/board-harmony-power.c | 13 ++++++++++++-
1 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
index 5ad8b2f..21d1285 100644
--- a/arch/arm/mach-tegra/board-harmony-power.c
+++ b/arch/arm/mach-tegra/board-harmony-power.c
@@ -18,10 +18,11 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-
+#include <linux/io.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/tps6586x.h>
+#include <mach/iomap.h>
#include <mach/irqs.h>
#include "board-harmony.h"
@@ -113,6 +114,16 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
int __init harmony_regulator_init(void)
{
+ void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+ u32 pmc_ctrl;
+
+ /*
+ * Configure the power management controller to trigger PMU
+ * interrupts when low
+ */
+ pmc_ctrl = readl(pmc + PMC_CTRL);
+ writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
+
i2c_register_board_info(3, harmony_regulators, 1);
return 0;
--
1.7.0.4
^ permalink raw reply related
* Link failures due to __bug_table in current -next
From: Simon Glass @ 2011-09-21 22:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110920185121.GA17169@n2100.arm.linux.org.uk>
Hi Russell,
On Tue, Sep 20, 2011 at 11:51 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Tue, Sep 20, 2011 at 10:00:06AM -0700, Simon Glass wrote:
>> On Tue, Sep 20, 2011 at 12:59 AM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>> > It's not that simple though - if you read the quote from the linker manual,
>> > the implication is that the linker would be entirely free to discard an
>> > input section as a priority if it appears in a discard section anywhere
>> > in the linker script. ?There's nothing to say future linkers won't do
>> > this. ?It would still be conformant to the linker manual.
>>
>> Oh dear. That is why it might be a good idea to hassle the linker
>> people, since relying on experiments on how things currently work
>> might be risky if someone leaps in and changes the algorithm.
>
> Or we just ensure that we conform to the apparant looseness of the
> manual, and make the addition of EXIT_TEXT etc in DISCARDS conditional
> (which is effectively what I'm doing with my patch.)
Yes that is safer for the moment.
>
> That means we're no longer reliant on trusting the linker to do what
> we want for this (we _do_ still trust it for the unwind information,
> but I think that's less of an issue.)
>
>> Hmm even more out there, I wonder if we can modify the BUG macro to
>> put the bug table entry into one of two separate depending on whether
>> BUG is in an __exit function or not? Then at link time, either concat
>> the two tables, or just ignore the exit one...
>
> That was the same thought for the SMP alternatives problem - I think
> Nicolas proposed that there should be some way that the linker can
> do sections based on the current section name. ?That'd allow us to
> have .alt.smp.exit.text and __bug_table.exit.text etc.
Yes
>
>> In any case, it sounds from the next email in this thread that your
>> patch has fixed the problem! So, where does that leave us?
>
> I think we apply the patch, which resolves the problem, and point it
> out to whoever looks after the asm-generic/vmlinux.lds.S file (Arnd?
> I'll check when I re-dock the laptop later this evening.) ?I suspect
> Arnd is already reading some of these messages...
>
Sounds good to me, and thanks for finding that solution.
Regards,
Simon
^ permalink raw reply
* Link failures due to __bug_table in current -next
From: Simon Glass @ 2011-09-21 22:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1109201546400.12663@xanadu.home>
Hi Nicolas,
On Tue, Sep 20, 2011 at 12:57 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> On Tue, 20 Sep 2011, Russell King - ARM Linux wrote:
>
>> On Tue, Sep 20, 2011 at 10:00:06AM -0700, Simon Glass wrote:
>> > Hmm even more out there, I wonder if we can modify the BUG macro to
>> > put the bug table entry into one of two separate depending on whether
>> > BUG is in an __exit function or not? Then at link time, either concat
>> > the two tables, or just ignore the exit one...
>>
>> That was the same thought for the SMP alternatives problem - I think
>> Nicolas proposed that there should be some way that the linker can
>> do sections based on the current section name. ?That'd allow us to
>> have .alt.smp.exit.text and __bug_table.exit.text etc.
>
> Initially that was proposed by Dave Martin, then I tried to push things
> ahead a bit in the Linaro toolchain work group.
>
> The thread with the latest exchanges can be viewed here:
> http://news.gmane.org/group/gmane.linux.linaro.toolchain/thread=1270
The thread is from July. Does that mean it is dead?
>
> In a nutshell, it seems that enhancing gas to support this isn't
> trivial, and we are asked how beneficial (i.e. how much smaller the
> kernel image would be if all those sections could actually be split and
> discarded at link time) this would be to justify the effort.
Well it's probably not a huge benefit in terms of kernel size. Exit
code tends to be relatively small, and many distributions use modules
extensively now anyway. But there is also the issue of the workarounds
in the lds file, and where this might lead in the years ahead.
Would it be easier / less intrusive to add a new .pushsubsection
directive which prepends the current section name to the name you give
it?
Regards,
Simon
>
>
> Nicolas
>
^ permalink raw reply
* [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII
From: Barry Song @ 2011-09-21 23:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316618267-4348-4-git-send-email-21cnbao@gmail.com>
2011/9/21 Barry Song <21cnbao@gmail.com>:
> From: Rongjun Ying <rongjun.ying@csr.com>
>
> This patch adds suspend-to-mem support for prima2. It will make prima2
> enter DEEPSLEEP mode while accepting PM_SUSPEND_MEM command.
>
> Signed-off-by: Rongjun Ying <baohua.song@csr.com>
sorry for typo. it should be:
Signed-off-by: Rongjun Ying <rongjun.ying@csr.com>
this was fixed in repository for pull.
> Signed-off-by: Barry Song <baohua.song@csr.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> ---
> -v2:
> ?don't call l2x0_of_init after resuming as Shawn's patch[1] seems
> ?not to be applied;
> ?Since people still need some time to figure out the best way for l2
> ?resume, we move the l2 re-init to bootloader for the moment to keep
> ?things go ahead.
>
> ?arch/arm/mach-prima2/Makefile | ? ?1 +
> ?arch/arm/mach-prima2/pm.c ? ? | ?149 +++++++++++++++++++++++++++++++++++++++++
> ?arch/arm/mach-prima2/pm.h ? ? | ? 31 +++++++++
> ?arch/arm/mach-prima2/sleep.S ?| ? 64 ++++++++++++++++++
> ?4 files changed, 245 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/mach-prima2/pm.c
> ?create mode 100644 arch/arm/mach-prima2/pm.h
> ?create mode 100644 arch/arm/mach-prima2/sleep.S
>
> diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
> index f49d70b..13dd160 100644
> --- a/arch/arm/mach-prima2/Makefile
> +++ b/arch/arm/mach-prima2/Makefile
> @@ -6,3 +6,4 @@ obj-y += prima2.o
> ?obj-y += rtciobrg.o
> ?obj-$(CONFIG_DEBUG_LL) += lluart.o
> ?obj-$(CONFIG_CACHE_L2X0) += l2x0.o
> +obj-$(CONFIG_SUSPEND) += pm.o sleep.o
> diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c
> new file mode 100644
> index 0000000..0ba39f3
> --- /dev/null
> +++ b/arch/arm/mach-prima2/pm.c
> @@ -0,0 +1,149 @@
> +/*
> + * power management entry for CSR SiRFprimaII
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/suspend.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/io.h>
> +#include <linux/rtc/sirfsoc_rtciobrg.h>
> +#include <asm/suspend.h>
> +#include <asm/hardware/cache-l2x0.h>
> +
> +#include "pm.h"
> +
> +/*
> + * suspend asm codes will access these to make DRAM become self-refresh and
> + * system sleep
> + */
> +u32 sirfsoc_pwrc_base;
> +void __iomem *sirfsoc_memc_base;
> +
> +static void sirfsoc_set_wakeup_source(void)
> +{
> + ? ? ? u32 pwr_trigger_en_reg;
> + ? ? ? pwr_trigger_en_reg = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base +
> + ? ? ? ? ? ? ? SIRFSOC_PWRC_TRIGGER_EN);
> +#define X_ON_KEY_B (1 << 0)
> + ? ? ? sirfsoc_rtc_iobrg_writel(pwr_trigger_en_reg | X_ON_KEY_B,
> + ? ? ? ? ? ? ? sirfsoc_pwrc_base + SIRFSOC_PWRC_TRIGGER_EN);
> +}
> +
> +static void sirfsoc_set_sleep_mode(u32 mode)
> +{
> + ? ? ? u32 sleep_mode = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base +
> + ? ? ? ? ? ? ? SIRFSOC_PWRC_PDN_CTRL);
> + ? ? ? sleep_mode &= ~(SIRFSOC_SLEEP_MODE_MASK << 1);
> + ? ? ? sleep_mode |= mode << 1;
> + ? ? ? sirfsoc_rtc_iobrg_writel(sleep_mode, sirfsoc_pwrc_base +
> + ? ? ? ? ? ? ? SIRFSOC_PWRC_PDN_CTRL);
> +}
> +
> +static int sirfsoc_pre_suspend_power_off(void)
> +{
> + ? ? ? u32 wakeup_entry = virt_to_phys(cpu_resume);
> +
> + ? ? ? sirfsoc_rtc_iobrg_writel(wakeup_entry, sirfsoc_pwrc_base +
> + ? ? ? ? ? ? ? SIRFSOC_PWRC_SCRATCH_PAD1);
> +
> + ? ? ? sirfsoc_set_wakeup_source();
> +
> + ? ? ? sirfsoc_set_sleep_mode(SIRFSOC_DEEP_SLEEP_MODE);
> +
> + ? ? ? return 0;
> +}
> +
> +static int sirfsoc_pm_enter(suspend_state_t state)
> +{
> + ? ? ? switch (state) {
> + ? ? ? case PM_SUSPEND_MEM:
> + ? ? ? ? ? ? ? sirfsoc_pre_suspend_power_off();
> +
> + ? ? ? ? ? ? ? outer_flush_all();
> + ? ? ? ? ? ? ? outer_disable();
> + ? ? ? ? ? ? ? /* go zzz */
> + ? ? ? ? ? ? ? cpu_suspend(0, sirfsoc_finish_suspend);
> + ? ? ? ? ? ? ? break;
> + ? ? ? default:
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> + ? ? ? return 0;
> +}
> +
> +static const struct platform_suspend_ops sirfsoc_pm_ops = {
> + ? ? ? .enter = sirfsoc_pm_enter,
> + ? ? ? .valid = suspend_valid_only_mem,
> +};
> +
> +static int __init sirfsoc_pm_init(void)
> +{
> + ? ? ? suspend_set_ops(&sirfsoc_pm_ops);
> + ? ? ? return 0;
> +}
> +late_initcall(sirfsoc_pm_init);
> +
> +static const struct of_device_id pwrc_ids[] = {
> + ? ? ? { .compatible = "sirf,prima2-pwrc" },
> + ? ? ? {}
> +};
> +
> +static int __init sirfsoc_of_pwrc_init(void)
> +{
> + ? ? ? struct device_node *np;
> +
> + ? ? ? np = of_find_matching_node(NULL, pwrc_ids);
> + ? ? ? if (!np)
> + ? ? ? ? ? ? ? panic("unable to find compatible pwrc node in dtb\n");
> +
> + ? ? ? /*
> + ? ? ? ?* pwrc behind rtciobrg is not located in memory space
> + ? ? ? ?* though the property is named reg. reg only means base
> + ? ? ? ?* offset for pwrc. then of_iomap is not suitable here.
> + ? ? ? ?*/
> + ? ? ? if (of_property_read_u32(np, "reg", &sirfsoc_pwrc_base))
> + ? ? ? ? ? ? ? panic("unable to find base address of pwrc node in dtb\n");
> +
> + ? ? ? of_node_put(np);
> +
> + ? ? ? return 0;
> +}
> +postcore_initcall(sirfsoc_of_pwrc_init);
> +
> +static const struct of_device_id memc_ids[] = {
> + ? ? ? { .compatible = "sirf,prima2-memc" },
> + ? ? ? {}
> +};
> +
> +static int __devinit sirfsoc_memc_probe(struct platform_device *op)
> +{
> + ? ? ? struct device_node *np = op->dev.of_node;
> +
> + ? ? ? sirfsoc_memc_base = of_iomap(np, 0);
> + ? ? ? if (!sirfsoc_memc_base)
> + ? ? ? ? ? ? ? panic("unable to map memc registers\n");
> +
> + ? ? ? return 0;
> +}
> +
> +static struct platform_driver sirfsoc_memc_driver = {
> + ? ? ? .probe ? ? ? ? ?= sirfsoc_memc_probe,
> + ? ? ? .driver = {
> + ? ? ? ? ? ? ? .name = "sirfsoc-memc",
> + ? ? ? ? ? ? ? .owner = THIS_MODULE,
> + ? ? ? ? ? ? ? .of_match_table = memc_ids,
> + ? ? ? },
> +};
> +
> +static int __init sirfsoc_memc_init(void)
> +{
> + ? ? ? return platform_driver_register(&sirfsoc_memc_driver);
> +}
> +postcore_initcall(sirfsoc_memc_init);
> diff --git a/arch/arm/mach-prima2/pm.h b/arch/arm/mach-prima2/pm.h
> new file mode 100644
> index 0000000..aa2b428
> --- /dev/null
> +++ b/arch/arm/mach-prima2/pm.h
> @@ -0,0 +1,31 @@
> +/*
> + * arch/arm/mach-prima2/pm.h
> + *
> + * Copyright (C) 2011 CSR
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _MACH_PRIMA2_PM_H_
> +#define _MACH_PRIMA2_PM_H_
> +
> +#define SIRFSOC_PWR_SLEEPFORCE ? ? ? ? 0x01
> +
> +#define SIRFSOC_SLEEP_MODE_MASK ? ? ? ? 0x3
> +#define SIRFSOC_DEEP_SLEEP_MODE ? ? ? ? 0x1
> +
> +#define SIRFSOC_PWRC_PDN_CTRL ? ? ? ? ? 0x0
> +#define SIRFSOC_PWRC_PON_OFF ? ? ? ? ? ?0x4
> +#define SIRFSOC_PWRC_TRIGGER_EN ? ? ? ? 0x8
> +#define SIRFSOC_PWRC_PIN_STATUS ? ? ? ? 0x14
> +#define SIRFSOC_PWRC_SCRATCH_PAD1 ? ? ? 0x18
> +#define SIRFSOC_PWRC_SCRATCH_PAD2 ? ? ? 0x1C
> +
> +#ifndef __ASSEMBLY__
> +extern int sirfsoc_finish_suspend(unsigned long);
> +#endif
> +
> +#endif
> +
> diff --git a/arch/arm/mach-prima2/sleep.S b/arch/arm/mach-prima2/sleep.S
> new file mode 100644
> index 0000000..0745abc
> --- /dev/null
> +++ b/arch/arm/mach-prima2/sleep.S
> @@ -0,0 +1,64 @@
> +/*
> + * sleep mode for CSR SiRFprimaII
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/ptrace.h>
> +#include <asm/assembler.h>
> +
> +#include "pm.h"
> +
> +#define DENALI_CTL_22_OFF ? ? ?0x58
> +#define DENALI_CTL_112_OFF ? ? 0x1c0
> +
> + ? ? ? .text
> +
> +ENTRY(sirfsoc_finish_suspend)
> + ? ? ? @ r5: ? mem controller
> + ? ? ? ldr ? ? r0, =sirfsoc_memc_base
> + ? ? ? ldr ? ? r5, [r0]
> + ? ? ? @ r6: ? pwrc base offset
> + ? ? ? ldr ? ? r0, =sirfsoc_pwrc_base
> + ? ? ? ldr ? ? r6, [r0]
> + ? ? ? @ r7: ? rtc iobrg controller
> + ? ? ? ldr ? ? r0, =sirfsoc_rtciobrg_base
> + ? ? ? ldr ? ? r7, [r0]
> +
> + ? ? ? @ Read the power control register and set the
> + ? ? ? @ sleep force bit.
> + ? ? ? add ? ? r0, r6, #SIRFSOC_PWRC_PDN_CTRL
> + ? ? ? bl ? ? ?__sirfsoc_rtc_iobrg_readl
> + ? ? ? orr ? ? r0,r0,#SIRFSOC_PWR_SLEEPFORCE
> + ? ? ? add ? ? r1, r6, #SIRFSOC_PWRC_PDN_CTRL
> + ? ? ? bl ? ? ?sirfsoc_rtc_iobrg_pre_writel
> + ? ? ? mov ? ? r1, #0x1
> +
> + ? ? ? @ read the MEM ctl register and set the self
> + ? ? ? @ refresh bit
> +
> + ? ? ? ldr ? ? r2, [r5, #DENALI_CTL_22_OFF]
> + ? ? ? orr ? ? r2, r2, #0x1
> +
> + ? ? ? @ Following code has to run from cache since
> + ? ? ? @ the RAM is going to self refresh mode
> + ? ? ? .align 5
> + ? ? ? str ? ? r2, [r5, #DENALI_CTL_22_OFF]
> +
> +1:
> + ? ? ? ldr ? ? r4, [r5, #DENALI_CTL_112_OFF]
> + ? ? ? tst ? ? r4, #0x1
> + ? ? ? bne ? ? 1b
> +
> + ? ? ? @ write SLEEPFORCE through rtc iobridge
> +
> + ? ? ? str ? ? r1, [r7]
> + ? ? ? @ wait rtc io bridge sync
> +1:
> + ? ? ? ldr ? ? r3, [r7]
> + ? ? ? tst ? ? r3, #0x01
> + ? ? ? bne ? ? 1b
> + ? ? ? b .
> --
> 1.7.0.4
>
>
^ permalink raw reply
* [PATCH] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Barry Song @ 2011-09-22 0:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABb+yY2L=wfRoascoriAcnNMKkV7LbQEHCpp78+rCY=aM46x7A@mail.gmail.com>
2011/9/21 Jassi Brar <jassisinghbrar@gmail.com>:
> On Fri, Sep 16, 2011 at 3:13 PM, Barry Song <Baohua.Song@csr.com> wrote:
>> dma_async_device_register will re-init chan_id and chancnt,
>> so whatever chan_id and chancnt are set in drivers, they will
>> be re-written by dma_async_device_register.
>>
>> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
>> Cc: Viresh Kumar <viresh.kumar@st.com>
>> Cc: Vinod Koul <vinod.koul@intel.com>
>> Cc: Piotr Ziecik <kosmo@semihalf.com>
>> Cc: Yong Wang <yong.y.wang@intel.com>
>> Cc: Jaswinder Singh <jassi.brar@samsung.com>
>> Cc: Pelagicore AB <info@pelagicore.com>
>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>> ---
>> ?drivers/dma/at_hdmac.c ? ? ?| ? ?5 ++---
>> ?drivers/dma/dw_dmac.c ? ? ? | ? ?5 ++---
>> ?drivers/dma/intel_mid_dma.c | ? ?2 --
>> ?drivers/dma/mpc512x_dma.c ? | ? ?1 -
>> ?drivers/dma/pch_dma.c ? ? ? | ? ?2 --
>> ?drivers/dma/pl330.c ? ? ? ? | ? ?2 --
>> ?drivers/dma/timb_dma.c ? ? ?| ? ?3 +--
>
> Apparently ....
>
> drivers/dma/ppc4xx/adma.c
> drivers/dma/ipu/ipu_idmac.c
> ? ? ? still write to chan_id.
>
> drivers/dma/amba-pl08x.c
> drivers/dma/fsldma.c
> drivers/dma/ioat/dma_v2.c
> drivers/dma/ioat/dma.c
> drivers/dma/mpc512x_dma.c
> drivers/dma/shdma.c
> ? ? ? still write to chancnt
>
> Most of them are simply a matter of removal, but some seem
> like really depending upon setting them(?)
>
> Anyways, even after you modify those as well, chan_id and chancnt
> are rendered overstaying guests in dmaengine core. Because chan_id
> of each channel would be _precisely_ the order in which the
> _dmac-driver_ added the channel to the 'channels' list.
>
> So if their values are _always_ gonna be just contiguously incrementing
> why need variables for that in the dmaengine api?
> Dmac drivers could use local variables for that.
>
> OTOH, why not chan_id be left solely for use by dmac drivers read by the
> dmaengine only to create sysfs entries ?
actually i don't like the way dmaengine core handles chan_id. in my
opinion, every dmac only needs to tell dmaengine core the chan_base.
then dmaengine core set the id in a global scale.
for example, if you have two dmac in system:
dmac0 chan_base 0
dmac1 chan_base 16
then core will have chan 0~31 by chan_id from 0 to 31 but not
dmac0chan0~15, dmac1chan0~15.
client drivers can request a specific chan_id just like it can request a gpio.
now dmac drivers and dmaengine core have repeated chan_id and chancnt,
anyway, it is a problem that should be fixed at first. then i'd like
to have some common function to support the request of specific
chan_id.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
-barry
^ permalink raw reply
* [PATCH v2 1/3] TI81XX: Prepare for addition of TI814X support
From: Pedanekar, Hemant @ 2011-09-22 0:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110921204057.GJ2937@atomide.com>
Tony Lindgren wrote on Thursday, September 22, 2011 2:11 AM:
> * Hemant Pedanekar <hemantp@ti.com> [110921 10:05]:
>> --- a/arch/arm/mach-omap2/board-ti8168evm.c
>> +++ b/arch/arm/mach-omap2/board-ti8168evm.c
>> @@ -37,16 +37,16 @@ static void __init ti8168_evm_init(void)
>>
>> static void __init ti8168_evm_map_io(void)
>> {
>> - omap2_set_globals_ti816x();
>> - omapti816x_map_common_io();
>> + omap2_set_globals_ti81xx();
>> + omapti81xx_map_common_io();
>> }
>>
>> MACHINE_START(TI8168EVM, "ti8168evm")
>> /* Maintainer: Texas Instruments */
>> .atag_offset = 0x100,
>> .map_io = ti8168_evm_map_io,
>> - .init_early = ti816x_init_early,
>> - .init_irq = ti816x_init_irq,
>> + .init_early = ti81xx_init_early,
>> + .init_irq = ti81xx_init_irq,
>> .timer = &omap3_timer,
>> .init_machine = ti8168_evm_init,
>> MACHINE_END
>
> Looks like you still need a minor rebase on the current cleanup
> branch as the ti8668_evm_map_io is no longer needed. The cleanup
> branch already has Paul's CHIP_IS removal, so that should be trivial.
>
Tony,
Can you please clarify? Do we not need ti8168_evm_map_io() for global data
initianlization and io init? Or, as you mentioned in comment on 3/3 of the
series, do you mean to rename this with ti81xx and move to common.c?
> Ideally the rename patch would be separate without any functional
> changes, maybe you can move the changes and additions to the next patch?
>
> Tony
If the above understanding is correct, then I will just have to rename+move
ti8168_evm_map_io() so the change can still be in this patch, right? Or are
You referring to any other part which should not be in this patch?
Thanks.
Hemant
^ permalink raw reply
* [PATCH v2 3/3] TI814X: Create board support and enable build for TI8148 EVM
From: Pedanekar, Hemant @ 2011-09-22 0:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110921204826.GK2937@atomide.com>
Tony Lindgren wrote on Thursday, September 22, 2011 2:18 AM:
> * Hemant Pedanekar <hemantp@ti.com> [110921 10:05]:
>> +
>> +static struct omap_board_config_kernel ti8148_evm_config[] __initdata = {
>> +}; +
>> +static void __init ti8148_evm_init(void)
>> +{
>> + omap_serial_init();
>> + omap_board_config = ti8148_evm_config;
>> + omap_board_config_size = ARRAY_SIZE(ti8148_evm_config); +}
>> +
>> +static void __init ti8148_evm_map_io(void)
>> +{
>> + omap2_set_globals_ti81xx();
>> + omapti81xx_map_common_io();
>> +}
>
> Hmm I guess we still have board specific map_io in board-ti8668evm.c
> also. Those would be better replaced with ti81xx_map_io in
> mach-omap2/common.c. Care to take a look at that?
>
Yes, you are right. I will do that.
>> +MACHINE_START(TI8148EVM, "ti8148evm")
>> + /* Maintainer: Texas Instruments */
>> + .atag_offset = 0x100,
>> + .map_io = ti8148_evm_map_io,
>> + .init_early = ti81xx_init_early,
>> + .init_irq = ti81xx_init_irq,
>> + .timer = &omap3_timer,
>> + .init_machine = ti8148_evm_init,
>> +MACHINE_END
>
> Please add this all to board-ti8168evm.c instead of adding a new
> board-*.c file. With the upcoming device tree conversion most of these will
> disappear anyways.
>
Ok, I will do that.
Thanks.
Hemant
> Regards,
>
> Tony
Hemant
^ permalink raw reply
* [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
From: Tony Lindgren @ 2011-09-22 0:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-11-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> The request functions now verify the success of omap_dm_timer_prepare() call
> after a timer is acquired. If *_prepare() fails then we have to release the
> timer. In order to avoid race condition during this time, include *_prepare()
> within lock.
This I've folded into patch 5.
Tony
^ permalink raw reply
* [GIT PULL] omap cleanup part1 for v3.2 merge window
From: Tony Lindgren @ 2011-09-22 0:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1836081.h7sKlomlak@wuerfel>
* Arnd Bergmann <arnd@arndb.de> [110920 23:34]:
> On Tuesday 20 September 2011 15:33:12 Tony Lindgren wrote:
> > * Arnd Bergmann <arnd@arndb.de> [110920 14:12]:
> > > On Tuesday 20 September 2011, Arnd Bergmann wrote:
> > > >
> > > > One more thing: my randconfig tests are running now and
> > > > have spit out a new error after merging lost of stuff
> > > > today:
> >
> > Good to hear you got "arndconfig" running :)
> >
> > Do you think we could also add support for something
> > like this:
> >
> > $ echo CONFIG_ARCH_OMAP=y > .config
> > $ make randconfig
> >
> > or
> >
> > $ make --force=CONFIG_ARCH_OMAP randconfig
> >
> > Where randconfig would keep the forced CONFIG_ARCH_OMAP
> > static while randomly selecting the others?
> >
> > This would allow targeted randconfig for each patch more
> > or less..
>
> The mechanism I use is setting KCONFIG_ALLCONFIG= to a file
> that has the options I want to have set to a specific value.
>
> If you don't do that, randconfig will take the default option
> for each 'choice' statement, which means we build for the
> ARCH_VERSATILE platform.
>
> See the script I'm using at the end of this mail. It should
> be easy for you to pick out the parts you need.
Thanks will take a look at that for sure.
Tony
^ permalink raw reply
* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
From: Tony Lindgren @ 2011-09-22 0:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-1-git-send-email-tarun.kanti@ti.com>
Hi Tarun,
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> Adaptation of dmtimer code to platform driver using omap_device and
> omap_hwmod abstraction. It also include pm-runtime and off-mode support.
I've applied these into dmtimer branch with some changes to simplify
things further. I've also merged it into linux-omap master branch
for further testing.
I'll reply to your patches with the changes I've done. Care give the
dmtimer branch a try and see if I've missed something?
Regards,
Tony
^ permalink raw reply
* [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
From: Tony Lindgren @ 2011-09-22 1:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-9-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -514,10 +514,23 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> timer->irq = irq->start;
> timer->pdev = pdev;
>
> - /* Skip pm_runtime_enable for OMAP1 */
> - if (!pdata->needs_manual_reset) {
> - pm_runtime_enable(&pdev->dev);
> - pm_runtime_irq_safe(&pdev->dev);
> +/*
> + * sys_timer_reserved is not defined for OMAP1.
> + * Use the macro to avoid compilation error on OMAP1.
> + */
> +#if defined(CONFIG_ARCH_OMAP2PLUS)
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_irq_safe(&pdev->dev);
> + /* Mark clocksource and clockevent timers as reserved */
> + if ((sys_timer_reserved >> (pdev->id - 1)) & 0x1)
> + timer->reserved = 1;
> +#endif
> +
> + if (!timer->reserved) {
> + pm_runtime_get_sync(&pdev->dev);
> + __omap_dm_timer_init_regs(timer);
> + timer->tidr = __raw_readl(timer->io_base);
> + pm_runtime_put(&pdev->dev);
> }
>
> /* add the timer element to the list */
This all should not be necessary. We can pass the reserved flag
in pdata. Let's replace this one with the patch below.
Regards,
Tony
From: Tony Lindgren <tony@atomide.com>
Date: Wed, 21 Sep 2011 16:38:51 -0700
Subject: [PATCH] ARM: OMAP: dmtimer: skip reserved timers
Pass the reserved flag in pdata and use it. We can
now make sys_timer_reserved static to mach-omap2/timer.c.
Signed-off-by: Tony Lindgren <tony@atomide.com>
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 9c2f588..f1e3ec1 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -69,7 +69,7 @@
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
#define MAX_GPTIMER_ID 12
-u32 sys_timer_reserved;
+static u32 sys_timer_reserved;
/* Clockevent code */
@@ -463,6 +463,10 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
pdata->set_timer_src = omap2_dm_timer_set_src;
pdata->timer_ip_version = oh->class->rev;
+ /* Mark clocksource and clockevent timers as reserved */
+ if ((sys_timer_reserved >> (id - 1)) & 0x1)
+ pdata->reserved = 1;
+
od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
omap2_dmtimer_latency,
ARRAY_SIZE(omap2_dmtimer_latency),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index ac904c2..c8df3c3 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -509,6 +509,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
timer->id = pdev->id;
timer->irq = irq->start;
+ timer->reserved = pdata->reserved;
timer->pdev = pdev;
/* Skip pm_runtime_enable for OMAP1 */
@@ -517,6 +518,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
pm_runtime_irq_safe(&pdev->dev);
}
+ if (!timer->reserved) {
+ pm_runtime_get_sync(&pdev->dev);
+ __omap_dm_timer_init_regs(timer);
+ pm_runtime_put(&pdev->dev);
+ }
+
/* add the timer element to the list */
spin_lock_irqsave(&dm_timer_lock, flags);
list_add_tail(&timer->node, &omap_timer_list);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 4e3a326..29764c3 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -77,6 +77,7 @@ struct dmtimer_platform_data {
int (*set_timer_src)(struct platform_device *pdev, int source);
int timer_ip_version;
u32 needs_manual_reset:1;
+ bool reserved;
};
struct omap_dm_timer *omap_dm_timer_request(void);
@@ -248,7 +249,6 @@ struct omap_dm_timer {
struct list_head node;
};
-extern u32 sys_timer_reserved;
int omap_dm_timer_prepare(struct omap_dm_timer *timer);
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
^ permalink raw reply related
* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
From: Tony Lindgren @ 2011-09-22 1:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-10-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> Clock is enabled only when timer is started and disabled when the the timer
> is stopped. Therefore before accessing registers in functions clock is enabled
> and then disabled back at the end of access. Context save is done dynamically
> whenever the registers are modified. Context restore is called when context is
> lost.
I've updated this to use revision instead of tidr. Updated patch below.
Regards,
Tony
From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Tue, 20 Sep 2011 17:00:24 +0530
Subject: [PATCH] ARM: OMAP: dmtimer: low-power mode support
Clock is enabled only when timer is started and disabled when the the timer
is stopped. Therefore before accessing registers in functions clock is enabled
and then disabled back at the end of access. Context save is done dynamically
whenever the registers are modified. Context restore is called when context is
lost.
Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[tony at atomide.com: updated to use revision instead of tidr]
Signed-off-by: Tony Lindgren <tony@atomide.com>
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index f1e3ec1..1140e98 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -44,6 +44,9 @@
#include <plat/common.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#include "powerdomain.h"
/* Parent clocks, eventually these will come from the clock framework */
@@ -433,6 +436,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
struct dmtimer_platform_data *pdata;
struct omap_device *od;
struct omap_timer_capability_dev_attr *timer_dev_attr;
+ struct powerdomain *pwrdm;
pr_debug("%s: %s\n", __func__, oh->name);
@@ -467,6 +471,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
if ((sys_timer_reserved >> (id - 1)) & 0x1)
pdata->reserved = 1;
+ pwrdm = omap_hwmod_get_pwrdm(oh);
+ pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+#ifdef CONFIG_PM
+ pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+#endif
od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
omap2_dmtimer_latency,
ARRAY_SIZE(omap2_dmtimer_latency),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index c8df3c3..43eb750 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
__omap_dm_timer_write(timer, reg, value, timer->posted);
}
+static void omap_timer_restore_context(struct omap_dm_timer *timer)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+ timer->context.tiocp_cfg);
+ 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);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
+ timer->context.tcrr);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+ timer->context.tldr);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
+ timer->context.tmar);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+ timer->context.tsicr);
+ __raw_writel(timer->context.tier, timer->irq_ena);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
+ timer->context.tclr);
+}
+
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
{
int c;
@@ -96,12 +119,14 @@ 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_disable(timer);
timer->posted = 1;
}
@@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
return -EINVAL;
}
- omap_dm_timer_enable(timer);
-
if (pdata->needs_manual_reset)
omap_dm_timer_reset(timer);
@@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
void omap_dm_timer_free(struct omap_dm_timer *timer)
{
- omap_dm_timer_disable(timer);
clk_put(timer->fclk);
WARN_ON(!timer->reserved);
@@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
void omap_dm_timer_trigger(struct omap_dm_timer *timer)
{
+ if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+ pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+ return;
+ }
+
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
{
u32 l;
+ omap_dm_timer_enable(timer);
+
+ if (timer->loses_context) {
+ u32 ctx_loss_cnt_after =
+ timer->get_context_loss_count(&timer->pdev->dev);
+ if (ctx_loss_cnt_after != timer->ctx_loss_count)
+ omap_timer_restore_context(timer);
+ }
+
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (!(l & OMAP_TIMER_CTRL_ST)) {
l |= OMAP_TIMER_CTRL_ST;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
+
+ /* Save the context */
+ timer->context.tclr = l;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
@@ -311,9 +350,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
if (source < 0 || source >= 3)
return -EINVAL;
- omap_dm_timer_disable(timer);
ret = pdata->set_timer_src(timer->pdev, source);
- omap_dm_timer_enable(timer);
return ret;
}
@@ -324,6 +361,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
{
u32 l;
+ omap_dm_timer_enable(timer);
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (autoreload)
l |= OMAP_TIMER_CTRL_AR;
@@ -333,6 +371,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+ /* Save the context */
+ timer->context.tclr = l;
+ timer->context.tldr = load;
+ omap_dm_timer_disable(timer);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
@@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
{
u32 l;
+ omap_dm_timer_enable(timer);
+
+ if (timer->loses_context) {
+ u32 ctx_loss_cnt_after =
+ timer->get_context_loss_count(&timer->pdev->dev);
+ if (ctx_loss_cnt_after != timer->ctx_loss_count)
+ omap_timer_restore_context(timer);
+ }
+
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (autoreload) {
l |= OMAP_TIMER_CTRL_AR;
@@ -352,6 +403,11 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
l |= OMAP_TIMER_CTRL_ST;
__omap_dm_timer_load_start(timer, l, load, timer->posted);
+
+ /* Save the context */
+ timer->context.tclr = l;
+ timer->context.tldr = load;
+ timer->context.tcrr = load;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
@@ -360,6 +416,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
{
u32 l;
+ omap_dm_timer_enable(timer);
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (enable)
l |= OMAP_TIMER_CTRL_CE;
@@ -367,6 +424,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
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);
+
+ /* Save the context */
+ timer->context.tclr = l;
+ timer->context.tmar = match;
+ omap_dm_timer_disable(timer);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
@@ -375,6 +437,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
{
u32 l;
+ omap_dm_timer_enable(timer);
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
OMAP_TIMER_CTRL_PT | (0x03 << 10));
@@ -384,6 +447,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
l |= OMAP_TIMER_CTRL_PT;
l |= trigger << 10;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+ /* Save the context */
+ timer->context.tclr = l;
+ omap_dm_timer_disable(timer);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
@@ -391,6 +458,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
{
u32 l;
+ omap_dm_timer_enable(timer);
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -398,13 +466,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
l |= prescaler << 2;
}
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+ /* Save the context */
+ timer->context.tclr = l;
+ omap_dm_timer_disable(timer);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
unsigned int value)
{
+ omap_dm_timer_enable(timer);
__omap_dm_timer_int_enable(timer, value);
+
+ /* Save the context */
+ timer->context.tier = value;
+ timer->context.twer = value;
+ omap_dm_timer_disable(timer);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
@@ -412,6 +490,11 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
unsigned int l;
+ if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+ pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+ return 0;
+ }
+
l = __raw_readl(timer->irq_stat);
return l;
@@ -421,18 +504,33 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
{
__omap_dm_timer_write_status(timer, value);
+ /* Save the context */
+ timer->context.tisr = value;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
{
+ if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+ pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+ return 0;
+ }
+
return __omap_dm_timer_read_counter(timer, timer->posted);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
{
+ if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+ pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+ return;
+ }
+
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+ /* Save the context */
+ timer->context.tcrr = value;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
@@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
timer->irq = irq->start;
timer->reserved = pdata->reserved;
timer->pdev = pdev;
+ timer->loses_context = pdata->loses_context;
+ timer->get_context_loss_count = pdata->get_context_loss_count;
/* Skip pm_runtime_enable for OMAP1 */
if (!pdata->needs_manual_reset) {
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 29764c3..9519d87 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -73,11 +73,38 @@ struct omap_timer_capability_dev_attr {
struct omap_dm_timer;
struct clk;
+struct timer_regs {
+ u32 tidr;
+ u32 tiocp_cfg;
+ u32 tistat;
+ u32 tisr;
+ u32 tier;
+ u32 twer;
+ u32 tclr;
+ u32 tcrr;
+ u32 tldr;
+ u32 ttrg;
+ u32 twps;
+ u32 tmar;
+ u32 tcar1;
+ u32 tsicr;
+ u32 tcar2;
+ u32 tpir;
+ u32 tnir;
+ u32 tcvr;
+ u32 tocr;
+ u32 towr;
+};
+
struct dmtimer_platform_data {
int (*set_timer_src)(struct platform_device *pdev, int source);
int timer_ip_version;
u32 needs_manual_reset:1;
bool reserved;
+
+ bool loses_context;
+
+ u32 (*get_context_loss_count)(struct device *dev);
};
struct omap_dm_timer *omap_dm_timer_request(void);
@@ -245,8 +272,14 @@ struct omap_dm_timer {
unsigned long rate;
unsigned reserved:1;
unsigned posted:1;
+ struct timer_regs context;
+ bool loses_context;
+ int ctx_loss_count;
+ int revision;
struct platform_device *pdev;
struct list_head node;
+
+ u32 (*get_context_loss_count)(struct device *dev);
};
int omap_dm_timer_prepare(struct omap_dm_timer *timer);
@@ -278,6 +311,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
/* Assume v1 ip if bits [31:16] are zero */
tidr = __raw_readl(timer->io_base);
if (!(tidr >> 16)) {
+ timer->revision = 1;
timer->sys_stat = timer->io_base +
OMAP_TIMER_V1_SYS_STAT_OFFSET;
timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
@@ -286,6 +320,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
timer->func_base = timer->io_base;
} else {
+ timer->revision = 2;
timer->sys_stat = 0;
timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
^ permalink raw reply related
* [PATCH v16 12/12] OMAP: dmtimer: get rid of timer_ip_version field
From: Tony Lindgren @ 2011-09-22 1:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-13-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> We do not need this field in dmtimer_platform_data{} anymore.
> Instead, read "tidr" register to identify the ip version now.
Let's wait a bit on this one as Benoit had some comments regarding
the use of tidr.
Regards,
Tony
^ permalink raw reply
* [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
From: Tony Lindgren @ 2011-09-22 1:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-2-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> Add device name to OMAP2 dmtimer fclk nodes so that the fclk nodes can be
> retrieved by doing a clk_get with the corresponding device pointers or
> device names.
>
> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com
I've fixed the missing bracket in the email address ^^^
Tony
^ permalink raw reply
* [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
From: Tony Lindgren @ 2011-09-22 1:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-8-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -254,9 +259,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer);
> static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
> int posted)
> {
> - if (posted)
> - while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> - cpu_relax();
> + int i = 0;
> +
> + if (posted) {
> + omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
> + , MAX_WRITE_PEND_WAIT, i);
> +
> + if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
> + pr_err("Read timeout!\n");
> + }
>
> return __raw_readl(timer->func_base + (reg & 0xff));
> }
> @@ -264,9 +275,15 @@ static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
> static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
> u32 reg, u32 val, int posted)
> {
> - if (posted)
> - while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> - cpu_relax();
> + int i = 0;
> +
> + if (posted) {
> + omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
> + , MAX_WRITE_PEND_WAIT, i);
> +
> + if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
> + pr_err("Write timeout!\n");
> + }
>
> __raw_writel(val, timer->func_base + (reg & 0xff));
> }
Let's leave out these changes for now, they make the
omap2_gp_timer_set_next_event used for system timer interrupts
huge if you take a look at it with objdump.
Later on we might want to split the posted bit check into a separate
inline function, and then you can implement this for the device
driver where things are more likely to go wrong with more complicated
use scenarios.
Regards,
Tony
^ permalink raw reply
* [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
From: Tony Lindgren @ 2011-09-22 1:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316518227-28116-6-git-send-email-tarun.kanti@ti.com>
* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -347,15 +346,16 @@ static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
> if (l & OMAP_TIMER_CTRL_ST) {
> l &= ~0x1;
> __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - /* Readback to make sure write has completed */
> - __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
> - /*
> - * Wait for functional clock period x 3.5 to make sure that
> - * timer is stopped
> - */
> - udelay(3500000 / rate + 1);
> -#endif
> + if (is_omap2) {
> + /* Readback to make sure write has completed */
> + __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG,
> + posted);
> + /*
> + * Wait for functional clock period x 3.5 to make sure
> + * that timer is stopped
> + */
> + udelay(3500000 / rate + 1);
> + }
> }
>
> /* Ack possibly pending interrupt */
I've left out this is_omap2 change as it really does not improve anything.
Instead it just makes __omap_dm_timer_stop inline function more complex.
I've also folded in the spinlock fixes in patch 10 into this patch.
Updated patch below.
Tony
From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Tue, 20 Sep 2011 17:00:20 +0530
Subject: [PATCH] ARM: OMAP: dmtimer: switch-over to platform device driver
Register timer devices by going through hwmod database using
hwmod API. The driver probes each of the registered devices.
Functionality which are already performed by hwmod framework
are removed from timer code. New set of timers present on
OMAP4 are now supported.
Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
[tony at atomide.com: folded in spinlock changes, left out is_omap2]
Signed-off-by: Tony Lindgren <tony@atomide.com>
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index b2829ee..9c2f588 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -478,3 +478,23 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
return ret;
}
+
+/**
+ * omap2_dm_timer_init - top level regular device initialization
+ *
+ * Uses dedicated hwmod api to parse through hwmod database for
+ * given class name and then build and register the timer device.
+ */
+static int __init omap2_dm_timer_init(void)
+{
+ int ret;
+
+ ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
+ if (unlikely(ret)) {
+ pr_err("%s: device registration failed.\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+arch_initcall(omap2_dm_timer_init);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 92d5aff..6019208 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -36,120 +36,22 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
#include <linux/slab.h>
-#include <mach/hardware.h>
-#include <plat/dmtimer.h>
-#include <mach/irqs.h>
-
-static int dm_timer_count;
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct omap_dm_timer omap2_dm_timers[] = {
- { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
- { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
- { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
- { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
- { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
- { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
- { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
- { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
- { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
- { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
- { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
- { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
-};
-
-static const char *omap2_dm_source_names[] __initdata = {
- "sys_ck",
- "func_32k_ck",
- "alt_ck",
- NULL
-};
-
-static struct clk *omap2_dm_source_clocks[3];
-static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
-
-#else
-#define omap2_dm_timers NULL
-#define omap2_dm_timer_count 0
-#define omap2_dm_source_names NULL
-#define omap2_dm_source_clocks NULL
-#endif /* CONFIG_ARCH_OMAP2 */
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_dm_timer omap3_dm_timers[] = {
- { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
- { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
- { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
- { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
- { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
- { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
- { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
- { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
- { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
- { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
- { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
- { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
-};
-
-static const char *omap3_dm_source_names[] __initdata = {
- "sys_ck",
- "omap_32k_fck",
- NULL
-};
-
-static struct clk *omap3_dm_source_clocks[2];
-static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
-
-#else
-#define omap3_dm_timers NULL
-#define omap3_dm_timer_count 0
-#define omap3_dm_source_names NULL
-#define omap3_dm_source_clocks NULL
-#endif /* CONFIG_ARCH_OMAP3 */
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct omap_dm_timer omap4_dm_timers[] = {
- { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
- { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
- { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
- { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
- { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
- { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
- { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
- { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
- { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
- { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
- { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
- { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
-};
-static const char *omap4_dm_source_names[] __initdata = {
- "sys_clkin_ck",
- "sys_32k_ck",
- NULL
-};
-static struct clk *omap4_dm_source_clocks[2];
-static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+#include <linux/err.h>
-#else
-#define omap4_dm_timers NULL
-#define omap4_dm_timer_count 0
-#define omap4_dm_source_names NULL
-#define omap4_dm_source_clocks NULL
-#endif /* CONFIG_ARCH_OMAP4 */
-
-static struct omap_dm_timer *dm_timers;
-static const char **dm_source_names;
-static struct clk **dm_source_clocks;
+#include <plat/dmtimer.h>
-static spinlock_t dm_timer_lock;
static LIST_HEAD(omap_timer_list);
+static DEFINE_SPINLOCK(dm_timer_lock);
-/*
- * Reads timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode write pending bit must be
- * checked. Otherwise a read of a non completed write will produce an error.
+/**
+ * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
+ * @timer: timer pointer over which read operation to perform
+ * @reg: lowest byte holds the register offset
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode write
+ * pending bit must be checked. Otherwise a read of a non completed write
+ * will produce an error.
*/
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
{
@@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
return __omap_dm_timer_read(timer, reg, timer->posted);
}
-/*
- * Writes timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode the write pending bit must be
- * checked. Otherwise a write on a register which has a pending write will be
- * lost.
+/**
+ * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
+ * @timer: timer pointer over which write operation is to perform
+ * @reg: lowest byte holds the register offset
+ * @value: data to write into the register
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode the write
+ * pending bit must be checked. Otherwise a write on a register which has a
+ * pending write will be lost.
*/
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
u32 value)
@@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
- int autoidle = 0, wakeup = 0;
-
- if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+ 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_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
- /* Enable autoidle on OMAP2+ */
- if (cpu_class_is_omap2())
- autoidle = 1;
-
- /*
- * Enable wake-up on OMAP2 CPUs.
- */
- if (cpu_class_is_omap2())
- wakeup = 1;
- __omap_dm_timer_reset(timer, autoidle, wakeup);
+ __omap_dm_timer_reset(timer, 0, 0);
timer->posted = 1;
}
-void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+int omap_dm_timer_prepare(struct omap_dm_timer *timer)
{
+ struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+ int ret;
+
+ timer->fclk = clk_get(&timer->pdev->dev, "fck");
+ if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
+ timer->fclk = NULL;
+ dev_err(&timer->pdev->dev, ": No fclk handle.\n");
+ return -EINVAL;
+ }
+
omap_dm_timer_enable(timer);
- omap_dm_timer_reset(timer);
+
+ if (pdata->needs_manual_reset)
+ omap_dm_timer_reset(timer);
+
+ ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+ timer->posted = 1;
+ return ret;
}
struct omap_dm_timer *omap_dm_timer_request(void)
{
- struct omap_dm_timer *timer = NULL;
+ struct omap_dm_timer *timer = NULL, *t;
unsigned long flags;
- int i;
+ int ret = 0;
spin_lock_irqsave(&dm_timer_lock, flags);
- for (i = 0; i < dm_timer_count; i++) {
- if (dm_timers[i].reserved)
+ list_for_each_entry(t, &omap_timer_list, node) {
+ if (t->reserved)
continue;
- timer = &dm_timers[i];
+ timer = t;
timer->reserved = 1;
break;
}
+
+ if (timer) {
+ ret = omap_dm_timer_prepare(timer);
+ if (ret) {
+ timer->reserved = 0;
+ timer = NULL;
+ }
+ }
spin_unlock_irqrestore(&dm_timer_lock, flags);
- if (timer != NULL)
- omap_dm_timer_prepare(timer);
+ if (!timer)
+ pr_debug("%s: timer request failed!\n", __func__);
return timer;
}
@@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
struct omap_dm_timer *omap_dm_timer_request_specific(int id)
{
- struct omap_dm_timer *timer;
+ struct omap_dm_timer *timer = NULL, *t;
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&dm_timer_lock, flags);
- if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
- spin_unlock_irqrestore(&dm_timer_lock, flags);
- printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
- __FILE__, __LINE__, __func__, id);
- dump_stack();
- return NULL;
+ list_for_each_entry(t, &omap_timer_list, node) {
+ if (t->pdev->id == id && !t->reserved) {
+ timer = t;
+ timer->reserved = 1;
+ break;
+ }
}
- timer = &dm_timers[id-1];
- timer->reserved = 1;
+ if (timer) {
+ ret = omap_dm_timer_prepare(timer);
+ if (ret) {
+ timer->reserved = 0;
+ timer = NULL;
+ }
+ }
spin_unlock_irqrestore(&dm_timer_lock, flags);
- omap_dm_timer_prepare(timer);
+ if (!timer)
+ pr_debug("%s: timer%d request failed!\n", __func__, id);
return timer;
}
@@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
void omap_dm_timer_free(struct omap_dm_timer *timer)
{
- omap_dm_timer_enable(timer);
- omap_dm_timer_reset(timer);
omap_dm_timer_disable(timer);
+ clk_put(timer->fclk);
WARN_ON(!timer->reserved);
timer->reserved = 0;
@@ -278,15 +202,15 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_free);
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
+ struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+
if (timer->enabled)
return;
-#ifdef CONFIG_ARCH_OMAP2PLUS
- if (cpu_class_is_omap2()) {
+ if (!pdata->needs_manual_reset) {
clk_enable(timer->fclk);
clk_enable(timer->iclk);
}
-#endif
timer->enabled = 1;
}
@@ -294,15 +218,15 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
+ struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+
if (!timer->enabled)
return;
-#ifdef CONFIG_ARCH_OMAP2PLUS
- if (cpu_class_is_omap2()) {
+ if (!pdata->needs_manual_reset) {
clk_disable(timer->iclk);
clk_disable(timer->fclk);
}
-#endif
timer->enabled = 0;
}
@@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
*/
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
- int i;
+ int i = 0;
+ struct omap_dm_timer *timer = NULL;
+ unsigned long flags;
/* If ARMXOR cannot be idled this function call is unnecessary */
if (!(inputmask & (1 << 1)))
return inputmask;
/* If any active timer is using ARMXOR return modified mask */
- for (i = 0; i < dm_timer_count; i++) {
+ spin_lock_irqsave(&dm_timer_lock, flags);
+ list_for_each_entry(timer, &omap_timer_list, node) {
u32 l;
- l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (l & OMAP_TIMER_CTRL_ST) {
if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
inputmask &= ~(1 << 1);
else
inputmask &= ~(1 << 2);
}
+ i++;
}
+ spin_unlock_irqrestore(&dm_timer_lock, flags);
return inputmask;
}
@@ -384,10 +313,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
void omap_dm_timer_stop(struct omap_dm_timer *timer)
{
unsigned long rate = 0;
+ struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
-#ifdef CONFIG_ARCH_OMAP2PLUS
- rate = clk_get_rate(timer->fclk);
-#endif
+ if (!pdata->needs_manual_reset)
+ rate = clk_get_rate(timer->fclk);
__omap_dm_timer_stop(timer, timer->posted, rate);
}
@@ -395,15 +324,17 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
+ int ret;
+ struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+
if (source < 0 || source >= 3)
return -EINVAL;
-#ifdef CONFIG_ARCH_OMAP2PLUS
- return __omap_dm_timer_set_source(timer->fclk,
- dm_source_clocks[source]);
-#else
- return 0;
-#endif
+ omap_dm_timer_disable(timer);
+ ret = pdata->set_timer_src(timer->pdev, source);
+ omap_dm_timer_enable(timer);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
@@ -526,13 +457,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
int omap_dm_timers_active(void)
{
- int i;
-
- for (i = 0; i < dm_timer_count; i++) {
- struct omap_dm_timer *timer;
-
- timer = &dm_timers[i];
+ struct omap_dm_timer *timer;
+ list_for_each_entry(timer, &omap_timer_list, node) {
if (!timer->enabled)
continue;
@@ -602,7 +529,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
timer->id = pdev->id;
timer->irq = irq->start;
timer->pdev = pdev;
- __omap_dm_timer_init_regs(timer);
/* add the timer element to the list */
spin_lock_irqsave(&dm_timer_lock, flags);
@@ -675,73 +601,3 @@ MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Texas Instruments Inc");
-
-static int __init omap_dm_timer_init(void)
-{
- struct omap_dm_timer *timer;
- int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */
-
- if (!cpu_class_is_omap2())
- return -ENODEV;
-
- spin_lock_init(&dm_timer_lock);
-
- if (cpu_is_omap24xx()) {
- dm_timers = omap2_dm_timers;
- dm_timer_count = omap2_dm_timer_count;
- dm_source_names = omap2_dm_source_names;
- dm_source_clocks = omap2_dm_source_clocks;
- } else if (cpu_is_omap34xx()) {
- dm_timers = omap3_dm_timers;
- dm_timer_count = omap3_dm_timer_count;
- dm_source_names = omap3_dm_source_names;
- dm_source_clocks = omap3_dm_source_clocks;
- } else if (cpu_is_omap44xx()) {
- dm_timers = omap4_dm_timers;
- dm_timer_count = omap4_dm_timer_count;
- dm_source_names = omap4_dm_source_names;
- dm_source_clocks = omap4_dm_source_clocks;
-
- pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
- return -ENODEV;
- }
-
- if (cpu_class_is_omap2())
- for (i = 0; dm_source_names[i] != NULL; i++)
- dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
-
- if (cpu_is_omap243x())
- dm_timers[0].phys_base = 0x49018000;
-
- for (i = 0; i < dm_timer_count; i++) {
- timer = &dm_timers[i];
-
- /* Static mapping, never released */
- timer->io_base = ioremap(timer->phys_base, map_size);
- BUG_ON(!timer->io_base);
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
- if (cpu_class_is_omap2()) {
- char clk_name[16];
- sprintf(clk_name, "gpt%d_ick", i + 1);
- timer->iclk = clk_get(NULL, clk_name);
- sprintf(clk_name, "gpt%d_fck", i + 1);
- timer->fclk = clk_get(NULL, clk_name);
- }
-
- /* One or two timers may be set up early for sys_timer */
- if (sys_timer_reserved & (1 << i)) {
- timer->reserved = 1;
- timer->posted = 1;
- continue;
- }
-#endif
- omap_dm_timer_enable(timer);
- __omap_dm_timer_init_regs(timer);
- omap_dm_timer_disable(timer);
- }
-
- return 0;
-}
-
-arch_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 98f186e..2ac7538 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -231,9 +231,8 @@ struct omap_dm_timer {
unsigned long phys_base;
int id;
int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
struct clk *iclk, *fclk;
-#endif
+
void __iomem *io_base;
void __iomem *sys_stat; /* TISTAT timer status */
void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */
@@ -251,7 +250,7 @@ struct omap_dm_timer {
};
extern u32 sys_timer_reserved;
-void omap_dm_timer_prepare(struct omap_dm_timer *timer);
+int omap_dm_timer_prepare(struct omap_dm_timer *timer);
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted)
^ permalink raw reply related
* [PATCH v4] DRM: add DRM Driver for Samsung SoC EXYNOS4210.
From: Inki Dae @ 2011-09-22 1:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110921185312.GK17357@phenom.oracle.com>
Hello, Konrad Rzeszutek Wilk.
> -----Original Message-----
> From: Konrad Rzeszutek Wilk [mailto:konrad.wilk at oracle.com]
> Sent: Thursday, September 22, 2011 3:53 AM
> To: Inki Dae
> Cc: airlied at linux.ie; dri-devel at lists.freedesktop.org;
> sw0312.kim at samsung.com; kyungmin.park at samsung.com; linux-arm-
> kernel at lists.infradead.org
> Subject: Re: [PATCH v4] DRM: add DRM Driver for Samsung SoC EXYNOS4210.
>
> > > > > > + DRM_ERROR("desired size is bigger then real
> > size.\n");
> > > > >
> > > > > So .. you can't continue by just using the real size instead?
> > > > >
> > > >
> > > > I am afraid I don't understand what you mean but I think that
> condition
> > > is
> > > > fine. size is a vm area to user-desired size and you could request
> > > mapping
> > > > as specific size. so it just check user-requested virtual space
> region
> > > it
> > > > bigger than allocated physical memory region to be mapped. if there
> is
> > > my
> > > > missing points, I would be happy to you give me your comments. thank
> > you.
> > >
> > > I meant that you return -EINVAL. But I am wondering if it would be
> > > possible
> > > to just continue on, but ignore what the user specified.
> > >
> > > I think the issue here is that you are outputing the DRM_ERROR and
> > > I am not sure if it is that neccessary. Perhaps DRM_DEBUG, but
> DRM_ERROR
> > > just seems a bit.. heavy handed.
> > >
> >
> > I thought this condition would be critical issue as user application
> should
> > be terminated. is your wondering if user application could go ahead
> after
> > mmap failed? this is just my view so I would be happy you to give me
> your
> > advice. Thank you.
>
> I think terminating the appliaction is the right thing. But the DRM_ERROR
> is not neccessary.
I understood. I will remove DRM_ERROR or use DRM_DEBUG instead. thank you.
^ permalink raw reply
* [PATCH] ARM: futex: fix clobbering oldval
From: mhban @ 2011-09-22 2:53 UTC (permalink / raw)
To: linux-arm-kernel
This patch fixes clobbering oldval bug. oldval should be preserved for next
compare operation.
Change-Id: I2a63bc1bdb8de330eb9e1ac02d7da1f77e6e8c3c
Signed-off-by: Minho Ban <mhban@samsung.com>
---
arch/arm/include/asm/futex.h | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index d2d733c..b0f2e8e 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -30,14 +30,14 @@
__asm__ __volatile__( \
"1: ldrex %1, [%2]\n" \
" " insn "\n" \
- "2: strex %1, %0, [%2]\n" \
- " teq %1, #0\n" \
+ "2: strex r5, %0, [%2]\n" \
+ " teq r5, #0\n" \
" bne 1b\n" \
" mov %0, #0\n" \
__futex_atomic_ex_table("%4") \
: "=&r" (ret), "=&r" (oldval) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
- : "cc", "memory")
+ : "r5", "cc", "memory")
static inline int
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2] [media] at91: add code to initialize and manage the ISI_MCK for Atmel ISI driver.
From: Wu, Josh @ 2011-09-22 3:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E69E4BF.3030402@atmel.com>
Hi, Nicolas
On Friday, September 09, 2011 6:05 PM, Nicolas Ferre wrote:
> Le 06/09/2011 08:54, Guennadi Liakhovetski :
>> On Tue, 6 Sep 2011, Josh Wu wrote:
>>
>>> This patch enable the configuration for ISI_MCK, which is provided by programmable clock.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>> drivers/media/video/atmel-isi.c | 60 ++++++++++++++++++++++++++++++++++++++-
>>> include/media/atmel-isi.h | 4 ++
>>> 2 files changed, 63 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/drivers/media/video/atmel-isi.c
>>> b/drivers/media/video/atmel-isi.c
> [..]
>>> /*
>>> ---------------------------------------------------------------------
>>> --*/
>>> +/* Initialize ISI_MCK clock, called by atmel_isi_probe() function */
>>> +static int initialize_mck(struct platform_device *pdev,
>>> + struct atmel_isi *isi)
>>> +{
>>> + struct device *dev = &pdev->dev;
>>> + struct isi_platform_data *pdata = dev->platform_data;
>>> + struct clk *pck_parent;
>>> + int ret;
>>> +
>>> + if (!strlen(pdata->pck_name) || !strlen(pdata->pck_parent_name))
>>> + return -EINVAL;
>>> +
>>> + /* ISI_MCK is provided by PCK clock */
>>> + isi->mck = clk_get(dev, pdata->pck_name);
>>
>> I think, it's still not what Russell meant. Look at
>> drivers/mmc/host/atmel-mci.c:
>>
>> host->mck = clk_get(&pdev->dev, "mci_clk");
>>
>> and in arch/arm/mach-at91/at91sam9g45.c they've got
>>
>> CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
>> CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
>>
>> where
>>
>> #define CLKDEV_CON_DEV_ID(_con_id, _dev_id, _clk) \
>> { \
>> .con_id = _con_id, \
>> .dev_id = _dev_id, \
>> .clk = _clk, \
>> }
>>
>> I.e., in the device driver (mmc in this case) you only use the
>> (platform) device instance, whose dev_name(dev) is then matched
>> against one of clock lookups above, and a connection ID, which is used
>> in case your device is using more than one clock. In the ISI case,
>> your pck1 clock, that you seem to need here, doesn't have a clock
>> lookup object, so, you might have to add one, and then use its connection ID.
>>
>>> + if (IS_ERR(isi->mck)) {
>>> + dev_err(dev, "Failed to get PCK: %s\n", pdata->pck_name);
>>> + return PTR_ERR(isi->mck);
>>> + }
>>> +
>>> + pck_parent = clk_get(dev, pdata->pck_parent_name);
>>> + if (IS_ERR(pck_parent)) {
>>> + ret = PTR_ERR(pck_parent);
>>> + dev_err(dev, "Failed to get PCK parent: %s\n",
>>> + pdata->pck_parent_name);
>>> + goto err_init_mck;
>>> + }
>>> +
>>> + ret = clk_set_parent(isi->mck, pck_parent);
>>
>> I'm not entirely sure on this one, but as we had a similar situation
>> with clocks, we decided to extablish the clock hierarchy in the board
>> code, and only deal with the actual device clocks in the driver
>> itself. I.e., we moved all clk_set_parent() and setting up the parent clock into the board.
>> And I do think, this makes more sense, than doing this in the driver,
>> not all users of this driver will need to manage the parent clock, right?
> Exactly.
>
> Josh, for the two comments by Guennadi above, you can take sound/soc/atmel/sam9g20_wm8731.c as an example of using PCK and parent clocks. You will also find how to use named clocks and how to set the programmable clocks rate...
According to sam9g20_wm8731.c file, and combined Guennadi and J.C's advices, I'd like to only add clk_set_rate() and enable/disble isi_mck code in ISI driver.
Also I will define isi_mck clock in soc chip file(at91sam9g45.c).
Then I will move all setting up the parent clock code into the at91sam9g45_devices.c, where there are code to add Atmel ISI device.
I will generate the new version patch for it soon.
>>> + clk_put(pck_parent);
>>> + if (ret)
>>> + goto err_init_mck;
>>> +
>>> + ret = clk_set_rate(isi->mck, pdata->isi_mck_hz);
>>> + if (ret < 0)
>>> + goto err_init_mck;
>>> +
>>> + return 0;
>>> +
>>> +err_init_mck:
>>> + clk_put(isi->mck);
>>> + return ret;
>>> +}
>>> +
>>> static int __devexit atmel_isi_remove(struct platform_device *pdev)
>>> {
>>> struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
>>> @@ -897,6 +948,7 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev)
>>> isi->fb_descriptors_phys);
>>>
>>> iounmap(isi->regs);
>>> + clk_put(isi->mck);
>>> clk_put(isi->pclk);
>>> kfree(isi);
> [..]
> Best regards,
> --
> Nicolas Ferre
Best Regards,
Josh Wu
^ permalink raw reply
* [PATCH v3 1/2][media] Add code to enable/disable ISI_MCK clock.
From: Josh Wu @ 2011-09-22 4:11 UTC (permalink / raw)
To: linux-arm-kernel
This patch add code to enable/disable ISI_MCK clock when add/remove soc camera device.it also set ISI_MCK frequence before using it.
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
drivers/media/video/atmel-isi.c | 30 ++++++++++++++++++++++++++++--
include/media/atmel-isi.h | 2 ++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
index 7b89f00..888234a 100644
--- a/drivers/media/video/atmel-isi.c
+++ b/drivers/media/video/atmel-isi.c
@@ -90,7 +90,10 @@ struct atmel_isi {
struct isi_dma_desc dma_desc[MAX_BUFFER_NUM];
struct completion complete;
+ /* ISI peripherial clock */
struct clk *pclk;
+ /* ISI_MCK, provided by Programmable clock */
+ struct clk *mck;
unsigned int irq;
struct isi_platform_data *pdata;
@@ -763,6 +766,12 @@ static int isi_camera_add_device(struct soc_camera_device *icd)
if (ret)
return ret;
+ ret = clk_enable(isi->mck);
+ if (ret) {
+ clk_disable(isi->pclk);
+ return ret;
+ }
+
isi->icd = icd;
dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
icd->devnum);
@@ -776,6 +785,7 @@ static void isi_camera_remove_device(struct soc_camera_device *icd)
BUG_ON(icd != isi->icd);
+ clk_disable(isi->mck);
clk_disable(isi->pclk);
isi->icd = NULL;
@@ -897,6 +907,7 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev)
isi->fb_descriptors_phys);
iounmap(isi->regs);
+ clk_put(isi->mck);
clk_put(isi->pclk);
kfree(isi);
@@ -915,7 +926,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
struct isi_platform_data *pdata;
pdata = dev->platform_data;
- if (!pdata || !pdata->data_width_flags) {
+ if (!pdata || !pdata->data_width_flags || !pdata->isi_mck_hz) {
dev_err(&pdev->dev,
"No config available for Atmel ISI\n");
return -EINVAL;
@@ -944,6 +955,19 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&isi->video_buffer_list);
INIT_LIST_HEAD(&isi->dma_desc_head);
+ /* Get ISI_MCK, which is provided by Programmable clock */
+ isi->mck = clk_get(dev, "isi_mck");
+ if (IS_ERR(isi->mck)) {
+ dev_err(dev, "Failed to get isi_mck\n");
+ ret = PTR_ERR(isi->mck);
+ goto err_alloc_descriptors;
+ }
+
+ /* Set ISI_MCK's frequency, it should be faster than pixel clock */
+ ret = clk_set_rate(isi->mck, pdata->isi_mck_hz);
+ if (ret < 0)
+ goto err_set_mck_rate;
+
isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
sizeof(struct fbd) * MAX_BUFFER_NUM,
&isi->fb_descriptors_phys,
@@ -951,7 +975,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
if (!isi->p_fb_descriptors) {
ret = -ENOMEM;
dev_err(&pdev->dev, "Can't allocate descriptors!\n");
- goto err_alloc_descriptors;
+ goto err_set_mck_rate;
}
for (i = 0; i < MAX_BUFFER_NUM; i++) {
@@ -1013,6 +1037,8 @@ err_alloc_ctx:
sizeof(struct fbd) * MAX_BUFFER_NUM,
isi->p_fb_descriptors,
isi->fb_descriptors_phys);
+err_set_mck_rate:
+ clk_put(isi->mck);
err_alloc_descriptors:
kfree(isi);
err_alloc_isi:
diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h
index 26cece5..a0229a6 100644
--- a/include/media/atmel-isi.h
+++ b/include/media/atmel-isi.h
@@ -114,6 +114,8 @@ struct isi_platform_data {
u32 data_width_flags;
/* Using for ISI_CFG1 */
u32 frate;
+ /* Using for ISI_MCK, provided by Programmable clock */
+ u32 isi_mck_hz;
};
#endif /* __ATMEL_ISI_H__ */
--
1.6.3.3
^ permalink raw reply related
* [PATCH v3 2/2] at91: add Atmel ISI and ov2640 support on sam9m10/sam9g45 board.
From: Josh Wu @ 2011-09-22 4:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316664661-11383-1-git-send-email-josh.wu@atmel.com>
This patch
1. add ISI_MCK parent setting code when add ISI device.
2. add ov2640 support on board file.
3. define isi_mck clock in sam9g45 chip file.
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
arch/arm/mach-at91/at91sam9g45.c | 3 +
arch/arm/mach-at91/at91sam9g45_devices.c | 105 +++++++++++++++++++++++++++++-
arch/arm/mach-at91/board-sam9m10g45ek.c | 85 ++++++++++++++++++++++++-
arch/arm/mach-at91/include/mach/board.h | 3 +-
4 files changed, 193 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index e04c5fb..5e23d6d 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -201,6 +201,7 @@ static struct clk *periph_clocks[] __initdata = {
// irq0
};
+static struct clk pck1;
static struct clk_lookup periph_clocks_lookups[] = {
/* One additional fake clock for ohci */
CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
@@ -215,6 +216,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ /* ISI_MCK, which is provided by programmable clock(PCK1) */
+ CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", &pck1),
};
static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 600bffb..82eeac8 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -16,7 +16,7 @@
#include <linux/platform_device.h>
#include <linux/i2c-gpio.h>
#include <linux/atmel-mci.h>
-
+#include <linux/clk.h>
#include <linux/fb.h>
#include <video/atmel_lcdc.h>
@@ -28,6 +28,8 @@
#include <mach/at_hdmac.h>
#include <mach/atmel-mci.h>
+#include <media/atmel-isi.h>
+
#include "generic.h"
@@ -863,6 +865,107 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data)
void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
#endif
+/* --------------------------------------------------------------------
+ * Image Sensor Interface
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
+static u64 isi_dmamask = DMA_BIT_MASK(32);
+static struct isi_platform_data isi_data;
+
+struct resource isi_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_ISI,
+ .end = AT91SAM9G45_BASE_ISI + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_ISI,
+ .end = AT91SAM9G45_ID_ISI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_isi_device = {
+ .name = "atmel_isi",
+ .id = 0,
+ .dev = {
+ .dma_mask = &isi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &isi_data,
+ },
+ .resource = isi_resources,
+ .num_resources = ARRAY_SIZE(isi_resources),
+};
+
+static int __init isi_set_clk_parent(void)
+{
+ struct clk *pck1;
+ struct clk *plla;
+ int ret;
+
+ /* ISI_MCK is supplied by PCK1 - set parent for it. */
+ pck1 = clk_get(NULL, "pck1");
+ if (IS_ERR(pck1)) {
+ printk(KERN_ERR "Failed to get PCK1\n");
+ ret = PTR_ERR(pck1);
+ goto err;
+ }
+
+ plla = clk_get(NULL, "plla");
+ if (IS_ERR(plla)) {
+ printk(KERN_ERR "Failed to get PLLA\n");
+ ret = PTR_ERR(plla);
+ goto err_pck1;
+ }
+ ret = clk_set_parent(pck1, plla);
+ clk_put(plla);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to set PCK1 parent\n");
+ goto err_pck1;
+ }
+ return ret;
+
+err_pck1:
+ clk_put(pck1);
+err:
+ return ret;
+}
+
+void __init at91_add_device_isi(struct isi_platform_data * data)
+{
+ if (!data)
+ return;
+ isi_data = *data;
+
+ at91_set_A_periph(AT91_PIN_PB20, 0); /* ISI_D0 */
+ at91_set_A_periph(AT91_PIN_PB21, 0); /* ISI_D1 */
+ at91_set_A_periph(AT91_PIN_PB22, 0); /* ISI_D2 */
+ at91_set_A_periph(AT91_PIN_PB23, 0); /* ISI_D3 */
+ at91_set_A_periph(AT91_PIN_PB24, 0); /* ISI_D4 */
+ at91_set_A_periph(AT91_PIN_PB25, 0); /* ISI_D5 */
+ at91_set_A_periph(AT91_PIN_PB26, 0); /* ISI_D6 */
+ at91_set_A_periph(AT91_PIN_PB27, 0); /* ISI_D7 */
+ at91_set_A_periph(AT91_PIN_PB28, 0); /* ISI_PCK */
+ at91_set_A_periph(AT91_PIN_PB30, 0); /* ISI_HSYNC */
+ at91_set_A_periph(AT91_PIN_PB29, 0); /* ISI_VSYNC */
+ at91_set_B_periph(AT91_PIN_PB31, 0); /* ISI_MCK (PCK1) */
+ at91_set_B_periph(AT91_PIN_PB8, 0); /* ISI_PD8 */
+ at91_set_B_periph(AT91_PIN_PB9, 0); /* ISI_PD9 */
+ at91_set_B_periph(AT91_PIN_PB10, 0); /* ISI_PD10 */
+ at91_set_B_periph(AT91_PIN_PB11, 0); /* ISI_PD11 */
+
+ platform_device_register(&at91sam9g45_isi_device);
+
+ if (isi_set_clk_parent())
+ printk(KERN_ERR "Fail to set parent for ISI_MCK.\n");
+
+ return;
+}
+#else
+static int __init isi_set_clk_parent(void) { }
+void __init at91_add_device_isi(struct isi_platform_data * data) { }
+#endif
+
/* --------------------------------------------------------------------
* LCD Controller
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index ad234cc..d5293fb 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -23,11 +23,13 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/leds.h>
-#include <linux/clk.h>
#include <linux/atmel-mci.h>
+#include <linux/delay.h>
#include <mach/hardware.h>
#include <video/atmel_lcdc.h>
+#include <media/soc_camera.h>
+#include <media/atmel-isi.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -185,6 +187,83 @@ static void __init ek_add_device_nand(void)
at91_add_device_nand(&ek_nand_data);
}
+/*
+ * ISI
+ */
+#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
+static struct isi_platform_data __initdata isi_data = {
+ .frate = ISI_CFG1_FRATE_CAPTURE_ALL,
+ .has_emb_sync = 0,
+ .emb_crc_sync = 0,
+ .hsync_act_low = 0,
+ .vsync_act_low = 0,
+ .pclk_act_falling = 0,
+ /* to use codec and preview path simultaneously */
+ .isi_full_mode = 1,
+ .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
+ /* ISI_MCK is provided by PCK1 */
+ .isi_mck_hz = 25000000,
+};
+
+#else
+static struct isi_platform_data __initdata isi_data;
+#endif
+
+/*
+ * soc-camera OV2640
+ */
+#if defined(CONFIG_SOC_CAMERA_OV2640)
+static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
+{
+ /* ISI board for ek using default 8-bits connection */
+ return SOCAM_DATAWIDTH_8;
+}
+
+static int i2c_camera_power(struct device *dev, int on)
+{
+ /* enable or disable the camera */
+ pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
+ at91_set_gpio_output(AT91_PIN_PD13, on ? 0 : 1);
+
+ if (!on)
+ goto out;
+
+ /* If enabled, give a reset impulse */
+ at91_set_gpio_output(AT91_PIN_PD12, 0);
+ msleep(20);
+ at91_set_gpio_output(AT91_PIN_PD12, 1);
+ msleep(100);
+
+out:
+ return 0;
+}
+
+static struct i2c_board_info i2c_camera = {
+ I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+ .bus_id = 0,
+ .board_info = &i2c_camera,
+ .i2c_adapter_id = 0,
+ .power = i2c_camera_power,
+ .query_bus_param = isi_camera_query_bus_param,
+};
+
+static struct platform_device isi_ov2640 = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &iclink_ov2640,
+ },
+};
+
+static struct platform_device *devices[] __initdata = {
+ &isi_ov2640,
+};
+#else
+static struct platform_device *devices[] __initdata = {};
+#endif
/*
* LCD Controller
@@ -400,6 +479,10 @@ static void __init ek_board_init(void)
ek_add_device_nand();
/* I2C */
at91_add_device_i2c(0, NULL, 0);
+ /* ISI */
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ at91_add_device_isi(&isi_data);
+
/* LCD Controller */
at91_add_device_lcdc(&ek_lcdc_data);
/* Touch Screen */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index ed544a0..276d63a 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -183,7 +183,8 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
/* ISI */
-extern void __init at91_add_device_isi(void);
+struct isi_platform_data;
+extern void __init at91_add_device_isi(struct isi_platform_data *data);
/* Touchscreen Controller */
struct at91_tsadcc_data {
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 0/3] add fec support for imx6q
From: Shawn Guo @ 2011-09-22 5:10 UTC (permalink / raw)
To: linux-arm-kernel
This series adds imx6q enet support. The imx6q enet is a derivative of
imx28 enet controller. It fixed the frame endian issue found on imx28,
and added 1 Gbps support.
Changes since v3:
* The minus one on phy_speed should happend before left shift.
Changes since v2:
* Refine patch #1 to get fec_reset_phy() return void
Changes since v1:
* Fix typo pointed out by Francois Romieu
* Drop patch #3 in the v1
* Rebase on net-next tree
Thanks.
Shawn Guo (3):
net/fec: fec_reset_phy() does not need to always succeed
net/fec: fix fec1 check in fec_enet_mii_init()
net/fec: add imx6q enet support
drivers/net/ethernet/freescale/Kconfig | 9 ++--
drivers/net/ethernet/freescale/fec.c | 79 +++++++++++++++++++++++---------
2 files changed, 61 insertions(+), 27 deletions(-)
^ permalink raw reply
* [PATCH v4 1/3] net/fec: fec_reset_phy() does not need to always succeed
From: Shawn Guo @ 2011-09-22 5:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316668218-10194-1-git-send-email-shawn.guo@linaro.org>
FEC can work without a phy reset on some platforms, which means not
very platform necessarily have a phy-reset gpio encoded in device tree.
Even on the platforms that have the gpio, FEC can work without
resetting phy for some cases, e.g. boot loader has done that.
So it makes more sense to have the phy-reset-gpio request failure as
a debug message rather than a warning, and get fec_reset_phy() return
void since the caller does not check the return anyway.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/net/ethernet/freescale/fec.c | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 158b82e..9c1d059 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -1411,24 +1411,22 @@ static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev)
return -ENODEV;
}
-static int __devinit fec_reset_phy(struct platform_device *pdev)
+static void __devinit fec_reset_phy(struct platform_device *pdev)
{
int err, phy_reset;
struct device_node *np = pdev->dev.of_node;
if (!np)
- return -ENODEV;
+ return;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset");
if (err) {
- pr_warn("FEC: failed to get gpio phy-reset: %d\n", err);
- return err;
+ pr_debug("FEC: failed to get gpio phy-reset: %d\n", err);
+ return;
}
msleep(1);
gpio_set_value(phy_reset, 1);
-
- return 0;
}
#else /* CONFIG_OF */
static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
@@ -1436,13 +1434,12 @@ static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
return -ENODEV;
}
-static inline int fec_reset_phy(struct platform_device *pdev)
+static inline void fec_reset_phy(struct platform_device *pdev)
{
/*
* In case of platform probe, the reset has been done
* by machine code.
*/
- return 0;
}
#endif /* CONFIG_OF */
--
1.7.4.1
^ permalink raw reply related
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