* [PATCH] ARM: debug: provide dummy default option for DEBUG_LL UART choice
From: Will Deacon @ 2011-09-30 9:28 UTC (permalink / raw)
To: linux-arm-kernel
Defaulting to DEBUG_ICEDCC will cause systems to hang during boot unless
a hardware debugger is listening to the debug comms. channel.
This patch adds a dummy UART option as the default DEBUG_LL choice which
requires the platform to do the right thing.
Acked-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
This came out of discussion on the list yesterday but I thought I'd better
post a patch before sending to Russell.
Will
arch/arm/Kconfig.debug | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 32b1be4..5bc7814 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -81,6 +81,14 @@ choice
prompt "Kernel low-level debugging port"
depends on DEBUG_LL
+ config DEBUG_LL_UART_NONE
+ bool "No low-level debugging UART"
+ help
+ Say Y here if your platform doesn't provide a UART option
+ below. This relies on your platform choosing the right UART
+ definition internally in order for low-level debugging to
+ work.
+
config DEBUG_ICEDCC
bool "Kernel low-level debugging via EmbeddedICE DCC channel"
help
@@ -89,8 +97,8 @@ choice
co-processor 14. This is known to work on the ARM9 style ICE
channel and on the XScale with the PEEDI.
- It does include a timeout to ensure that the system does not
- totally freeze when there is nothing connected to read.
+ Note that the system will appear to hang during boot if there
+ is nothing connected to read from the DCC.
config DEBUG_FOOTBRIDGE_COM1
bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
--
1.7.0.4
^ permalink raw reply related
* [PATCH v3] ARM: cache-l2x0: add resume entry for l2 in secure mode
From: Shawn Guo @ 2011-09-30 9:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGsJ_4zUL-6VzifctuDTe=jF-2FzjbkD10VfR=hC8ZDaFMiOFw@mail.gmail.com>
On Fri, Sep 30, 2011 at 04:44:33PM +0800, Barry Song wrote:
> 2011/9/30 Shawn Guo <shawn.guo@freescale.com>:
> > On Thu, Sep 29, 2011 at 08:31:21PM -0700, Barry Song wrote:
> >> From: Barry Song <Baohua.Song@csr.com>
> >>
> >> we save the l2x0 registers at the first initialization, and platform codes
> >> can get them to restore l2x0 status after wakeup.
> >>
> >> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
> >> Cc: Shawn Guo <shawn.guo@linaro.org>
> >> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> >> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> >> ---
> >> ?-v3:
> >> ?save PREFETCH_CTRL and POWER_CTRL according to revision;
> >> ?save l2x0 physical address so that asm codes can use.
> >
> > On imx6q:
> >
> > Tested-by: Shawn Guo <shawn.guo@linaro.org>
>
> Shawn, Thanks.
>
> >
> > One minor comment below.
> >
> >>
> >> ?arch/arm/include/asm/hardware/cache-l2x0.h | ? 23 +++++
> >> ?arch/arm/include/asm/outercache.h ? ? ? ? ?| ? ?7 ++
> >> ?arch/arm/kernel/asm-offsets.c ? ? ? ? ? ? ?| ? 12 +++
> >> ?arch/arm/mm/cache-l2x0.c ? ? ? ? ? ? ? ? ? | ?129 +++++++++++++++++++++++++--
> >> ?4 files changed, 161 insertions(+), 10 deletions(-)
> >
> > [... ]
> >
> >> diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
> >> index 0d85d22..3f9b998 100644
> >> --- a/arch/arm/mm/cache-l2x0.c
> >> +++ b/arch/arm/mm/cache-l2x0.c
> >> @@ -33,6 +33,14 @@ static DEFINE_SPINLOCK(l2x0_lock);
> >> ?static uint32_t l2x0_way_mask; ? ? ? /* Bitmask of active ways */
> >> ?static uint32_t l2x0_size;
> >>
> >> +struct l2x0_regs l2x0_saved_regs;
> >> +
> > Can we add a declaration of l2x0_saved_regs in cache-l2x0.h, so that
> > platform code does not need to declare it individually?
>
> it could be ok. if the platform codes are in c after MMU on, it can be
> useful.
Actually, it's needed for imx6q case (resume in asm) too, because we
need to save __pa(l2x0_saved_regs) in C for later use by asm.
> but people might be able to call outer_resume() in c directly.
> then it doesn't need the declaration as well.
We do not define l2x0_saved_regs as static for the only reason that
some platform codes need to access it. Then we could add declaration
to ease platform code a little bit more.
--
Regards,
Shawn
^ permalink raw reply
* [PATCH 7/8] OMAP4: clock: Add CPU local timer clock node.
From: Shilimkar, Santosh @ 2011-09-30 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKnu2Mp4QnQPwcGJCrfMqS6VcfvvvAxginjJkLG1mPLO0WJBUw@mail.gmail.com>
On Fri, Sep 30, 2011 at 3:00 AM, Linus Walleij <linus.walleij@linaro.org> wrote:
> 2011/9/8 Santosh Shilimkar <santosh.shilimkar@ti.com>:
>
>> Local timer clock is sourced from the CPU clock and hence changes
>> along with CPU clock. These per CPU local timers are used as
>> clock-events, so they need to be reconfigured on CPU frequency
>> change as part of CPUfreq governor.
>
> This requires patch 6956/2 right?
> http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=6956/2
>
> Can I add your Tested-by: to the patch as well?
>
Sure.
^ permalink raw reply
* [PATCH 7/8] OMAP4: clock: Add CPU local timer clock node.
From: Shilimkar, Santosh @ 2011-09-30 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1109291308060.26728@utopia.booyaka.com>
On Fri, Sep 30, 2011 at 12:42 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi Santosh,
>
> On Thu, 8 Sep 2011, Santosh Shilimkar wrote:
>
>> Local timer clock is sourced from the CPU clock and hence changes
>> along with CPU clock. These per CPU local timers are used as
>> clock-events, so they need to be reconfigured on CPU frequency
>> change as part of CPUfreq governor.
>>
>> Newly introduced clockevents_reconfigure() needs to know the
>> twd clock-rate. Provide a clock-node to make clk_get_rate() work
>> for TWD.
>>
>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> Cc: Paul Walmsley <paul@pwsan.com>
>> Cc: Kevin Hilman <khilman@ti.com>
>
> This clock looks like the ARM Cortex-A9 MPCore PERIPHCLK, correct? ?From
> ARM Cortex-A9 MPCore Technical Reference Manual (DDI 0407G) Section 5.1
> "Clocks"?
>
Yes. Peripheral clock/2
> Assuming that is so, I've modified this patch appropriately, and added
> support to the autogeneration script to generate this clock node.
> Care to take a quick look at it to make sure it's okay?
>
Thanks a lot Paul. It looks good.
Regards
Santosh
^ permalink raw reply
* [PATCH v3 1/2][media] Add code to enable/disable ISI_MCK clock.
From: Guennadi Liakhovetski @ 2011-09-30 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316664661-11383-1-git-send-email-josh.wu@atmel.com>
On Thu, 22 Sep 2011, Josh Wu wrote:
> 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.
Ok, the fact, that noone more comments on the clk API use in this patch
confirms my impression, that it's now mostly done right:-) But, as I
mentioned in my reply to patch 2/2, I think, you shouldn't be getting and
manipulating isi_mck unconditionally in this driver.
Actually, I think, this code
+ /* ISI_MCK, which is provided by programmable clock(PCK1) */
+ CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", &pck1),
in your other patch (sorry for cross-referencing), isn't quite correct.
This is not an ISI specific clock, this is a PCK1 clock, which might as
well be used for ISI, but can also be used for a different purpose. At
least this doesn't seem a generic sam9g45 feature to me. You, probably,
want to move this clock lookup registration to your board (sam9g45ek)
file, which does indeed wire PCK1 to the camera sensor, installed on it.
Thanks
Guennadi
>
> 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
>
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* [PATCH v3 2/2] at91: add Atmel ISI and ov2640 support on sam9m10/sam9g45 board.
From: Guennadi Liakhovetski @ 2011-09-30 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316664661-11383-2-git-send-email-josh.wu@atmel.com>
On Thu, 22 Sep 2011, Josh Wu wrote:
> 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>
Looking a bit more at this, I think, the arch maintainer might want to
take a closer look at this:
1. Wouldn't it be a good idea to also bind the isi_clk via a clock
connection ID and not via the clock's name?
2. pck1 is not really dedicated to ISI on sam9g45. It can also be used,
e.g., as a generic clock output and ISI_PCK can be supplied by an external
oscillator. Such set up seems perfectly valid to me and your patch would
just unconditionally grab PCK1 and configure it to some frequency... I
think, this shall be improved.
3.
> +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);
I think, here you also need a
clk_put(pck1);
> + 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;
> +}
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* [PATCH v4 6/7] arm/imx6q: add device tree machine support
From: Jamie Iles @ 2011-09-30 9:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317200808-6275-7-git-send-email-shawn.guo@linaro.org>
Hi Shawn,
On Wed, Sep 28, 2011 at 05:06:47PM +0800, Shawn Guo wrote:
> It adds generic device tree based machine support for imx6q.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
[...]
> diff --git a/arch/arm/mach-imx/mach-imx6q.c
> b/arch/arm/mach-imx/mach-imx6q.c
> new file mode 100644
> index 0000000..8bf5fa3
> --- /dev/null
> +++ b/arch/arm/mach-imx/mach-imx6q.c
[...]
> +static void __init imx6q_gpio_add_irq_domain(struct device_node *np,
> + struct device_node *interrupt_parent)
> +{
> + static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS -
> + 32 * 7; /* imx6q gets 7 gpio ports */
> +
> + irq_domain_add_simple(np, gpio_irq_base);
> + gpio_irq_base += 32;
Doesn't this rely on imx6q_gpio_add_irq_domain() being called for each
gpio bank in the order that they appear in the device tree (and that the
dt is correctly ordered)?
> +}
> +
> +static const struct of_device_id imx6q_irq_match[] __initconst = {
> + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
> + { .compatible = "fsl,imx6q-gpio", .data = imx6q_gpio_add_irq_domain, },
> + { /* sentinel */ }
> +};
> +
> +static void __init imx6q_init_irq(void)
> +{
> + l2x0_of_init(0, ~0UL);
> + imx_src_init();
> + imx_gpc_init();
> + of_irq_init(imx6q_irq_match);
> +}
Jamie
^ permalink raw reply
* [PATCH] Add platform driver support to the CS890x driver
From: Jaccon Bastiaansen @ 2011-09-30 9:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110928083048.GA15311@glitch.intra.local>
Hello Domenico,
2011/9/28 Domenico Andreoli <cavokz@gmail.com>:
> Hi Jaccon,
>
> On Mon, Sep 12, 2011 at 12:52:52PM +0200, Jaccon Bastiaansen wrote:
>>
>> Ok, so you would like to see the #ifdefs for the IXDP2351, IXDP2X01,
>> QQ2440 and MX31ADS in the cs890x driver replaced by platform_device
>> definitions in the platform specific code of those platforms (in the
>> same way as I have done for the i.MX21ADS platform)? Is this correct?
>
> Feel free to completely dump the QQ2440 thing, the QQ2440 board support
> is not in mainline and will not until it can be implemented mostly with
> DT, I guess. ?At that time I will be happy to use your platform device
> conversion - with the OF initialization that sombody will write ;)
>
> I will test it.
>
> cheers,
> Domenico
>
This patch does what you describe and removes the QQ2440 board support.
Regards,
Jaccon
^ permalink raw reply
* [PATCH v3] ARM: cache-l2x0: add resume entry for l2 in secure mode
From: Barry Song @ 2011-09-30 8:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110930083338.GB19807@S2100-06.ap.freescale.net>
2011/9/30 Shawn Guo <shawn.guo@freescale.com>:
> On Thu, Sep 29, 2011 at 08:31:21PM -0700, Barry Song wrote:
>> From: Barry Song <Baohua.Song@csr.com>
>>
>> we save the l2x0 registers at the first initialization, and platform codes
>> can get them to restore l2x0 status after wakeup.
>>
>> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>> ---
>> ?-v3:
>> ?save PREFETCH_CTRL and POWER_CTRL according to revision;
>> ?save l2x0 physical address so that asm codes can use.
>
> On imx6q:
>
> Tested-by: Shawn Guo <shawn.guo@linaro.org>
Shawn, Thanks.
>
> One minor comment below.
>
>>
>> ?arch/arm/include/asm/hardware/cache-l2x0.h | ? 23 +++++
>> ?arch/arm/include/asm/outercache.h ? ? ? ? ?| ? ?7 ++
>> ?arch/arm/kernel/asm-offsets.c ? ? ? ? ? ? ?| ? 12 +++
>> ?arch/arm/mm/cache-l2x0.c ? ? ? ? ? ? ? ? ? | ?129 +++++++++++++++++++++++++--
>> ?4 files changed, 161 insertions(+), 10 deletions(-)
>
> [... ]
>
>> diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
>> index 0d85d22..3f9b998 100644
>> --- a/arch/arm/mm/cache-l2x0.c
>> +++ b/arch/arm/mm/cache-l2x0.c
>> @@ -33,6 +33,14 @@ static DEFINE_SPINLOCK(l2x0_lock);
>> ?static uint32_t l2x0_way_mask; ? ? ? /* Bitmask of active ways */
>> ?static uint32_t l2x0_size;
>>
>> +struct l2x0_regs l2x0_saved_regs;
>> +
> Can we add a declaration of l2x0_saved_regs in cache-l2x0.h, so that
> platform code does not need to declare it individually?
it could be ok. if the platform codes are in c after MMU on, it can be
useful. but people might be able to call outer_resume() in c directly.
then it doesn't need the declaration as well.
anyway, we can add it for future possible use. v4 soon.
-barry
^ permalink raw reply
* [PATCH] arm: proc-v7: pc phy addresses before disable MMU
From: Will Deacon @ 2011-09-30 8:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E8555A5.9090304@stericsson.com>
Hi Per,
On Fri, Sep 30, 2011 at 06:37:41AM +0100, Per F?rlin wrote:
> On 09/24/2011 03:02 PM, Russell King - ARM Linux wrote:
> > On Sat, Sep 24, 2011 at 02:55:42PM +0200, Per F?rlin wrote:
> >> On 09/24/2011 01:00 PM, Will Deacon wrote:
> >>> On Sat, Sep 24, 2011 at 10:32:48AM +0100, Per F?rlin wrote:
> >>>> I am trying to figure out how I can get the value of PHYS_OFFSET in assembler code (proc-v7.S).
> >>>> I guess I could use the value calculated in arch/arm/kernel.head.S but wouldn't that make
> >>>> this patch dependent on CONFIG_ARM_PATCH_PHYS_VIRT?
> >>>
> >>> Wouldn't we just be better off passing a physical address to cpu_v7_reset
> >>> instead?
> >>>
> >> Good point! I'm fine with that.
> >
> > Alternatively, call it using the phys address.
> I changed the code to use a label instead of the ARM specific instruction offset +4. A few more lines but the intention is that it should work with both ARM and THUMB. I'm in favour of Russell's idea of setting pc to physical before calling cpu_reset().
> /* Go to physical addresses to be ready for MMU disable */
> asm("ADR r1, pc_phy_here \n\t"
> "sub r1, %0 \n\t"
> "mov pc, r1 \n\t"
> "pc_phy_here: \n\t"
> : :"r" (PAGE_OFFSET - PHYS_OFFSET) : "r1", "cc");
I'm not sure why all of this is necessary. Take a look at my kexec patches
here:
http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/kexec-mmu-off
The interesting bit is __arm_machine_reset in kernel/process.c
Will
^ permalink raw reply
* [PATCH v3] ARM: cache-l2x0: add resume entry for l2 in secure mode
From: Shawn Guo @ 2011-09-30 8:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317353481-28723-1-git-send-email-Barry.Song@csr.com>
On Thu, Sep 29, 2011 at 08:31:21PM -0700, Barry Song wrote:
> From: Barry Song <Baohua.Song@csr.com>
>
> we save the l2x0 registers at the first initialization, and platform codes
> can get them to restore l2x0 status after wakeup.
>
> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> ---
> -v3:
> save PREFETCH_CTRL and POWER_CTRL according to revision;
> save l2x0 physical address so that asm codes can use.
On imx6q:
Tested-by: Shawn Guo <shawn.guo@linaro.org>
One minor comment below.
>
> arch/arm/include/asm/hardware/cache-l2x0.h | 23 +++++
> arch/arm/include/asm/outercache.h | 7 ++
> arch/arm/kernel/asm-offsets.c | 12 +++
> arch/arm/mm/cache-l2x0.c | 129 +++++++++++++++++++++++++--
> 4 files changed, 161 insertions(+), 10 deletions(-)
[... ]
> diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
> index 0d85d22..3f9b998 100644
> --- a/arch/arm/mm/cache-l2x0.c
> +++ b/arch/arm/mm/cache-l2x0.c
> @@ -33,6 +33,14 @@ static DEFINE_SPINLOCK(l2x0_lock);
> static uint32_t l2x0_way_mask; /* Bitmask of active ways */
> static uint32_t l2x0_size;
>
> +struct l2x0_regs l2x0_saved_regs;
> +
Can we add a declaration of l2x0_saved_regs in cache-l2x0.h, so that
platform code does not need to declare it individually?
--
Regards,
Shawn
^ permalink raw reply
* [PATCH v5 1/3] AM35x: Using OMAP3 generic hwmods
From: Paul Walmsley @ 2011-09-30 8:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317363153-10259-2-git-send-email-abhilash.kv@ti.com>
Hi Abhilash,
On Fri, 30 Sep 2011, Abhilash K V wrote:
> From: Abhilash K V <abhilash.kv@ti.com>
>
> Removing modules iva, sr1_hwmod, sr2_hwmod, mailbox from
> the base omap3xxx_hwmods list, so that they can be excluded
> for am35x.
>
> Signed-off-by: Abhilash K V <abhilash.kv@ti.com>
Looks good to me, provisionally queued for 3.2 fixes.
- Paul
^ permalink raw reply
* [PATCH 5/5] ARM: pxa: move gpio driver into drivers directory
From: Russell King - ARM Linux @ 2011-09-30 8:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAN1soZyBTOq_qQ+o3OFP-GuwRN=WwNE6te1Hy7vrkureFuLA3A@mail.gmail.com>
On Fri, Sep 30, 2011 at 03:09:11PM +0800, Haojian Zhuang wrote:
> On Fri, Sep 30, 2011 at 12:30 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Thu, Sep 29, 2011 at 11:19:06PM +0800, Haojian Zhuang wrote:
> >> +#include <linux/gpio-pxa.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +#include <asm/io.h>
> >
> > linux/gpio.h please.
> >
>
> Excuse me that I didn't use any gpio API in mach-pxa/gpio.c. It seems
> that I needn't include "linux/gpio.h" at mach-pxa/gpio.c.
Sorry, that should've been linux/io.h not gpio.h
^ permalink raw reply
* [PATCH 2/9] regulator: helper routine to extract regulator_init_data
From: Cousson, Benoit @ 2011-09-30 7:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E854532.6080605@ti.com>
On 9/30/2011 6:27 AM, Nayak, Rajendra wrote:
[...]
>> They need both. We need to reference the device that provides the
>> supply and use a name to say which of the potentially multiple supplies
>> on the consumer device is which.
>
> Mark, I still seem to be a little confused with this one as to why
> we would need a phandle *and* a supply-name to reference a parent
> regulator/supply.
> The phandle would point to a regulator dt node and that node internally
> would have just one name associated with it.
I think as well that we should avoid considering a regulator with
several outputs. I saw the same pattern used for the clock binding in DT
as well.
A clock node like a regulator node should output only one signal.
These nodes should provide atomic functionality. And if extra
functionality are needed we might consider adding some intermediate nodes.
Except for a regulator that will output several lines at the same
voltage to spread the current load, assuming it does exist, I'm not sure
to understand the need.
Mark,
What usage do you have in mind for such supply node with several outputs?
Regards,
Benoit
^ permalink raw reply
* [RFC PATCH v5] ARM hibernation / suspend-to-disk (fwd)
From: Barry Song @ 2011-09-30 7:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1106131303290.25153@localhost6.localdomain6>
Hi Frank,
2011/6/13 Frank Hofmann <frank.hofmann@tomtom.com>:
> Hi,
>
> to make one thing clear to start with:
>
> This is not a proposal to integrate the hibernation feature into mainline.
>
> It's not ripe for that because it's unclear what exactly the differences are
> between what the hibernation / S2RAM codepaths have to do, and/or how much
> code sharing between these codepaths is advisable.
>
>
> Therefore, I'm merely putting this out as-is as a reference / base for those
> who want to do their own experiments with the feature.
>
> Prerequisites:
>
> * The patch requires a working cpu_reset(); for v6/v7, that's in Will
> ?Deacon's patch series from last week.
>
> * It also requires being able to take the address of cpu_reset and
> ?on MULTI_CPU configs therefore, again see Will Deacon's patch series.
>
> * It uses on cpu_suspend() / cpu_resume(), therefore a recent-enough
> ?kernel (or a port of those to whatever you're using) is required.
>
>
> Important / Limitations:
>
> A) For platforms that currently use cpu_suspend/cpu_resume in their s2ram
> ?codepaths AND DO NOTHING ELSE BEFORE AND NOTHING ELSE AFTER THAT BUT TO
> ?"ENTER LOW POWER", the way the hibernation state snapshot for the CPU
> ?core is done by this patch is sufficient.
>
> ?To make it clear: IF AND ONLY IF your suspend(-to-ram) func looks like:
>
> ? ? ? ?ENTRY(acmeSoC_cpu_suspend)
> ? ? ? ? ? ? ? ?stmfd ? sp!, {r4-r12,lr}
> ? ? ? ? ? ? ? ?ldr ? ? r3, resume_mmu_done
> ? ? ? ? ? ? ? ?bl ? ? ?cpu_suspend
> ? ? ? ?resume_mmu_done:
> ? ? ? ? ? ? ? ?ldmfd ? sp!, {r3-r12,pc}
> ? ? ? ?ENDPROC(acmeSoC_cpu_suspend)
>
> ?then this patch is ok to provide hibernation support for your CPU core.
>
> ?In all other cases, item B).
>
> ?IN ALL CASES, read item C) below; there's more than the core to the SoC.
>
> B) If there's any cpu-specific / SoC-specific state that needs (re)init
> ?over a suspend-to-disk/resume-from-disk cycle, this patch is incomplete
> ?because it provides no hooks/code for that.
>
> ?This is the case e.g. for "secure" SoCs that have different sets of
> ?control registers and/or different CR reg access patterns.
>
> ?It's also the case e.g. for SoCs with L2 caches as the activation
> ?sequence there is SoC-dependent; a full off-on cycle for L2 is not done
> ?by the hibernation support code.
>
> ?It's also the case if the SoC requires steps on wakeup _before_ the
> ?"generic" parts done by cpu_suspend / cpu_resume can work correctly.
>
> ?(OMAP is an example of such a SoC; the patch "works" on OMAP in the
> ?sense that it gets you a non-secure OMAP back from hibernation but as
> ?mentioned, your mileage may vary; I for example don't know what the
> ?consequences ?of not disabling / reenabling the L2 cache over cpu_reset
> ?are)
>
> C) The current low-power handling may perform SoC-specific tasks such
> ?as GPIO state handling, which is currently also not addressed by this
> ?patch; the assumption is rather that device suspend/resume deals with
> ?this. That is not guaranteed to be complete / sufficient - if your SoC
> ?and/or your device drivers have particular needs in this area, you can
> ?put hooks performing these actions into save_/restore_processor_state().
>
> D) If you wish to extend this to a SoC for which the generic CPU core
> ?hooks (i.e. what cpu_suspend/resume provide) are either insufficient
> ?or unavailable, hook your own state snapshot mechanism into the places
> ?where this code currently calls cpu_suspend and cpu_resume. The main
> ?assumption by the assembly code within swusp_arch_resume() is that
> ?__swsusp_arch_restore_image() returns to its caller with the stack
> ?restored - how you achieve that is up to you, the patch as-is does it
> ?by cpu_reset(cpu_resume) but your mileage may vary.
>
>
> I will, at this point, not send further iterations of this patch.
>
> I'll answer questions about it though, if there are any.
i did bring-up prima2(cortex-a9) swsusp hibernation support based on
your patch. i am considering whether we can have some ways to make the
resume faster.
Now the resume flow is:
[1] poweron -> bootloader -> kernel -> all boot and device probed ->
late_init() -> loading snapshot from disk to memory -> resume devices
and software
Is it possible we make it:
[2] poweron -> bootloader -> loading snapshot from disk to memory ->
resume devices and software
Then the sub-process "bootloader -> kernel -> all boot and device
probed -> late_init()" will be eliminated and time to boot kernel will
not be needed too.
the flow [2] is more platform-related. so it is probably we can use
platform_hibernation_ops to handle. but it can be generic as well.
>
>
> Thanks for all the comments during the previous threads - learned a lot !
>
>
> Best regards,
> FrankH.
-barry
^ permalink raw reply
* [PATCH 5/5] ARM: pxa: move gpio driver into drivers directory
From: Haojian Zhuang @ 2011-09-30 7:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110929222723.GI10886@ponder.secretlab.ca>
On Fri, Sep 30, 2011 at 6:27 AM, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Thu, Sep 29, 2011 at 11:19:06PM +0800, Haojian Zhuang wrote:
>> Move gpio driver from plat-pxa to drivers/gpio directory. Only leave
>> gpio number macro in mach/gpio.h.
>>
>> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
>> ---
>> +static int __init mmp_gpio_init(void)
>> +{
>> + [...]
>> + ? ? platform_device_add_data(&mmp_gpio, &mmp_gpio_config, size);
>> + ? ? platform_device_register(&mmp_gpio);
>> + ? ? return 0;
>> +}
>> +postcore_initcall(mmp_gpio_init);
>
> You'll also want to bail on this init function if a DT is passed to
> the kernel. ?Otherwise it looks okay.
>
I can avoid to use this init function. So platform driver will
register gpio directly.
>> -#define GPIO_REG(x) ?(*((volatile u32 *)(GPIO_REGS_VIRT + (x))))
>> +#define GPIO_REGS_VIRT ? ? ? ? ? ? ? (APB_VIRT_BASE + 0x19000)
>
> Nit: don't change the whitespace on this line because it isn't
> actually changing functionally, but diff makes it look like it is.
>
> I assume these remaining macros will be removed/reworked in a future
> patch?
>
Do you mean that abandon APB_VIRT_BASE?
>> +static int __init pxa_gpio_init(void)
>> +{
>> + ? ? int size = sizeof(struct pxa_gpio_platform_data);
>> + ? ? u32 reg_base = io_p2v(0x40E00000);
>> +
>> + ? ? if (cpu_is_pxa25x()) {
>> +#ifdef CONFIG_PXA26x
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_type = PXA26X_GPIO;
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_end = 89;
>> +#else
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_type = PXA25X_GPIO;
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_end = 84;
>> +#endif
>
> Not multiplatform friendly. ?The subarch may not support
> multiplatform, but that's no excuse for adding either/or #ifdef
> blocks. ?I'd rather see one #ifdef for PXA26x and another for PXA25x,
> and the code organizes so that they can peacefully co-exist.
>
OK.
>> + ? ? } else if (cpu_is_pxa27x()) {
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_type = PXA27X_GPIO;
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_end = 120;
>> + ? ? } else if (cpu_is_pxa93x() || cpu_is_pxa95x()) {
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_type = PXA93X_GPIO;
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_end = 191;
>> + ? ? } else if (cpu_is_pxa3xx()) {
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_type = PXA3XX_GPIO;
>> + ? ? ? ? ? ? pxa_gpio_config.gpio_end = 127;
>> + ? ? } else
>> + ? ? ? ? ? ? return 0;
>> +
>> + ? ? pxa_gpio_regs.gplr = reg_base + GPLR_OFFSET;
>> + ? ? pxa_gpio_regs.gpdr = reg_base + GPDR_OFFSET;
>> + ? ? pxa_gpio_regs.gpsr = reg_base + GPSR_OFFSET;
>> + ? ? pxa_gpio_regs.gpcr = reg_base + GPCR_OFFSET;
>> + ? ? pxa_gpio_regs.grer = reg_base + GRER_OFFSET;
>> + ? ? pxa_gpio_regs.gfer = reg_base + GFER_OFFSET;
>> + ? ? pxa_gpio_regs.gedr = reg_base + GEDR_OFFSET;
>> + ? ? pxa_gpio_regs.gafr = reg_base + GAFR_OFFSET;
>
> I'd rather have this layout knowledge as part of the driver
> rather than using platform data to pass stuff. ?The driver can make
> the selection either based on device name, or by testing
> cpio_is_pxa*() directly. ?We already have the mechanisms needed for
> this.
>
> Same goes for mmp_gpio_init().
>
OK. I'll move these code into drivers/gpio/gpio-pxa.c.
>> +
>> + ? ? platform_device_add_data(&pxa_gpio, &pxa_gpio_config, size);
>> + ? ? platform_device_register(&pxa_gpio);
>> + ? ? return 0;
>> +}
>> +postcore_initcall(pxa_gpio_init);
>
> Same as mmp_gpio_init, this function needs to be skipped if a DT is
> passed to the kernel.
>
OK
>> @@ -282,7 +281,6 @@ static int __init pxa95x_init(void)
>> ? ? ? ? ? ? ? ? ? ? ? return ret;
>>
>> ? ? ? ? ? ? ? register_syscore_ops(&pxa_irq_syscore_ops);
>> - ? ? ? ? ? ? register_syscore_ops(&pxa_gpio_syscore_ops);
>> ? ? ? ? ? ? ? register_syscore_ops(&pxa3xx_clock_syscore_ops);
>>
>> ? ? ? ? ? ? ? ret = platform_add_devices(devices, ARRAY_SIZE(devices));
>
> Instead of encoding it into pdata, it would be simpler to select the
> type by assiging an (platform_driver*)->id_table and using the .data
> member in the table to select the correct initialization data. ?That
> means using the name of the device to select the correct
> initialization.
>
Yes, you're right. I'll change it to id_table.
>>
>> +
>> +static int __init pxa_gpio_probe(struct platform_device *pdev)
>
> This needs to be __devinit for correctness.
>
OK
>>
>> +#define GPLR(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gplr + BANK_OFF((x >> 5))))
>> +#define GPDR(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gpdr + BANK_OFF((x >> 5))))
>> +#define GPSR(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gpsr + BANK_OFF((x >> 5))))
>> +#define GPCR(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gpcr + BANK_OFF((x >> 5))))
>> +#define GRER(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.grer + BANK_OFF((x >> 5))))
>> +#define GFER(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gfer + BANK_OFF((x >> 5))))
>> +#define GEDR(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gedr + BANK_OFF((x >> 5))))
>> +#define GAFR(x) ? ? ? ? ? ? ?(*(volatile u32 *)(pxa_gpio_regs.gafr + (((x) & 0x70) >> 2)))
>> +
>> +#define GPIO_BANK(n) (pxa_gpio_regs.gplr + BANK_OFF(n))
>
> All these macros really need a pxa_gpio prefix, but that can be done
> in a separate patch.
>
OK
^ permalink raw reply
* [PATCH v2 5/5] iommu/exynos: Use bus_set_iommu instead of register_iommu
From: Kukjin Kim @ 2011-09-30 7:31 UTC (permalink / raw)
To: linux-arm-kernel
From: KyongHo Cho <pullip.cho@samsung.com>
This replaces register_iommu() with bus_set_iommu() according to the
suggestion of Joerg Roedel.
Cc: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
drivers/iommu/exynos_iommu.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/iommu/exynos_iommu.c b/drivers/iommu/exynos_iommu.c
index d355a2e..e36f7b2 100644
--- a/drivers/iommu/exynos_iommu.c
+++ b/drivers/iommu/exynos_iommu.c
@@ -912,7 +912,7 @@ static int __init exynos_iommu_init(void)
if (!l2table_cachep)
return -ENOMEM;
- register_iommu(&exynos_iommu_ops);
+ bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
return 0;
}
--
1.7.1
^ permalink raw reply related
* [PATCH v2 4/5] iommu/exynos: Add iommu fault handler
From: Kukjin Kim @ 2011-09-30 7:31 UTC (permalink / raw)
To: linux-arm-kernel
From: KyongHo Cho <pullip.cho@samsung.com>
This adds IOMMU fault handler that is suggested by Ohad Ben-Cohen.
Users of IOMMU API can register its own fault handler with
iommu_set_fault_handler() and the handler is called by IRQ handler
of System MMU.
If no user installs fault handler, IOMMU driver prints debugging
message and generates kernel oops.
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
drivers/iommu/exynos_iommu.c | 21 +++++++++++++--------
1 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/iommu/exynos_iommu.c b/drivers/iommu/exynos_iommu.c
index 33fa4a8..d355a2e 100644
--- a/drivers/iommu/exynos_iommu.c
+++ b/drivers/iommu/exynos_iommu.c
@@ -207,28 +207,33 @@ static int default_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
static irqreturn_t exynos_sysmmu_irq(int irq, void * dev_id)
{
/* SYSMMU is in blocked when interrupt occurred. */
+ unsigned long addr;
struct sysmmu_drvdata *data = dev_id;
enum S5P_SYSMMU_INTERRUPT_TYPE itype;
- bool handled = false;
+ int ret = -ENOSYS;
WARN_ON(!is_sysmmu_active(data));
itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
__ffs(__raw_readl(data->sfrbase + S5P_INT_STATUS));
- if (WARN_ON((itype < 0) && (itype >= 8))) {
+ if (WARN_ON((itype < 0) && (itype >= 8)))
itype = SYSMMU_FAULT_UNKNOWN;
- } else if (data->fault_handler) {
+
+ addr = __raw_readl(data->sfrbase + fault_reg_offset[itype]);
+
+ if (data->domain)
+ ret = report_iommu_fault(data->domain, data->owner, addr,
+ itype);
+
+ if ((ret == -ENOSYS) && (data->fault_handler)) {
unsigned long base;
- unsigned long addr;
- addr = __raw_readl(data->sfrbase + fault_reg_offset[itype]);
base = __raw_readl(data->sfrbase + S5P_PT_BASE_ADDR);
- if (!data->fault_handler(itype, base, addr))
- handled = true;
+ ret = data->fault_handler(itype, base, addr);
}
- if (handled)
+ if (ret == 0)
__raw_writel(1 << itype, data->sfrbase + S5P_INT_CLEAR);
else
dev_dbg(data->dev, "%s is not handled.\n",
--
1.7.1
^ permalink raw reply related
* [PATCH v2 3/5] iommu/exynos: Add iommu driver for Exynos4 Platforms
From: Kukjin Kim @ 2011-09-30 7:31 UTC (permalink / raw)
To: linux-arm-kernel
From: KyongHo Cho <pullip.cho@samsung.com>
This is the System MMU driver and IOMMU API implementation for
Exynos4 SOC platforms. Exynos4 platforms has more than 10 System
MMUs dedicated for each multimedia accellerators.
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
drivers/iommu/Kconfig | 14 +
drivers/iommu/Makefile | 1 +
drivers/iommu/exynos_iommu.c | 914 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 929 insertions(+), 0 deletions(-)
create mode 100644 drivers/iommu/exynos_iommu.c
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index b57b3fa..1c754cd 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -107,4 +107,18 @@ config INTR_REMAP
To use x2apic mode in the CPU's which support x2APIC enhancements or
to support platforms with CPU's having > 8 bit APIC ID, say Y.
+# EXYNOS IOMMU support
+config EXYNOS_IOMMU
+ bool "Exynos IOMMU Support"
+ depends on ARCH_EXYNOS4
+ select IOMMU_API
+ select EXYNOS4_DEV_SYSMMU
+ help
+ Support for the IOMMUs (System MMUs) Samsung Exynos application
+ processor family. This enables H/W multimedia accellerators to view
+ non-linear physical memory chunks as a linear memory in their virtual
+ address spaces.
+
+ If unsure, say N here.
+
endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 4d4d77d..1eb924f 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
+obj-$(CONFIG_EXYNOS_IOMMU) += exynos_iommu.o
diff --git a/drivers/iommu/exynos_iommu.c b/drivers/iommu/exynos_iommu.c
new file mode 100644
index 0000000..33fa4a8
--- /dev/null
+++ b/drivers/iommu/exynos_iommu.c
@@ -0,0 +1,914 @@
+/* linux/drivers/iommu/exynos_iommu.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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/io.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/atomic.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+
+#include <mach/map.h>
+#include <mach/regs-sysmmu.h>
+#include <mach/sysmmu.h>
+
+#define CTRL_ENABLE 0x5
+#define CTRL_BLOCK 0x7
+#define CTRL_DISABLE 0x0
+
+enum S5P_SYSMMU_INTERRUPT_TYPE {
+ SYSMMU_PAGEFAULT,
+ SYSMMU_AR_MULTIHIT,
+ SYSMMU_AW_MULTIHIT,
+ SYSMMU_BUSERROR,
+ SYSMMU_AR_SECURITY,
+ SYSMMU_AR_ACCESS,
+ SYSMMU_AW_SECURITY,
+ SYSMMU_AW_PROTECTION, /* 7 */
+ SYSMMU_FAULT_UNKNOWN,
+ SYSMMU_FAULTS_NUM
+};
+
+static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
+ S5P_PAGE_FAULT_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR,
+ S5P_DEFAULT_SLAVE_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR
+};
+
+static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM + 1] = {
+ "PAGE FAULT",
+ "AR MULTI-HIT FAULT",
+ "AW MULTI-HIT FAULT",
+ "BUS ERROR",
+ "AR SECURITY PROTECTION FAULT",
+ "AR ACCESS PROTECTION FAULT",
+ "AW SECURITY PROTECTION FAULT",
+ "AW ACCESS PROTECTION FAULT",
+ "UNKOWN FAULT"
+};
+
+struct exynos_iommu_domain {
+ struct device *dev;
+ unsigned long *pgtable;
+ spinlock_t lock;
+ spinlock_t pgtablelock;
+};
+
+struct sysmmu_drvdata {
+ struct list_head node;
+ struct device *dev;
+ struct device *owner;
+ void __iomem *sfrbase;
+ struct clk *clk;
+ int activations;
+ struct iommu_domain *domain;
+ int (*fault_handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr);
+};
+
+/* List of sysmmu_drvdata */
+static LIST_HEAD(sysmmu_list);
+
+static inline struct sysmmu_drvdata *get_sysmmu_data(struct device *owner,
+ struct sysmmu_drvdata *start)
+{
+ struct list_head *pos, *head;
+
+ head = (start) ? &start->node : &sysmmu_list;
+
+ list_for_each(pos, head) {
+ struct sysmmu_drvdata *data =
+ container_of(pos, struct sysmmu_drvdata, node);
+
+ if (pos == &sysmmu_list)
+ return NULL;
+
+ if (data->owner == owner)
+ return data;
+ }
+
+ return NULL;
+}
+
+static inline bool set_sysmmu_active(struct sysmmu_drvdata *data)
+{
+ /* return true if the System MMU was not active previously
+ and it needs to be initialized */
+
+ data->activations++;
+ return data->activations == 1;
+}
+
+static inline bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
+{
+ /* return true if the System MMU is needed to be disabled */
+ data->activations--;
+
+ if (data->activations == 0)
+ return true;
+
+ if (WARN_ON(data->activations < 0))
+ /* System MMU is already disabled */
+ data->activations = 0;
+
+ return false;
+}
+
+static inline bool is_sysmmu_active(struct sysmmu_drvdata *data)
+{
+ return data->activations != 0;
+}
+
+static inline void sysmmu_block(void __iomem *sfrbase)
+{
+ __raw_writel(CTRL_BLOCK, sfrbase + S5P_MMU_CTRL);
+}
+
+static inline void sysmmu_unblock(void __iomem *sfrbase)
+{
+ __raw_writel(CTRL_ENABLE, sfrbase + S5P_MMU_CTRL);
+}
+
+static inline void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
+{
+ __raw_writel(0x1, sfrbase + S5P_MMU_FLUSH);
+}
+
+static inline void __sysmmu_set_ptbase(void __iomem *sfrbase,
+ unsigned long pgd)
+{
+ if (unlikely(pgd == 0)) {
+ pgd = (unsigned long)ZERO_PAGE(0);
+ __raw_writel(0x20, sfrbase + S5P_MMU_CFG); /* 4KB LV1 */
+ } else {
+ __raw_writel(0x0, sfrbase + S5P_MMU_CFG); /* 16KB LV1 */
+ }
+
+ __raw_writel(pgd, sfrbase + S5P_PT_BASE_ADDR);
+
+ __sysmmu_tlb_invalidate(sfrbase);
+}
+
+static inline void __set_fault_handler(struct sysmmu_drvdata *data,
+ int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr))
+{
+ data->fault_handler = handler;
+}
+
+void s5p_sysmmu_set_fault_handler(struct device *owner,
+ int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr))
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data)))
+ __set_fault_handler(data, handler);
+}
+
+static int default_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base, unsigned long fault_addr)
+{
+ if ((itype > SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
+ itype = SYSMMU_FAULTS_NUM;
+
+ pr_err("%s occured@0x%08lx(Page table base: 0x%08lx)\n",
+ sysmmu_fault_name[itype], fault_addr, pgtable_base);
+ pr_err("\t\tGenerating Kernel OOPS... because it is unrecoverable.\n");
+
+ BUG();
+
+ return 0;
+}
+
+static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
+{
+ /* SYSMMU is in blocked when interrupt occurred. */
+ struct sysmmu_drvdata *data = dev_id;
+ enum S5P_SYSMMU_INTERRUPT_TYPE itype;
+ bool handled = false;
+
+ WARN_ON(!is_sysmmu_active(data));
+
+ itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
+ __ffs(__raw_readl(data->sfrbase + S5P_INT_STATUS));
+
+ if (WARN_ON((itype < 0) && (itype >= 8))) {
+ itype = SYSMMU_FAULT_UNKNOWN;
+ } else if (data->fault_handler) {
+ unsigned long base;
+ unsigned long addr;
+ addr = __raw_readl(data->sfrbase + fault_reg_offset[itype]);
+ base = __raw_readl(data->sfrbase + S5P_PT_BASE_ADDR);
+
+ if (!data->fault_handler(itype, base, addr))
+ handled = true;
+ }
+
+ if (handled)
+ __raw_writel(1 << itype, data->sfrbase + S5P_INT_CLEAR);
+ else
+ dev_dbg(data->dev, "%s is not handled.\n",
+ sysmmu_fault_name[itype]);
+
+ sysmmu_unblock(data->sfrbase);
+
+ return IRQ_HANDLED;
+}
+
+void exynos_sysmmu_set_tablebase_pgd(struct device *owner, unsigned long pgd)
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data))) {
+ if (is_sysmmu_active(data)) {
+ sysmmu_block(data->sfrbase);
+ __sysmmu_set_ptbase(data->sfrbase, pgd);
+ sysmmu_unblock(data->sfrbase);
+ dev_dbg(data->dev,
+ "New page table base is 0x%08lx\n", pgd);
+ } else {
+ dev_dbg(data->dev,
+ "Disabled: Skipping setting page table base.\n");
+ }
+ }
+}
+
+static int __exynos_sysmmu_enable(struct device *owner, unsigned long pgtable,
+ struct iommu_domain *domain)
+{
+ struct sysmmu_drvdata *data = NULL;
+ bool enabled = false;
+
+ /* There are some devices that control more System MMUs than one such
+ * as MFC.
+ */
+ while ((data = get_sysmmu_data(owner, data))) {
+ enabled = true;
+
+ if (!set_sysmmu_active(data)) {
+ dev_dbg(data->dev, "Already enabled.\n");
+ continue;
+ }
+
+ pm_runtime_get_sync(data->dev);
+
+ clk_enable(data->clk);
+
+ __sysmmu_set_ptbase(data->sfrbase, pgtable);
+
+ __raw_writel(CTRL_ENABLE, data->sfrbase + S5P_MMU_CTRL);
+
+ data->domain = domain;
+
+ dev_dbg(data->dev, "Enabled.\n");
+ }
+
+ return (enabled) ? 0 : -ENODEV;
+}
+
+static inline int exynos_iommu_enable(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ if (!priv || !priv->dev)
+ return -EINVAL;
+
+ return __exynos_sysmmu_enable(priv->dev, __pa(priv->pgtable), domain);
+}
+
+int exynos_sysmmu_enable(struct device *owner, unsigned long pgtable)
+{
+ return __exynos_sysmmu_enable(owner, pgtable, NULL);
+}
+
+void exynos_sysmmu_disable(struct device *owner)
+{
+ struct sysmmu_drvdata *data = NULL;
+ bool disabled = false;
+
+ while ((data = get_sysmmu_data(owner, data))) {
+ disabled = true;
+
+ if (!set_sysmmu_inactive(data)) {
+ dev_dbg(data->dev, "Inactivation request ignorred\n");
+ continue;
+ }
+
+ __raw_writel(CTRL_DISABLE, data->sfrbase + S5P_MMU_CTRL);
+
+ clk_disable(data->clk);
+
+ pm_runtime_put_sync(data->dev);
+
+ data->domain = NULL;
+
+ dev_dbg(data->dev, "Disabled.\n");
+ }
+
+ BUG_ON(!disabled);
+}
+
+static inline void exynos_iommu_disable(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ if (priv && priv->dev)
+ exynos_sysmmu_disable(priv->dev);
+}
+
+void exynos_sysmmu_tlb_invalidate(struct device *owner)
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data))) {
+ if (is_sysmmu_active(data)) {
+ sysmmu_block(data->sfrbase);
+ __sysmmu_tlb_invalidate(data->sfrbase);
+ sysmmu_unblock(data->sfrbase);
+ } else {
+ dev_dbg(data->dev,
+ "Disabled: Skipping invalidating TLB.\n");
+ }
+ }
+}
+
+static int exynos_sysmmu_probe(struct platform_device *pdev)
+{
+ struct resource *res, *ioarea;
+ int ret = 0;
+ int irq;
+ struct device *dev;
+ void *sfr;
+ struct sysmmu_drvdata *data;
+ struct clk *clk;
+
+ dev = &pdev->dev;
+
+ data = kzalloc(GFP_KERNEL, sizeof(*data));
+ if (!data) {
+ dev_err(dev, "Failed to probing System MMU: "
+ "Not enough memory");
+ return -ENOMEM;
+ }
+
+ if (!dev_get_platdata(dev)) {
+ dev_err(dev, "Failed to probing system MMU: "
+ "Owner device is not set.");
+
+ ret = -ENODEV;
+ goto err_init;
+ }
+
+ ret = dev_set_drvdata(dev, data);
+ if (ret) {
+ dev_err(dev, "Failed to probing system MMU: "
+ "Unable to set driver data.");
+ goto err_init;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev,
+ "Failed probing system MMU: failed to get resource.");
+ ret = -ENOENT;
+ goto err_init;
+ }
+
+ ioarea = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (ioarea == NULL) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to request memory region.");
+ ret = -ENOENT;
+ goto err_init;
+ }
+
+ sfr = ioremap(res->start, resource_size(res));
+ if (!sfr) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to call ioremap().");
+ ret = -ENOENT;
+ goto err_ioremap;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to get irq resource.");
+ ret = irq;
+ goto err_irq;
+ }
+
+ ret = request_irq(irq, exynos_sysmmu_irq, 0, dev_name(dev), data);
+ if (ret) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to request irq.");
+ goto err_irq;
+ }
+
+ clk = clk_get(dev, "sysmmu");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to probing System MMU: "
+ "failed to get clock descriptor");
+ ret = PTR_ERR(clk);
+ goto err_clk;
+ }
+
+ data->dev = dev;
+ data->owner = dev_get_platdata(dev);
+ data->clk = clk;
+ data->sfrbase = sfr;
+ data->fault_handler = &default_fault_handler;
+ INIT_LIST_HEAD(&data->node);
+
+ list_add(&data->node, &sysmmu_list);
+
+ if (dev->parent)
+ pm_runtime_enable(dev);
+
+ dev_dbg(dev, "Initialized for %s.\n", dev_name(data->owner));
+ return 0;
+err_clk:
+ free_irq(irq, data);
+err_irq:
+ iounmap(sfr);
+err_ioremap:
+ release_resource(ioarea);
+ kfree(ioarea);
+err_init:
+ kfree(data);
+ dev_err(dev, "Probing system MMU failed.");
+ return ret;
+}
+
+int exynos_sysmmu_runtime_suspend(struct device *dev)
+{
+ if (WARN_ON(is_sysmmu_active(dev_get_drvdata(dev))))
+ return -EFAULT;
+
+ return 0;
+}
+
+int exynos_sysmmu_runtime_resume(struct device *dev)
+{
+ if (WARN_ON(is_sysmmu_active(dev_get_drvdata(dev))))
+ return -EFAULT;
+
+ return 0;
+}
+
+const struct dev_pm_ops exynos_sysmmu_pm_ops = {
+ .runtime_suspend = exynos_sysmmu_runtime_suspend,
+ .runtime_resume = exynos_sysmmu_runtime_resume,
+};
+
+static struct platform_driver exynos_sysmmu_driver = {
+ .probe = exynos_sysmmu_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s5p-sysmmu",
+ .pm = &exynos_sysmmu_pm_ops,
+ }
+};
+
+static int __init exynos_sysmmu_init(void)
+{
+ return platform_driver_register(&exynos_sysmmu_driver);
+}
+arch_initcall(exynos_sysmmu_init);
+
+/* We does not consider super section mapping (16MB) */
+#define S5P_SPAGE_SHIFT 12
+#define S5P_LPAGE_SHIFT 16
+#define S5P_SECTION_SHIFT 20
+
+#define S5P_SPAGE_SIZE (1 << S5P_SPAGE_SHIFT)
+#define S5P_LPAGE_SIZE (1 << S5P_LPAGE_SHIFT)
+#define S5P_SECTION_SIZE (1 << S5P_SECTION_SHIFT)
+
+#define S5P_SPAGE_MASK (~(S5P_SPAGE_SIZE - 1))
+#define S5P_LPAGE_MASK (~(S5P_LPAGE_SIZE - 1))
+#define S5P_SECTION_MASK (~(S5P_SECTION_SIZE - 1))
+
+#define S5P_SPAGE_ORDER (S5P_SPAGE_SHIFT - PAGE_SHIFT)
+#define S5P_LPAGE_ORDER (S5P_LPAGE_SHIFT - S5P_SPAGE_SHIFT)
+#define S5P_SECTION_ORDER (S5P_SECTION_SHIFT - S5P_SPAGE_SHIFT)
+
+#define S5P_LV1TABLE_ENTRIES (1 << (BITS_PER_LONG - S5P_SECTION_SHIFT))
+
+#define S5P_LV2TABLE_ENTRIES (1 << S5P_SECTION_ORDER)
+#define S5P_LV2TABLE_SIZE (S5P_LV2TABLE_ENTRIES * sizeof(long))
+#define S5P_LV2TABLE_MASK (~(S5P_LV2TABLE_SIZE - 1)) /* 0xFFFFFC00 */
+
+#define S5P_SECTION_LV1_ENTRY(entry) ((entry & 0x40003) == 2)
+#define S5P_SUPSECT_LV1_ENTRY(entry) ((entry & 0x40003) == 0x40002)
+#define S5P_PAGE_LV1_ENTRY(entry) ((entry & 3) == 1)
+#define S5P_FAULT_LV1_ENTRY(entry) (((entry & 3) == 0) || (entry & 3) == 3)
+
+#define S5P_LPAGE_LV2_ENTRY(entry) ((entry & 3) == 1)
+#define S5P_SPAGE_LV2_ENTRY(entry) ((entry & 2) == 2)
+#define S5P_FAULT_LV2_ENTRY(entry) ((entry & 3) == 0)
+
+#define MAKE_FAULT_ENTRY(entry) do { entry = 0; } while (0)
+#define MAKE_SECTION_ENTRY(entry, pa) do { entry = pa | 2; } while (0)
+#define MAKE_SUPSECT_ENTRY(entry, pa) do { entry = pa | 0x40002; } while (0)
+#define MAKE_LV2TABLE_ENTRY(entry, pa) do { entry = pa | 1; } while (0)
+
+#define MAKE_LPAGE_ENTRY(entry, pa) do { entry = pa | 1; } while (0)
+#define MAKE_SPAGE_ENTRY(entry, pa) do { entry = pa | 3; } while (0)
+
+#define GET_LV2ENTRY(entry, iova) (\
+ (unsigned long *)phys_to_virt(entry & S5P_LV2TABLE_MASK) +\
+ ((iova & (~S5P_SECTION_MASK)) >> S5P_SPAGE_SHIFT))
+
+/* slab cache for level 2 page tables */
+static struct kmem_cache *l2table_cachep;
+
+static inline void pgtable_flush(void *vastart, void *vaend)
+{
+ dmac_flush_range(vastart, vaend);
+ outer_flush_range(virt_to_phys(vastart),
+ virt_to_phys(vaend));
+}
+
+static int exynos_iommu_domain_init(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pgtable = (unsigned long *)__get_free_pages(GFP_KERNEL,
+ (S5P_LV1TABLE_ENTRIES * sizeof(unsigned long)) >> PAGE_SHIFT);
+ if (!priv->pgtable) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ memset(priv->pgtable, 0, S5P_LV1TABLE_ENTRIES * sizeof(unsigned long));
+ pgtable_flush(priv->pgtable, priv->pgtable + S5P_LV1TABLE_ENTRIES);
+
+ spin_lock_init(&priv->lock);
+
+ domain->priv = priv;
+
+ iommu_set_fault_handler(domain, &exynos_iommu_fault_handler);
+
+ return 0;
+}
+
+static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ free_pages((unsigned long)priv->pgtable,
+ (S5P_LV1TABLE_ENTRIES * sizeof(unsigned long)) >> PAGE_SHIFT);
+
+ kfree(priv);
+
+ domain->priv = NULL;
+}
+
+static int exynos_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ int ret;
+
+ spin_lock(&priv->lock);
+
+ priv->dev = dev;
+
+ ret = exynos_iommu_enable(domain);
+
+ spin_unlock(&priv->lock);
+
+ return ret;
+}
+
+static void exynos_iommu_detach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ spin_lock(&priv->lock);
+
+ if (priv->dev == dev) {
+ exynos_iommu_disable(domain);
+ priv->dev = NULL;
+ }
+
+ spin_unlock(&priv->lock);
+}
+
+static bool section_available(struct iommu_domain *domain,
+ unsigned long *lv1entry)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ if (S5P_SECTION_LV1_ENTRY(*lv1entry)) {
+ dev_err(priv->dev, "1MB entry alread exists at 0x%08x\n",
+ (lv1entry - priv->pgtable) * SZ_1M);
+ return false;
+ }
+
+ if (S5P_PAGE_LV1_ENTRY(*lv1entry)) {
+ unsigned long *lv2end, *lv2base;
+
+ lv2base = phys_to_virt(*lv1entry & S5P_LV2TABLE_MASK);
+ lv2end = lv2base + S5P_LV2TABLE_ENTRIES;
+ while (lv2base != lv2end) {
+ if (!S5P_FAULT_LV2_ENTRY(*lv2base)) {
+ dev_err(priv->dev, "Failed to free L2 page "
+ "table for section mapping.\n");
+ return false;
+ }
+ lv2base++;
+ }
+
+ kmem_cache_free(l2table_cachep,
+ phys_to_virt(*lv1entry & S5P_LV2TABLE_MASK));
+
+ MAKE_FAULT_ENTRY(*lv1entry);
+ }
+
+ return true;
+}
+
+static bool write_lpage(unsigned long *head_entry, unsigned long phys_addr)
+{
+ unsigned long *entry, *end;
+
+ entry = head_entry;
+ end = entry + (1 << S5P_LPAGE_ORDER);
+
+ while (entry != end) {
+ if (!S5P_FAULT_LV2_ENTRY(*entry))
+ break;
+
+ MAKE_LPAGE_ENTRY(*entry, phys_addr);
+
+ entry++;
+ }
+
+ if (entry != end) {
+ end = entry;
+ while (entry != head_entry)
+ MAKE_FAULT_ENTRY(*(--entry));
+
+ return false;
+ }
+
+ return true;
+}
+
+static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, int gfp_order, int prot)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *start_entry, *entry, *end_entry;
+ int num_entry;
+ int ret = 0;
+ unsigned long flags;
+
+ BUG_ON(priv->pgtable == NULL);
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ start_entry = entry = priv->pgtable + (iova >> S5P_SECTION_SHIFT);
+
+ if (gfp_order >= S5P_SECTION_ORDER) {
+ BUG_ON((paddr | iova) & ~S5P_SECTION_MASK);
+ /* 1MiB mapping */
+
+ num_entry = 1 << (gfp_order - S5P_SECTION_ORDER);
+ end_entry = entry + num_entry;
+
+ while (entry != end_entry) {
+ if (!section_available(domain, entry))
+ break;
+
+ MAKE_SECTION_ENTRY(*entry, paddr);
+
+ paddr += S5P_SECTION_SIZE;
+ entry++;
+ }
+
+ if (entry != end_entry)
+ goto mapping_error;
+
+ pgtable_flush(start_entry, entry);
+ goto mapping_done;
+ }
+
+ if (S5P_FAULT_LV1_ENTRY(*entry)) {
+ unsigned long *l2table;
+
+ l2table = kmem_cache_zalloc(l2table_cachep, GFP_KERNEL);
+ if (!l2table) {
+ ret = -ENOMEM;
+ goto nomem_error;
+ }
+
+ pgtable_flush(entry, entry + S5P_LV2TABLE_ENTRIES);
+
+ MAKE_LV2TABLE_ENTRY(*entry, virt_to_phys(l2table));
+ pgtable_flush(entry, entry + 1);
+ }
+
+ /* 'entry' points level 2 entries, hereafter */
+ entry = GET_LV2ENTRY(*entry, iova);
+
+ start_entry = entry;
+ num_entry = 1 << gfp_order;
+ end_entry = entry + num_entry;
+
+ if (gfp_order >= S5P_LPAGE_ORDER) {
+ /* large page(64KiB) mapping */
+ BUG_ON((paddr | iova) & ~S5P_LPAGE_MASK);
+
+ while (entry != end_entry) {
+ if (!write_lpage(entry, paddr)) {
+ pr_err("%s: "
+ "Failed to allocate large page entry."
+ "\n", __func__);
+ break;
+ }
+
+ paddr += S5P_LPAGE_SIZE;
+ entry += (1 << S5P_LPAGE_ORDER);
+ }
+
+ if (entry != end_entry) {
+ entry -= 1 << S5P_LPAGE_ORDER;
+ goto mapping_error;
+ }
+ } else {
+ /* page (4KiB) mapping */
+ while (entry != end_entry && S5P_FAULT_LV2_ENTRY(*entry)) {
+
+ MAKE_SPAGE_ENTRY(*entry, paddr);
+
+ entry++;
+ paddr += S5P_SPAGE_SIZE;
+ }
+
+ if (entry != end_entry) {
+ pr_err("%s: Failed to allocate small page entry.\n",
+ __func__);
+ goto mapping_error;
+ }
+ }
+
+ pgtable_flush(start_entry, entry);
+mapping_error:
+ if (entry != end_entry) {
+ unsigned long *current_entry = entry;
+ while (entry != start_entry)
+ MAKE_FAULT_ENTRY(*(--entry));
+ pgtable_flush(start_entry, current_entry);
+ ret = -EADDRINUSE;
+ }
+
+nomem_error:
+mapping_done:
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ return 0;
+}
+
+static int exynos_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+ int gfp_order)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *entry;
+ int num_entry;
+ unsigned long flags;
+
+ BUG_ON(priv->pgtable == NULL);
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ entry = priv->pgtable + (iova >> S5P_SECTION_SHIFT);
+
+ if (gfp_order >= S5P_SECTION_ORDER) {
+ gfp_order -= S5P_SECTION_ORDER;
+ num_entry = 1 << (gfp_order - S5P_SECTION_ORDER);
+ while (num_entry--) {
+ if (S5P_SECTION_LV1_ENTRY(*entry)) {
+ MAKE_FAULT_ENTRY(*entry);
+ } else if (S5P_PAGE_LV1_ENTRY(*entry)) {
+ unsigned long *lv2beg, *lv2end;
+ lv2beg = phys_to_virt(
+ *entry & S5P_LV2TABLE_MASK);
+ lv2end = lv2beg + S5P_LV2TABLE_ENTRIES;
+ while (lv2beg != lv2end) {
+ MAKE_FAULT_ENTRY(*lv2beg);
+ lv2beg++;
+ }
+ }
+ entry++;
+ }
+ } else {
+ entry = GET_LV2ENTRY(*entry, iova);
+
+ BUG_ON(S5P_LPAGE_LV2_ENTRY(*entry) &&
+ (gfp_order < S5P_LPAGE_ORDER));
+
+ num_entry = 1 << gfp_order;
+
+ while (num_entry--) {
+ MAKE_FAULT_ENTRY(*entry);
+ entry++;
+ }
+ }
+
+ if (priv->dev)
+ exynos_sysmmu_tlb_invalidate(priv->dev);
+
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ return 0;
+}
+
+static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
+ unsigned long iova)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *entry;
+ unsigned long offset;
+
+ entry = priv->pgtable + (iova >> S5P_SECTION_SHIFT);
+
+ if (S5P_FAULT_LV1_ENTRY(*entry))
+ return 0;
+
+ offset = iova & ~S5P_SECTION_MASK;
+
+ if (S5P_SECTION_LV1_ENTRY(*entry))
+ return (*entry & S5P_SECTION_MASK) + offset;
+
+ entry = GET_LV2ENTRY(*entry, iova);
+
+ if (S5P_SPAGE_LV2_ENTRY(*entry))
+ return (*entry & S5P_SPAGE_MASK) + (iova & ~S5P_SPAGE_MASK);
+
+ if (S5P_LPAGE_LV2_ENTRY(*entry))
+ return (*entry & S5P_LPAGE_MASK) + (iova & ~S5P_LPAGE_MASK);
+
+ return 0;
+}
+
+static int exynos_iommu_domain_has_cap(struct iommu_domain *domain,
+ unsigned long cap)
+{
+ return 0;
+}
+
+static struct iommu_ops exynos_iommu_ops = {
+ .domain_init = &exynos_iommu_domain_init,
+ .domain_destroy = &exynos_iommu_domain_destroy,
+ .attach_dev = &exynos_iommu_attach_device,
+ .detach_dev = &exynos_iommu_detach_device,
+ .map = &exynos_iommu_map,
+ .unmap = &exynos_iommu_unmap,
+ .iova_to_phys = &exynos_iommu_iova_to_phys,
+ .domain_has_cap = &exynos_iommu_domain_has_cap,
+};
+
+static int __init exynos_iommu_init(void)
+{
+ l2table_cachep = kmem_cache_create("SysMMU Lv2 Tables",
+ S5P_LV2TABLE_SIZE, S5P_LV2TABLE_SIZE, 0, NULL);
+ if (!l2table_cachep)
+ return -ENOMEM;
+
+ register_iommu(&exynos_iommu_ops);
+
+ return 0;
+}
+arch_initcall(exynos_iommu_init);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 2/5] ARM: S5P: Remove system MMU driver from arm/plat-s5p
From: Kukjin Kim @ 2011-09-30 7:30 UTC (permalink / raw)
To: linux-arm-kernel
From: KyongHo Cho <pullip.cho@samsung.com>
Due to Ohad Ben-Cohen gathered IOMMU drivers in drivers/iommu directory,
System MMU driver is moved to drivers/iommu directory and removed
from arch/arm/plat-s5p directory.
Please see
https://lkml.org/lkml/2011/6/8/69
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
arch/arm/plat-s5p/Kconfig | 8 -
arch/arm/plat-s5p/Makefile | 1 -
arch/arm/plat-s5p/include/plat/sysmmu.h | 95 ----------
arch/arm/plat-s5p/sysmmu.c | 312 -------------------------------
4 files changed, 0 insertions(+), 416 deletions(-)
delete mode 100644 arch/arm/plat-s5p/include/plat/sysmmu.h
delete mode 100644 arch/arm/plat-s5p/sysmmu.c
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index f9241a7..05ee709 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -40,14 +40,6 @@ config S5P_HRT
help
Use the High Resolution timer support
-comment "System MMU"
-
-config S5P_SYSTEM_MMU
- bool "S5P SYSTEM MMU"
- depends on ARCH_EXYNOS4
- help
- Say Y here if you want to enable System MMU
-
config S5P_DEV_FIMC0
bool
help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 1812019..afa0718 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -19,7 +19,6 @@ obj-y += clock.o
obj-y += irq.o
obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o
obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o
-obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM) += irq-pm.o
obj-$(CONFIG_S5P_HRT) += s5p-time.o
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
deleted file mode 100644
index bf5283c..0000000
--- a/arch/arm/plat-s5p/include/plat/sysmmu.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Samsung System MMU driver for S5P platform
- *
- * 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.
-*/
-
-#ifndef __ASM__PLAT_SYSMMU_H
-#define __ASM__PLAT_SYSMMU_H __FILE__
-
-enum S5P_SYSMMU_INTERRUPT_TYPE {
- SYSMMU_PAGEFAULT,
- SYSMMU_AR_MULTIHIT,
- SYSMMU_AW_MULTIHIT,
- SYSMMU_BUSERROR,
- SYSMMU_AR_SECURITY,
- SYSMMU_AR_ACCESS,
- SYSMMU_AW_SECURITY,
- SYSMMU_AW_PROTECTION, /* 7 */
- SYSMMU_FAULTS_NUM
-};
-
-#ifdef CONFIG_S5P_SYSTEM_MMU
-
-#include <mach/sysmmu.h>
-
-/**
- * s5p_sysmmu_enable() - enable system mmu of ip
- * @ips: The ip connected system mmu.
- * #pgd: Base physical address of the 1st level page table
- *
- * This function enable system mmu to transfer address
- * from virtual address to physical address
- */
-void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_disable() - disable sysmmu mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function disable system mmu to transfer address
- * from virtual address to physical address
- */
-void s5p_sysmmu_disable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
- * @ips: The ip connected system mmu.
- * @pgd: The page table base address.
- *
- * This function set page table base address
- * When system mmu transfer address from virtaul address to physical address,
- * system mmu refer address information from page table
- */
-void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
- * @ips: The ip connected system mmu.
- *
- * This function flush all TLB entry in system mmu
- */
-void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
-
-/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs
- * @itype: type of fault.
- * @pgtable_base: the physical address of page table base. This is 0 if @ips is
- * SYSMMU_BUSERROR.
- * @fault_addr: the device (virtual) address that the System MMU tried to
- * translated. This is 0 if @ips is SYSMMU_BUSERROR.
- * Called when interrupt occurred by the System MMUs
- * The device drivers of peripheral devices that has a System MMU can implement
- * a fault handler to resolve address translation fault by System MMU.
- * The meanings of return value and parameters are described below.
-
- * return value: non-zero if the fault is correctly resolved.
- * zero if the fault is not handled.
- */
-void s5p_sysmmu_set_fault_handler(sysmmu_ips ips,
- int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr));
-#else
-#define s5p_sysmmu_enable(ips, pgd) do { } while (0)
-#define s5p_sysmmu_disable(ips) do { } while (0)
-#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0)
-#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0)
-#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0)
-#endif
-#endif /* __ASM_PLAT_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
deleted file mode 100644
index e1cbc72..0000000
--- a/arch/arm/plat-s5p/sysmmu.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/* linux/arch/arm/plat-s5p/sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.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/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <asm/pgtable.h>
-
-#include <mach/map.h>
-#include <mach/regs-sysmmu.h>
-#include <plat/sysmmu.h>
-
-#define CTRL_ENABLE 0x5
-#define CTRL_BLOCK 0x7
-#define CTRL_DISABLE 0x0
-
-static struct device *dev;
-
-static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
- S5P_PAGE_FAULT_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AW_FAULT_ADDR,
- S5P_DEFAULT_SLAVE_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AW_FAULT_ADDR,
- S5P_AW_FAULT_ADDR
-};
-
-static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
- "PAGE FAULT",
- "AR MULTI-HIT FAULT",
- "AW MULTI-HIT FAULT",
- "BUS ERROR",
- "AR SECURITY PROTECTION FAULT",
- "AR ACCESS PROTECTION FAULT",
- "AW SECURITY PROTECTION FAULT",
- "AW ACCESS PROTECTION FAULT"
-};
-
-static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
- enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr);
-
-/*
- * If adjacent 2 bits are true, the system MMU is enabled.
- * The system MMU is disabled, otherwise.
- */
-static unsigned long sysmmu_states;
-
-static inline void set_sysmmu_active(sysmmu_ips ips)
-{
- sysmmu_states |= 3 << (ips * 2);
-}
-
-static inline void set_sysmmu_inactive(sysmmu_ips ips)
-{
- sysmmu_states &= ~(3 << (ips * 2));
-}
-
-static inline int is_sysmmu_active(sysmmu_ips ips)
-{
- return sysmmu_states & (3 << (ips * 2));
-}
-
-static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
-
-static inline void sysmmu_block(sysmmu_ips ips)
-{
- __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
- dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void sysmmu_unblock(sysmmu_ips ips)
-{
- __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
- __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
- dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
-{
- if (unlikely(pgd == 0)) {
- pgd = (unsigned long)ZERO_PAGE(0);
- __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */
- } else {
- __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */
- }
-
- __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
-
- dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
- sysmmu_ips_name[ips], pgd);
- __sysmmu_tlb_invalidate(ips);
-}
-
-void sysmmu_set_fault_handler(sysmmu_ips ips,
- int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr))
-{
- BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
- fault_handlers[ips] = handler;
-}
-
-static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
-{
- /* SYSMMU is in blocked when interrupt occurred. */
- unsigned long base = 0;
- sysmmu_ips ips = (sysmmu_ips)dev_id;
- enum S5P_SYSMMU_INTERRUPT_TYPE itype;
-
- itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
- __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
-
- BUG_ON(!((itype >= 0) && (itype < 8)));
-
- dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
- sysmmu_ips_name[ips]);
-
- if (fault_handlers[ips]) {
- unsigned long addr;
-
- base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
- addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]);
-
- if (fault_handlers[ips](itype, base, addr)) {
- __raw_writel(1 << itype,
- sysmmusfrs[ips] + S5P_INT_CLEAR);
- dev_notice(dev, "%s from %s is resolved."
- " Retrying translation.\n",
- sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
- } else {
- base = 0;
- }
- }
-
- sysmmu_unblock(ips);
-
- if (!base)
- dev_notice(dev, "%s from %s is not handled.\n",
- sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
-
- return IRQ_HANDLED;
-}
-
-void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
-{
- if (is_sysmmu_active(ips)) {
- sysmmu_block(ips);
- __sysmmu_set_ptbase(ips, pgd);
- sysmmu_unblock(ips);
- } else {
- dev_dbg(dev, "%s is disabled. "
- "Skipping initializing page table base.\n",
- sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
-{
- if (!is_sysmmu_active(ips)) {
- sysmmu_clk_enable(ips);
-
- __sysmmu_set_ptbase(ips, pgd);
-
- __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
-
- set_sysmmu_active(ips);
- dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
- } else {
- dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_disable(sysmmu_ips ips)
-{
- if (is_sysmmu_active(ips)) {
- __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- set_sysmmu_inactive(ips);
- sysmmu_clk_disable(ips);
- dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
- } else {
- dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
- if (is_sysmmu_active(ips)) {
- sysmmu_block(ips);
- __sysmmu_tlb_invalidate(ips);
- sysmmu_unblock(ips);
- } else {
- dev_dbg(dev, "%s is disabled. "
- "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]);
- }
-}
-
-static int s5p_sysmmu_probe(struct platform_device *pdev)
-{
- int i, ret;
- struct resource *res, *mem;
-
- dev = &pdev->dev;
-
- for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
- int irq;
-
- sysmmu_clk_init(dev, i);
- sysmmu_clk_disable(i);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- dev_err(dev, "Failed to get the resource of %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENODEV;
- goto err_res;
- }
-
- mem = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (!mem) {
- dev_err(dev, "Failed to request the memory region of %s.\n",
- sysmmu_ips_name[i]);
- ret = -EBUSY;
- goto err_res;
- }
-
- sysmmusfrs[i] = ioremap(res->start, resource_size(res));
- if (!sysmmusfrs[i]) {
- dev_err(dev, "Failed to ioremap() for %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENXIO;
- goto err_reg;
- }
-
- irq = platform_get_irq(pdev, i);
- if (irq <= 0) {
- dev_err(dev, "Failed to get the IRQ resource of %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENOENT;
- goto err_map;
- }
-
- if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
- pdev->name, (void *)i)) {
- dev_err(dev, "Failed to request IRQ for %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENOENT;
- goto err_map;
- }
- }
-
- return 0;
-
-err_map:
- iounmap(sysmmusfrs[i]);
-err_reg:
- release_mem_region(mem->start, resource_size(mem));
-err_res:
- return ret;
-}
-
-static int s5p_sysmmu_remove(struct platform_device *pdev)
-{
- return 0;
-}
-int s5p_sysmmu_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
-int s5p_sysmmu_runtime_resume(struct device *dev)
-{
- return 0;
-}
-
-const struct dev_pm_ops s5p_sysmmu_pm_ops = {
- .runtime_suspend = s5p_sysmmu_runtime_suspend,
- .runtime_resume = s5p_sysmmu_runtime_resume,
-};
-
-static struct platform_driver s5p_sysmmu_driver = {
- .probe = s5p_sysmmu_probe,
- .remove = s5p_sysmmu_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s5p-sysmmu",
- .pm = &s5p_sysmmu_pm_ops,
- }
-};
-
-static int __init s5p_sysmmu_init(void)
-{
- return platform_driver_register(&s5p_sysmmu_driver);
-}
-arch_initcall(s5p_sysmmu_init);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 1/5] ARM: EXYNOS4: Change System MMU device definition
From: Kukjin Kim @ 2011-09-30 7:30 UTC (permalink / raw)
To: linux-arm-kernel
From: KyongHo Cho <pullip.cho@samsung.com>
This patch contains a lot of changes of System MMU device definition.
1. Removed sysmmu_ips enumeration that are definitions of ID of System MMU
Instead, a System MMU device descriptor must be bound with a device
descriptor that needs System MMU in machine initialization.
2. Removed MDMA that is included in LCD0 block because it is not used
anymore. Use MDMA in TOP block.
3. Changed System MMU definitions of platform device. It is not an array
anymore.
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
arch/arm/mach-exynos4/Kconfig | 2 -
arch/arm/mach-exynos4/clock.c | 43 +++--
arch/arm/mach-exynos4/dev-sysmmu.c | 270 ++++++---------------------
arch/arm/mach-exynos4/include/mach/irqs.h | 1 -
arch/arm/mach-exynos4/include/mach/map.h | 1 -
arch/arm/mach-exynos4/include/mach/sysmmu.h | 85 +++++----
arch/arm/mach-exynos4/mach-armlex4210.c | 24 +++-
arch/arm/mach-exynos4/mach-smdkv310.c | 28 +++-
8 files changed, 186 insertions(+), 268 deletions(-)
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index 3b594fe..e9ccf5e 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -141,7 +141,6 @@ config MACH_SMDKV310
select SAMSUNG_DEV_KEYPAD
select EXYNOS4_DEV_PD
select SAMSUNG_DEV_PWM
- select EXYNOS4_DEV_SYSMMU
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
@@ -158,7 +157,6 @@ config MACH_ARMLEX4210
select S3C_DEV_HSMMC2
select S3C_DEV_HSMMC3
select EXYNOS4_DEV_AHCI
- select EXYNOS4_DEV_SYSMMU
select EXYNOS4_SETUP_SDHCI
help
Machine support for Samsung ARMLEX4210 based on EXYNOS4210
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index da9567a..b907d5f 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -691,59 +691,68 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 14),
}, {
- .name = "SYSMMU_MDMA",
- .enable = exynos4_clk_ip_image_ctrl,
- .ctrlbit = (1 << 5),
- }, {
- .name = "SYSMMU_FIMC0",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(fimc0, 1),
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 7),
}, {
- .name = "SYSMMU_FIMC1",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(fimc1, 2),
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 8),
}, {
- .name = "SYSMMU_FIMC2",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(fimc2, 3),
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 9),
}, {
- .name = "SYSMMU_FIMC3",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(fimc3, 4),
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 10),
}, {
- .name = "SYSMMU_JPEG",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(jpeg, 5),
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 11),
}, {
- .name = "SYSMMU_FIMD0",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(fimd0, 6),
.enable = exynos4_clk_ip_lcd0_ctrl,
.ctrlbit = (1 << 4),
}, {
- .name = "SYSMMU_FIMD1",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(fimd1, 7),
.enable = exynos4_clk_ip_lcd1_ctrl,
.ctrlbit = (1 << 4),
}, {
- .name = "SYSMMU_PCIe",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(pcie, 8),
.enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 18),
}, {
- .name = "SYSMMU_G2D",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(g2d, 9),
.enable = exynos4_clk_ip_image_ctrl,
.ctrlbit = (1 << 3),
}, {
- .name = "SYSMMU_ROTATOR",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(rot, 10),
.enable = exynos4_clk_ip_image_ctrl,
.ctrlbit = (1 << 4),
}, {
- .name = "SYSMMU_TV",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(tv, 12),
.enable = exynos4_clk_ip_tv_ctrl,
.ctrlbit = (1 << 4),
}, {
- .name = "SYSMMU_MFC_L",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(mfc_l, 13),
.enable = exynos4_clk_ip_mfc_ctrl,
.ctrlbit = (1 << 1),
}, {
- .name = "SYSMMU_MFC_R",
+ .name = "sysmmu",
+ .devname = SYSMMU_CLOCK_NAME(mfc_r, 14),
.enable = exynos4_clk_ip_mfc_ctrl,
.ctrlbit = (1 << 2),
}
diff --git a/arch/arm/mach-exynos4/dev-sysmmu.c b/arch/arm/mach-exynos4/dev-sysmmu.c
index 3b7cae0..2a5736b 100644
--- a/arch/arm/mach-exynos4/dev-sysmmu.c
+++ b/arch/arm/mach-exynos4/dev-sysmmu.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-exynos4/dev-sysmmu.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS4 - System MMU support
@@ -12,221 +12,71 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#include <plat/s5p-clock.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <mach/sysmmu.h>
-#include <plat/s5p-clock.h>
-
-/* These names must be equal to the clock names in mach-exynos4/clock.c */
-const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = {
- "SYSMMU_MDMA" ,
- "SYSMMU_SSS" ,
- "SYSMMU_FIMC0" ,
- "SYSMMU_FIMC1" ,
- "SYSMMU_FIMC2" ,
- "SYSMMU_FIMC3" ,
- "SYSMMU_JPEG" ,
- "SYSMMU_FIMD0" ,
- "SYSMMU_FIMD1" ,
- "SYSMMU_PCIe" ,
- "SYSMMU_G2D" ,
- "SYSMMU_ROTATOR",
- "SYSMMU_MDMA2" ,
- "SYSMMU_TV" ,
- "SYSMMU_MFC_L" ,
- "SYSMMU_MFC_R" ,
-};
-
-static struct resource exynos4_sysmmu_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_SYSMMU_MDMA,
- .end = EXYNOS4_PA_SYSMMU_MDMA + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_SYSMMU_MDMA0_0,
- .end = IRQ_SYSMMU_MDMA0_0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = EXYNOS4_PA_SYSMMU_SSS,
- .end = EXYNOS4_PA_SYSMMU_SSS + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [3] = {
- .start = IRQ_SYSMMU_SSS_0,
- .end = IRQ_SYSMMU_SSS_0,
- .flags = IORESOURCE_IRQ,
- },
- [4] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC0,
- .end = EXYNOS4_PA_SYSMMU_FIMC0 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [5] = {
- .start = IRQ_SYSMMU_FIMC0_0,
- .end = IRQ_SYSMMU_FIMC0_0,
- .flags = IORESOURCE_IRQ,
- },
- [6] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC1,
- .end = EXYNOS4_PA_SYSMMU_FIMC1 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [7] = {
- .start = IRQ_SYSMMU_FIMC1_0,
- .end = IRQ_SYSMMU_FIMC1_0,
- .flags = IORESOURCE_IRQ,
- },
- [8] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC2,
- .end = EXYNOS4_PA_SYSMMU_FIMC2 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [9] = {
- .start = IRQ_SYSMMU_FIMC2_0,
- .end = IRQ_SYSMMU_FIMC2_0,
- .flags = IORESOURCE_IRQ,
- },
- [10] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC3,
- .end = EXYNOS4_PA_SYSMMU_FIMC3 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [11] = {
- .start = IRQ_SYSMMU_FIMC3_0,
- .end = IRQ_SYSMMU_FIMC3_0,
- .flags = IORESOURCE_IRQ,
- },
- [12] = {
- .start = EXYNOS4_PA_SYSMMU_JPEG,
- .end = EXYNOS4_PA_SYSMMU_JPEG + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [13] = {
- .start = IRQ_SYSMMU_JPEG_0,
- .end = IRQ_SYSMMU_JPEG_0,
- .flags = IORESOURCE_IRQ,
- },
- [14] = {
- .start = EXYNOS4_PA_SYSMMU_FIMD0,
- .end = EXYNOS4_PA_SYSMMU_FIMD0 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [15] = {
- .start = IRQ_SYSMMU_LCD0_M0_0,
- .end = IRQ_SYSMMU_LCD0_M0_0,
- .flags = IORESOURCE_IRQ,
- },
- [16] = {
- .start = EXYNOS4_PA_SYSMMU_FIMD1,
- .end = EXYNOS4_PA_SYSMMU_FIMD1 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [17] = {
- .start = IRQ_SYSMMU_LCD1_M1_0,
- .end = IRQ_SYSMMU_LCD1_M1_0,
- .flags = IORESOURCE_IRQ,
- },
- [18] = {
- .start = EXYNOS4_PA_SYSMMU_PCIe,
- .end = EXYNOS4_PA_SYSMMU_PCIe + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [19] = {
- .start = IRQ_SYSMMU_PCIE_0,
- .end = IRQ_SYSMMU_PCIE_0,
- .flags = IORESOURCE_IRQ,
- },
- [20] = {
- .start = EXYNOS4_PA_SYSMMU_G2D,
- .end = EXYNOS4_PA_SYSMMU_G2D + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [21] = {
- .start = IRQ_SYSMMU_2D_0,
- .end = IRQ_SYSMMU_2D_0,
- .flags = IORESOURCE_IRQ,
- },
- [22] = {
- .start = EXYNOS4_PA_SYSMMU_ROTATOR,
- .end = EXYNOS4_PA_SYSMMU_ROTATOR + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [23] = {
- .start = IRQ_SYSMMU_ROTATOR_0,
- .end = IRQ_SYSMMU_ROTATOR_0,
- .flags = IORESOURCE_IRQ,
- },
- [24] = {
- .start = EXYNOS4_PA_SYSMMU_MDMA2,
- .end = EXYNOS4_PA_SYSMMU_MDMA2 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [25] = {
- .start = IRQ_SYSMMU_MDMA1_0,
- .end = IRQ_SYSMMU_MDMA1_0,
- .flags = IORESOURCE_IRQ,
- },
- [26] = {
- .start = EXYNOS4_PA_SYSMMU_TV,
- .end = EXYNOS4_PA_SYSMMU_TV + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [27] = {
- .start = IRQ_SYSMMU_TV_M0_0,
- .end = IRQ_SYSMMU_TV_M0_0,
- .flags = IORESOURCE_IRQ,
- },
- [28] = {
- .start = EXYNOS4_PA_SYSMMU_MFC_L,
- .end = EXYNOS4_PA_SYSMMU_MFC_L + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [29] = {
- .start = IRQ_SYSMMU_MFC_M0_0,
- .end = IRQ_SYSMMU_MFC_M0_0,
- .flags = IORESOURCE_IRQ,
- },
- [30] = {
- .start = EXYNOS4_PA_SYSMMU_MFC_R,
- .end = EXYNOS4_PA_SYSMMU_MFC_R + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [31] = {
- .start = IRQ_SYSMMU_MFC_M1_0,
- .end = IRQ_SYSMMU_MFC_M1_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-struct platform_device exynos4_device_sysmmu = {
- .name = "s5p-sysmmu",
- .id = 32,
- .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource),
- .resource = exynos4_sysmmu_resource,
-};
-EXPORT_SYMBOL(exynos4_device_sysmmu);
-
-static struct clk *sysmmu_clk[S5P_SYSMMU_TOTAL_IPNUM];
-void sysmmu_clk_init(struct device *dev, sysmmu_ips ips)
-{
- sysmmu_clk[ips] = clk_get(dev, sysmmu_ips_name[ips]);
- if (IS_ERR(sysmmu_clk[ips]))
- sysmmu_clk[ips] = NULL;
- else
- clk_put(sysmmu_clk[ips]);
+#define SYSMMU_RESOURCE(ipname, base, irq) \
+static struct resource sysmmu_resource_##ipname[] =\
+{\
+ {\
+ .start = EXYNOS4_PA_SYSMMU_##base,\
+ .end = EXYNOS4_PA_SYSMMU_##base + SZ_4K - 1,\
+ .flags = IORESOURCE_MEM,\
+ }, {\
+ .start = IRQ_SYSMMU_##irq##_0,\
+ .end = IRQ_SYSMMU_##irq##_0,\
+ .flags = IORESOURCE_IRQ,\
+ },\
}
-void sysmmu_clk_enable(sysmmu_ips ips)
-{
- if (sysmmu_clk[ips])
- clk_enable(sysmmu_clk[ips]);
+#define SYSMMU_PLATFORM_DEVICE(ipname, devid) \
+struct platform_device SYSMMU_PLATDEV(ipname) =\
+{\
+ .name = SYSMMU_DEVNAME_BASE,\
+ .id = devid,\
+ .num_resources = ARRAY_SIZE(sysmmu_resource_##ipname),\
+ .resource = sysmmu_resource_##ipname,\
+ .dev = {\
+ .dma_mask = &exynos_sysmmu_dma_mask,\
+ .coherent_dma_mask = DMA_BIT_MASK(32),\
+ },\
}
-void sysmmu_clk_disable(sysmmu_ips ips)
-{
- if (sysmmu_clk[ips])
- clk_disable(sysmmu_clk[ips]);
-}
+static u64 exynos_sysmmu_dma_mask = DMA_BIT_MASK(32);
+
+SYSMMU_RESOURCE(sss, SSS, SSS);
+SYSMMU_RESOURCE(fimc0, FIMC0, FIMC0);
+SYSMMU_RESOURCE(fimc1, FIMC1, FIMC1);
+SYSMMU_RESOURCE(fimc2, FIMC2, FIMC2);
+SYSMMU_RESOURCE(fimc3, FIMC3, FIMC3);
+SYSMMU_RESOURCE(jpeg, JPEG, JPEG);
+SYSMMU_RESOURCE(fimd0, FIMD0, LCD0_M0);
+SYSMMU_RESOURCE(fimd1, FIMD1, LCD1_M1);
+SYSMMU_RESOURCE(pcie, PCIe, PCIE);
+SYSMMU_RESOURCE(g2d, G2D, 2D);
+SYSMMU_RESOURCE(rot, ROTATOR, ROTATOR);
+SYSMMU_RESOURCE(mdma, MDMA2, MDMA1);
+SYSMMU_RESOURCE(tv, TV, TV_M0);
+SYSMMU_RESOURCE(mfc_l, MFC_L, MFC_M0);
+SYSMMU_RESOURCE(mfc_r, MFC_R, MFC_M1);
+
+SYSMMU_PLATFORM_DEVICE(sss, 0);
+SYSMMU_PLATFORM_DEVICE(fimc0, 1);
+SYSMMU_PLATFORM_DEVICE(fimc1, 2);
+SYSMMU_PLATFORM_DEVICE(fimc2, 3);
+SYSMMU_PLATFORM_DEVICE(fimc3, 4);
+SYSMMU_PLATFORM_DEVICE(jpeg, 5);
+SYSMMU_PLATFORM_DEVICE(fimd0, 6);
+SYSMMU_PLATFORM_DEVICE(fimd1, 7);
+SYSMMU_PLATFORM_DEVICE(pcie, 8);
+SYSMMU_PLATFORM_DEVICE(g2d, 9);
+SYSMMU_PLATFORM_DEVICE(rot, 10);
+SYSMMU_PLATFORM_DEVICE(mdma, 11);
+SYSMMU_PLATFORM_DEVICE(tv, 12);
+SYSMMU_PLATFORM_DEVICE(mfc_l, 13);
+SYSMMU_PLATFORM_DEVICE(mfc_r, 14);
diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
index 62093b9..9eeb9a6 100644
--- a/arch/arm/mach-exynos4/include/mach/irqs.h
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -123,7 +123,6 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
-#define IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
#define IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
#define IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
#define IRQ_SYSMMU_FIMC1_0 COMBINER_IRQ(4, 3)
diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos4/include/mach/map.h
index 1bea7d1..114d8b8 100644
--- a/arch/arm/mach-exynos4/include/mach/map.h
+++ b/arch/arm/mach-exynos4/include/mach/map.h
@@ -72,7 +72,6 @@
#define EXYNOS4_PA_PDMA0 0x12680000
#define EXYNOS4_PA_PDMA1 0x12690000
-#define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000
#define EXYNOS4_PA_SYSMMU_SSS 0x10A50000
#define EXYNOS4_PA_SYSMMU_FIMC0 0x11A20000
#define EXYNOS4_PA_SYSMMU_FIMC1 0x11A30000
diff --git a/arch/arm/mach-exynos4/include/mach/sysmmu.h b/arch/arm/mach-exynos4/include/mach/sysmmu.h
index 6a5fbb5..1811c20 100644
--- a/arch/arm/mach-exynos4/include/mach/sysmmu.h
+++ b/arch/arm/mach-exynos4/include/mach/sysmmu.h
@@ -3,44 +3,59 @@
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * Samsung sysmmu driver for EXYNOS4
+ * Exynos - System MMU Support
*
* 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.
*/
-#ifndef __ASM_ARM_ARCH_SYSMMU_H
-#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
-
-enum exynos4_sysmmu_ips {
- SYSMMU_MDMA,
- SYSMMU_SSS,
- SYSMMU_FIMC0,
- SYSMMU_FIMC1,
- SYSMMU_FIMC2,
- SYSMMU_FIMC3,
- SYSMMU_JPEG,
- SYSMMU_FIMD0,
- SYSMMU_FIMD1,
- SYSMMU_PCIe,
- SYSMMU_G2D,
- SYSMMU_ROTATOR,
- SYSMMU_MDMA2,
- SYSMMU_TV,
- SYSMMU_MFC_L,
- SYSMMU_MFC_R,
- EXYNOS4_SYSMMU_TOTAL_IPNUM,
-};
-
-#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM
-
-extern const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM];
-
-typedef enum exynos4_sysmmu_ips sysmmu_ips;
-
-void sysmmu_clk_init(struct device *dev, sysmmu_ips ips);
-void sysmmu_clk_enable(sysmmu_ips ips);
-void sysmmu_clk_disable(sysmmu_ips ips);
-
-#endif /* __ASM_ARM_ARCH_SYSMMU_H */
+#ifndef _ARM_MACH_EXYNOS_SYSMMU_H_
+#define _ARM_MACH_EXYNOS_SYSMMU_H_
+
+#include <linux/device.h>
+
+#define SYSMMU_DEVNAME_BASE "s5p-sysmmu"
+#define SYSMMU_CLOCK_NAME(ipname, id) SYSMMU_DEVNAME_BASE "." #id
+
+#ifdef CONFIG_EXYNOS4_DEV_SYSMMU
+
+#define SYSMMU_PLATDEV(ipname) exynos_device_sysmmu_##ipname
+
+#ifdef CONFIG_EXYNOS4_DEV_PD
+#define ASSIGN_SYSMMU_POWERDOMAIN(ipname, powerdomain) \
+ SYSMMU_PLATDEV(mfc_l).dev.parent = powerdomain
+#else
+#define ASSIGN_SYSMMU_POWERDOMAIN(ipname, powerdomain) do { } while (0)
+#endif
+
+extern struct platform_device SYSMMU_PLATDEV(sss);
+extern struct platform_device SYSMMU_PLATDEV(fimc0);
+extern struct platform_device SYSMMU_PLATDEV(fimc1);
+extern struct platform_device SYSMMU_PLATDEV(fimc2);
+extern struct platform_device SYSMMU_PLATDEV(fimc3);
+extern struct platform_device SYSMMU_PLATDEV(jpeg);
+extern struct platform_device SYSMMU_PLATDEV(fimd0);
+extern struct platform_device SYSMMU_PLATDEV(fimd1);
+extern struct platform_device SYSMMU_PLATDEV(pcie);
+extern struct platform_device SYSMMU_PLATDEV(g2d);
+extern struct platform_device SYSMMU_PLATDEV(rot);
+extern struct platform_device SYSMMU_PLATDEV(mdma);
+extern struct platform_device SYSMMU_PLATDEV(tv);
+extern struct platform_device SYSMMU_PLATDEV(mfc_l);
+extern struct platform_device SYSMMU_PLATDEV(mfc_r);
+extern struct platform_device SYSMMU_PLATDEV(g2d_acp);
+
+static inline void sysmmu_set_owner(struct device *sysmmu, struct device *owner)
+{
+ sysmmu->platform_data = owner;
+}
+
+#else /* CONFIG_EXYNOS4_DEV_SYSMMU */
+
+#define sysmmu_set_owner(sysmmu, owner) do { } while (0)
+#define ASSIGN_SYSMMU_POWERDOMAIN(ipname, powerdomain) do { } while (0)
+
+#endif /* CONFIG_EXYNOS4_DEV_SYSMMU */
+
+#endif /* _ARM_MACH_EXYNOS_SYSMMU_H_ */
diff --git a/arch/arm/mach-exynos4/mach-armlex4210.c b/arch/arm/mach-exynos4/mach-armlex4210.c
index b482c62..d7d2ff5 100644
--- a/arch/arm/mach-exynos4/mach-armlex4210.c
+++ b/arch/arm/mach-exynos4/mach-armlex4210.c
@@ -155,7 +155,23 @@ static struct platform_device *armlex4210_devices[] __initdata = {
&s3c_device_hsmmc3,
&s3c_device_rtc,
&s3c_device_wdt,
- &exynos4_device_sysmmu,
+#ifdef CONFIG_EXYNOS4_DEV_SYSMMU
+ &SYSMMU_PLATDEV(sss),
+ &SYSMMU_PLATDEV(fimc0),
+ &SYSMMU_PLATDEV(fimc1),
+ &SYSMMU_PLATDEV(fimc2),
+ &SYSMMU_PLATDEV(fimc3),
+ &SYSMMU_PLATDEV(jpeg),
+ &SYSMMU_PLATDEV(fimd0),
+ &SYSMMU_PLATDEV(fimd1),
+ &SYSMMU_PLATDEV(pcie),
+ &SYSMMU_PLATDEV(g2d),
+ &SYSMMU_PLATDEV(rot),
+ &SYSMMU_PLATDEV(mdma),
+ &SYSMMU_PLATDEV(tv),
+ &SYSMMU_PLATDEV(mfc_l),
+ &SYSMMU_PLATDEV(mfc_r),
+#endif
&samsung_asoc_dma,
&armlex4210_smsc911x,
&exynos4_device_ahci,
@@ -193,6 +209,10 @@ static void __init armlex4210_map_io(void)
ARRAY_SIZE(armlex4210_uartcfgs));
}
+static void __init sysmmu_init(void)
+{
+}
+
static void __init armlex4210_machine_init(void)
{
armlex4210_smsc911x_init();
@@ -201,6 +221,8 @@ static void __init armlex4210_machine_init(void)
armlex4210_wlan_init();
+ sysmmu_init();
+
platform_add_devices(armlex4210_devices,
ARRAY_SIZE(armlex4210_devices));
}
diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c
index 7ce4d8b..f87ad2d 100644
--- a/arch/arm/mach-exynos4/mach-smdkv310.c
+++ b/arch/arm/mach-exynos4/mach-smdkv310.c
@@ -40,6 +40,7 @@
#include <plat/mfc.h>
#include <mach/map.h>
+#include <mach/sysmmu.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDKV310_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -255,7 +256,23 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&exynos4_device_pd[PD_TV],
&exynos4_device_pd[PD_GPS],
&exynos4_device_spdif,
- &exynos4_device_sysmmu,
+#ifdef CONFIG_S5P_SYSTEM_MMU
+ &SYSMMU_PLATDEV(sss),
+ &SYSMMU_PLATDEV(fimc0),
+ &SYSMMU_PLATDEV(fimc1),
+ &SYSMMU_PLATDEV(fimc2),
+ &SYSMMU_PLATDEV(fimc3),
+ &SYSMMU_PLATDEV(jpeg),
+ &SYSMMU_PLATDEV(fimd0),
+ &SYSMMU_PLATDEV(fimd1),
+ &SYSMMU_PLATDEV(pcie),
+ &SYSMMU_PLATDEV(g2d),
+ &SYSMMU_PLATDEV(rot),
+ &SYSMMU_PLATDEV(mdma),
+ &SYSMMU_PLATDEV(tv),
+ &SYSMMU_PLATDEV(mfc_l),
+ &SYSMMU_PLATDEV(mfc_r),
+#endif
&samsung_asoc_dma,
&samsung_asoc_idma,
&s5p_device_fimd0,
@@ -310,6 +327,13 @@ static void __init smdkv310_reserve(void)
s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
}
+static void __init sysmmu_init(void)
+{
+ ASSIGN_SYSMMU_POWERDOMAIN(mfc, &exynos4_device_pd[PD_MFC].dev);
+ sysmmu_set_owner(&SYSMMU_PLATDEV(mfc_l).dev, &s5p_device_mfc.dev);
+ sysmmu_set_owner(&SYSMMU_PLATDEV(mfc_r).dev, &s5p_device_mfc.dev);
+}
+
static void __init smdkv310_machine_init(void)
{
s3c_i2c1_set_platdata(NULL);
@@ -327,6 +351,8 @@ static void __init smdkv310_machine_init(void)
samsung_bl_set(&smdkv310_bl_gpio_info, &smdkv310_bl_data);
s5p_fimd0_set_platdata(&smdkv310_lcd0_pdata);
+ sysmmu_init();
+
platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices));
s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev;
}
--
1.7.1
^ permalink raw reply related
* [PATCH v2 0/5] iommu/exynos: Add IOMMU and Enhance System MMU driver for Exynos4
From: Kukjin Kim @ 2011-09-30 7:30 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
This is the second try of submitting patches about IOMMU/System MMU
driver for Exynos4 SoCs with the fixes of the following problems
pointed by Russell King.:
- Missing unlocking a spinlock in exynos_iommu_attach_dev().
- atomic_t -> int in sysmmu_drvdata.activations
- sysmmu_platdata -> sysmmu_drvdata
- Change in error messages in irq handler
- Removed casting in format of error message
- omap_iommu_ops -> exynos_iommu_ops in the last patch.
First 2 patches enhance System MMU platform device definition:
- Removed System MMU for MDMA0 in LCD block because it is not used.
Use MDMA2 in TOP block.
- Removed System MMU ID. Instead a System MMU is bound to a device that
the System MMU is dedicated during machin initialization. If a device
driver wants to handle System MMU, it must bind its device with System
MMU with sysmmu_set_owner().
- clkdev
- System MMU device driver is removed from arch/arm/plat-s5p to move it
to driver/iommu directory.
Last 3 patches implements IOMMU API:
- Implements IOMMU API and System MMU driver that is moved from
arch/arm/plat-s5p.
- Implements fault handling that is suggested by Ohad.
- Used bus_set_iommu instead of register_iommu that is suggested by Joerg.
[PATCH v2 1/5] ARM: EXYNOS4: Change System MMU device definition
arch/arm/mach-exynos4/Kconfig | 2 -
arch/arm/mach-exynos4/clock.c | 43 +-
arch/arm/mach-exynos4/dev-sysmmu.c | 270 ++------
arch/arm/mach-exynos4/include/mach/irqs.h | 1 -
arch/arm/mach-exynos4/include/mach/map.h | 1 -
arch/arm/mach-exynos4/include/mach/sysmmu.h | 85 ++-
arch/arm/mach-exynos4/mach-armlex4210.c | 24 +-
arch/arm/mach-exynos4/mach-smdkv310.c | 28 +-
arch/arm/plat-s5p/Kconfig | 8 -
arch/arm/plat-s5p/Makefile | 1 -
arch/arm/plat-s5p/include/plat/sysmmu.h | 95 ---
arch/arm/plat-s5p/sysmmu.c | 312 ---------
drivers/iommu/Kconfig | 14 +
drivers/iommu/Makefile | 1 +
drivers/iommu/exynos_iommu.c | 919 +++++++++++++++++++++++++++
15 files changed, 1120 insertions(+), 684 deletions(-)
^ permalink raw reply
* [PATCH 5/5] ARM: pxa: move gpio driver into drivers directory
From: Haojian Zhuang @ 2011-09-30 7:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110929163048.GA21718@n2100.arm.linux.org.uk>
On Fri, Sep 30, 2011 at 12:30 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Thu, Sep 29, 2011 at 11:19:06PM +0800, Haojian Zhuang wrote:
>> +#include <linux/gpio-pxa.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include <asm/io.h>
>
> linux/gpio.h please.
>
Excuse me that I didn't use any gpio API in mach-pxa/gpio.c. It seems
that I needn't include "linux/gpio.h" at mach-pxa/gpio.c.
Thanks
Haojian
^ permalink raw reply
* [patch] ARM: smpboot: Enable interrupts after marking CPU online/active
From: Kukjin Kim @ 2011-09-30 6:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1109292211060.2711@ionos>
Thomas Gleixner wrote:
>
> On Thu, 29 Sep 2011, Kukjin Kim wrote:
> > Russell King - ARM Linux wrote:
> > But as Amit said, current EXYNOS4 SoCs which are using SPI for local timers
> > has problem that the irq_set_affinity() method is called in
> > percpu_timer_setup() before CPU1 becomes online with the commit
> > 5dfc54e087c15f823ee9b6541d2f0f314e69cbed ("ARM: GIC: avoid routing
> > interrupts to offline CPUs"). So I will check again.
>
> Why is a per cpu interrupt having an irq_set_affinity() function at all?
>
Actually, the interrupt of MCT in EXYNOS4210 is SPI(Shared Peripheral Interrupt), which can be routed to any CPUs.
Since its default affinity is 0 so if it is used on CPU1, needs to irq_set_affinity to CPU1 before using it.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply
* [PATCH] mx5: modify pm and idle
From: Hui Wang @ 2011-09-30 6:37 UTC (permalink / raw)
To: linux-arm-kernel
Two problems exist in the current i.MX5 pm suspend/resume and idle
functions. The first is the current i.MX5 suspend routine will call
tzic_enable_wake(1) to set wake source, this will set all enabled
irq as wake source rather than those wake capable. The second
is i.MX5 idle will call mx5_cpu_lp_set() to prepare enter low power
mode, but it forgets to call wfi instruction to enter this mode.
To fix these two problems, using generic irq chip pm interface and
adding a new function mx5_arch_idle().
Signed-off-by: Hui Wang <jason77.wang@gmail.com>
---
This patch is basing on the latest imx-features branch.
This patch is validated on the i.MX51 PDK board (CPU revision 2.0).
Since both pm suspend/resume and idle has close relation with
mx5_cpu_lp_set() and tzic_enable_wake(), i choose to use one patch
instead of independent two to address existing problems.
arch/arm/mach-mx5/system.c | 24 +++++++++++++++--
arch/arm/plat-mxc/include/mach/mxc.h | 2 +-
arch/arm/plat-mxc/include/mach/system.h | 3 +-
arch/arm/plat-mxc/tzic.c | 42 ++++++++++++++++++++++---------
4 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c
index 76ae8dc..92bf341 100644
--- a/arch/arm/mach-mx5/system.c
+++ b/arch/arm/mach-mx5/system.c
@@ -10,11 +10,17 @@
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
+#include <linux/suspend.h>
+#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <mach/hardware.h>
+#include <mach/common.h>
+
#include "crm_regs.h"
+static struct clk *gpc_dvfs_clk;
+
/* set cpu low power mode before WFI instruction. This function is called
* mx5 because it can be used for mx50, mx51, and mx53.*/
void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
@@ -54,9 +60,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
stop_mode = 1;
}
arm_srpgcr |= MXC_SRPGCR_PCR;
-
- if (tzic_enable_wake(1) != 0)
- return;
break;
case STOP_POWER_ON:
ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
@@ -82,3 +85,18 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
__raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR);
}
}
+
+void mx5_arch_idle(void)
+{
+ if (gpc_dvfs_clk == NULL)
+ gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
+
+ /* gpc clock is needed for SRPG */
+ clk_enable(gpc_dvfs_clk);
+ mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+ if (tzic_enable_wake() != 0)
+ goto exit;
+ cpu_do_idle();
+exit:
+ clk_disable(gpc_dvfs_clk);
+}
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 0987923..c4d324a 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -182,7 +182,7 @@ struct cpu_op {
u32 cpu_rate;
};
-int tzic_enable_wake(int is_idle);
+int tzic_enable_wake(void);
enum mxc_cpu_pwr_mode {
WAIT_CLOCKED, /* wfi only */
WAIT_UNCLOCKED, /* WAIT */
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
index 51f02a9..5b6f991 100644
--- a/arch/arm/plat-mxc/include/mach/system.h
+++ b/arch/arm/plat-mxc/include/mach/system.h
@@ -21,6 +21,7 @@
#include <mach/common.h>
extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
+extern void mx5_arch_idle(void);
static inline void arch_idle(void)
{
@@ -51,7 +52,7 @@ static inline void arch_idle(void)
"mcr p15, 0, %0, c1, c0, 0\n"
: "=r" (reg));
} else if (cpu_is_mx51())
- mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+ mx5_arch_idle();
else
cpu_do_idle();
}
diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c
index e993a18..bd73910 100644
--- a/arch/arm/plat-mxc/tzic.c
+++ b/arch/arm/plat-mxc/tzic.c
@@ -72,14 +72,35 @@ static int tzic_set_irq_fiq(unsigned int irq, unsigned int type)
#define tzic_set_irq_fiq NULL
#endif
-static unsigned int *wakeup_intr[4];
-
static struct mxc_extra_irq tzic_extra_irq = {
#ifdef CONFIG_FIQ
.set_irq_fiq = tzic_set_irq_fiq,
#endif
};
+#ifdef CONFIG_PM
+static void tzic_irq_suspend(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ int idx = gc->irq_base >> 5;
+
+ __raw_writel(gc->wake_active, tzic_base + TZIC_WAKEUP0(idx));
+}
+
+static void tzic_irq_resume(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ int idx = gc->irq_base >> 5;
+
+ __raw_writel(__raw_readl(tzic_base + TZIC_ENSET0(idx)),
+ tzic_base + TZIC_WAKEUP0(idx));
+}
+
+#else
+#define tzic_irq_suspend NULL
+#define tzic_irq_resume NULL
+#endif
+
static __init void tzic_init_gc(unsigned int irq_start)
{
struct irq_chip_generic *gc;
@@ -90,12 +111,13 @@ static __init void tzic_init_gc(unsigned int irq_start)
handle_level_irq);
gc->private = &tzic_extra_irq;
gc->wake_enabled = IRQ_MSK(32);
- wakeup_intr[idx] = &gc->wake_active;
ct = gc->chip_types;
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
ct->chip.irq_set_wake = irq_gc_set_wake;
+ ct->chip.irq_suspend = tzic_irq_suspend;
+ ct->chip.irq_resume = tzic_irq_resume;
ct->regs.disable = TZIC_ENCLEAR0(idx);
ct->regs.enable = TZIC_ENSET0(idx);
@@ -166,23 +188,19 @@ void __init tzic_init_irq(void __iomem *irqbase)
/**
* tzic_enable_wake() - enable wakeup interrupt
*
- * @param is_idle 1 if called in idle loop (ENSET0 register);
- * 0 to be used when called from low power entry
* @return 0 if successful; non-zero otherwise
*/
-int tzic_enable_wake(int is_idle)
+int tzic_enable_wake(void)
{
- unsigned int i, v;
+ unsigned int i;
__raw_writel(1, tzic_base + TZIC_DSMINT);
if (unlikely(__raw_readl(tzic_base + TZIC_DSMINT) == 0))
return -EAGAIN;
- for (i = 0; i < 4; i++) {
- v = is_idle ? __raw_readl(tzic_base + TZIC_ENSET0(i)) :
- *wakeup_intr[i];
- __raw_writel(v, tzic_base + TZIC_WAKEUP0(i));
- }
+ for (i = 0; i < 4; i++)
+ __raw_writel(__raw_readl(tzic_base + TZIC_ENSET0(i)),
+ tzic_base + TZIC_WAKEUP0(i));
return 0;
}
--
1.7.6
^ 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