Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv4 5/5] arm64: cpuinfo: print info for all CPUs
From: Catalin Marinas @ 2014-07-17 17:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAFEAcA_ZXDDRycNVXmw1FSgRFiPgtB_2qqe-ioj91jMeBJR7PQ@mail.gmail.com>

On Thu, Jul 17, 2014 at 02:55:37PM +0100, Peter Maydell wrote:
> On 17 July 2014 13:35, Will Deacon <will.deacon@arm.com> wrote:
> > We're not denying the possibility of heterogeneity, we're trying to expose a
> > consistent view of the system to userspace. Differences between cores should
> > be dealt with by the kernel (e.g. IKS, HMP scheduling), not blindly
> > passed off to userspace.
> 
> On that basis, why report anything at all about invididual cores?
> Just have /proc/cpuinfo report "number of processors: 4" and
> no per-CPU information at all...

We lost a lot of time on this already (given the internal threads). So
my proposal is to go ahead with Mark's patch with per-CPU features. They
currently just include the same elf_hwcap multiple times. If we ever
need to present different features, the conditions would be:

1. Never report more than elf_hwcap
2. elf_hwcap can only include non-symmetric features *if* Linux gets a
   way to transparently handle migration or emulation

It basically means that Linux would not rely on the user space to make
informed decisions on where to run a thread and avoid SIGILL.

-- 
Catalin

^ permalink raw reply

* [PATCH 7/8] mailbox: f_mhu: add driver for Fujitsu MHU controller
From: Jassi Brar @ 2014-07-17 17:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53C7E71C.8020501@arm.com>

On 17 July 2014 20:39, Sudeep Holla <sudeep.holla@arm.com> wrote:
>
>
> On 17/07/14 13:56, Jassi Brar wrote:
>>
>> On 17 July 2014 16:01, Sudeep Holla <sudeep.holla@arm.com> wrote:
>>>
>>> On 17/07/14 07:25, Jassi Brar wrote:
>>>>
>>>>
>>>>>
>>>>>> +       u32 val;
>>>>>> +
>>>>>> +       pr_debug("%s:%d\n", __func__, __LINE__);
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Please remove all these debug prints.
>>>>>
>>>> These are as good as absent unless DEBUG is defined.
>>>>
>>>
>>> Yes, but with mailbox framework, the controller driver(esp. this one)is
>>> almost like a shim layer. Instead of each driver adding these debugs,
>>> IMO it would be good to have these in the framework.
>>>
>> OK
>>
>>>>>
>>>>>> +       /* See NOTE_RX_DONE */
>>>>>> +       val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
>>>>>> +       mbox_chan_received_data(chan, (void *)val);
>>>>>> +
>>>>>> +       /*
>>>>>> +        * It is agreed with the remote firmware that the receiver
>>>>>> +        * will clear the STAT register indicating it is ready to
>>>>>> +        * receive next data - NOTE_RX_DONE
>>>>>> +        */
>>>>>
>>>>>
>>>>>
>>>>> This note could be added as how this mailbox works in general and
>>>>> it's not just Rx right ? Even Tx done is based on this logic.
>>>>> Basically the logic is valid on both directions.
>>>>>
>>>> Yes that is a protocol level agreement. Different f/w may behave
>>>> differently.
>>>>
>>>
>>> Ok, I am not sure if that's entirely true because the MHU spec says it
>>> drives
>>> the signal using a 32-bit register, with all 32 bits logically ORed
>>> together.
>>> Usually only Rx signals are wired to interrupts and Tx needs to be polled
>>> but that's entirely implementation choice I believe.
>>>
>> On my platform, _STAT register only carries the command code but
>> actual data is exchanged via SharedMemory/SHM. Now we need to know
>> when the sent data packet (in SHM) has been consumed by the remote -
>> for which our protocol mandates the remote clear the TX_STAT register.
>> And vice-versa for RX.
>>
>>   Some other f/w may choose some other mechanism for TX-Done - say some
>> ACK bit set or even some time bound guarantee.
>>
>>> More over if it's protocol level agreement it should not belong here :)
>>>
>> My f/w expects the RX_STAT cleared after reading data from SHM. Where
>> do you think is the right place to clear RX_STAT?
>>
>
> I understand that and what I am saying is the MHU is designed like that
> and protocol is just using it. There's nothing specific to protocol. Ideally
> if an implementation has both Rx and Tx interrupts, the RX_CLEAR from here
> raises an interrupt to the firmware. In absence of it we need polling that's
> what both Linux and firmware does for Tx case.
>
> Even on Juno, it's same. But we should be able to extend it to support Tx
> if an implementation supports. Similarly the firmware can make use of the
> same when Linux clears Rx(it would be Tx complete/ack for the firmware)
>
> When we need to make this driver work across different firmware, you just
> can't rely on the firmware protocol, hence I am asking to drop those
> comments.
>
OK, I will remove the comment.

>
>> I have said many times in many threads... its the mailbox controller
>> _and_ the remote f/w that should be seen as one entity. It may not be
>> possible to write a controller driver that works with any remote
>> firmware.
>>
>
> It should be possible if the remote protocol just use the same hardware
> feature without any extra software policy at the lowest level(raw Tx and
> Rx).
>
I wouldn't count on f/w always done the right way. And I am speaking
from my whatever first hand experience :D
And sometimes there may just be bugs that need some quirks at controller level.

> I believe that's what we need here if we want this driver to work
> on both Juno and your platform. Agree ?
>
Does this driver not work for Juno?
If no, may I see your driver and the MHU manual (mine is 90% Japanese)?

>
>>>
>>>>>> +static int mhu_startup(struct mbox_chan *chan)
>>>>>> +{
>>>>>> +       struct mhu_link *mlink = (struct mhu_link *)chan->con_priv;
>>>>>> +       unsigned long flags;
>>>>>> +       u32 val;
>>>>>> +       int ret;
>>>>>> +
>>>>>> +       pr_debug("%s:%d\n", __func__, __LINE__);
>>>>>> +       spin_lock_irqsave(&mlink->lock, flags);
>>>>>> +       val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
>>>>>> +       writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
>>>>>> +       spin_unlock_irqrestore(&mlink->lock, flags);
>>>>>> +
>>>>>> +       ret = request_irq(mlink->irq, mhu_rx_interrupt,
>>>>>> +                         IRQF_SHARED, "mhu_link", chan);
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Just a thought: Can this be threaded_irq instead ?
>>>>> Can move request_irq to probe instead esp. if threaded_irq ?
>>>>> That provides some flexibility to client's rx_callback.
>>>>>
>>>> This is controller driver, and can not know which client want
>>>> rx_callback in hard-irq context and which in thread_fn context.
>>>> Otherwise, request_irq() does evaluate to request_threaded_irq(), if
>>>> thats what you mean.
>>>
>>>
>>> Agreed but on contrary since MHU involves external firmware(running
>>> on different processor) which might have it's own latency, I prefer
>>> threaded over hard irq. And yes request_irq does evaluate to
>>> request_threaded_irq but with thread_fn = NULL which is not what I want.
>>>
>> If remote has its own latency, that does not mean we add some more :)
>>
>
> No what I meant is unless there is a real need to use hard irq, we
> should prefer threaded one otherwise.
>
And how does controller discern a "real need" from a "soft need" to
use hard irq?
Even if the controller driver pushes data up from a threaded function,
the client can't know the context and can't sleep because the
intermediate API says the rx_callback should be assumed to be atomic.
Again, it maybe more efficient if I see your implementation of the
driver and understand your concerns about mine.

> Also by latency I meant what if
> the remote firmware misbehaves. In threaded version you have little
> more flexibility whereas hard irq is executed with interrupts disabled.
> At least the system is responsive and only MHU interrupts are disabled.
>
If the remote firmware misbehaves, that is a bug of the platform. No
mailbox API could/should account for such malfunctions.

Thanks
Jassi

^ permalink raw reply

* [PATCH v2 1/3] ACPI: ARM64 does not have a BIOS add config for BIOS table scan.
From: Luck, Tony @ 2014-07-17 16:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53C7406E.40902@linaro.org>

> Tony, if it is ok with you, I will modify the patch and will not select
> ACPI_LEGACY_TABLES_LOOKUP on IA64, I'm waiting for your final confirmation.

Confirmed.  Thanks Peter for catching this.

-Tony

^ permalink raw reply

* [PATCH 1/8] ARM: Add platform support for Fujitsu MB86S7X SoCs
From: Jassi Brar @ 2014-07-17 16:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <13950816.fBdtyDiPqD@wuerfel>

On 17 July 2014 19:18, Arnd Bergmann <arnd@arndb.de> wrote:
> On Thursday 17 July 2014 19:02:53 Jassi Brar wrote:

>
>> > Losing half the RAM or PCI should not be a problem, you'd just run
>> > with reduced functionality. You wouldn't want to do that in practice,
>> > but it's different from a hard dependency.
>> >
>> Sorry I am not sure what you mean. Is it ok as such?
>
> What I mean is that it should be ok to drop the dependency, but you
> can't add a 'select ARM_LPAE'. The memory should be handled correctly
> already (you will just not see the upper 2GB), while the PCI host
> driver should probably be checked for its error handling so it
> prints a meaningful error message when it can't reach its MMIO space.
>
OK, got it.

>
>> >> >> +static void got_data(u32 code)
>> >> >> +{
>> >> >> +     struct completion *c = NULL;
>> >> >> +     mhu_handler_t hndlr = NULL;
>> >> >> +     unsigned long flags;
>> >> >> +     int ev;
>> >> >> +
>> >> >> +     if (code & RESP_BIT)
>> >> >> +             ev = EV_RR;
>> >> >> +     else
>> >> >> +             ev = EV_RC;
>> >> >> +
>> >> >> +     spin_lock_irqsave(&fsm_lock, flags);
>> >> >> +
>> >> >> +     if (mhu_fsm[fsm_state][ev] == MHU_INVLD) {
>> >> >> +             spin_unlock_irqrestore(&fsm_lock, flags);
>> >> >> +             pr_err("State-%d EV-%d FSM Broken!\n", fsm_state, ev);
>> >> >> +             return;
>> >> >> +     }
>> >> >> +     fsm_state = mhu_fsm[fsm_state][ev];
>> >> >> +
>> >> >> +     if (code & RESP_BIT) {
>> >> >> +             c = ax->c;
>> >> >> +             memcpy_fromio(ax->buf, rsp_from_scb, ax->len);
>> >> >> +             list_move(&ax->node, &free_xfers);
>> >> >> +             ax = NULL;
>> >> >> +     } else {
>> >> >> +             /* Find and dispatch relevant registered handler */
>> >> >> +             if (code < MHU_NUM_CMDS)
>> >> >> +                     hndlr = handler[code];
>> >> >> +             if (!hndlr)
>> >> >> +                     pr_err("No handler for CMD_%u\n", code);
>> >> >> +     }
>> >> >> +
>> >> >> +     spin_unlock_irqrestore(&fsm_lock, flags);
>> >> >> +
>> >> >> +     if (hndlr)
>> >> >> +             hndlr(code, cmd_from_scb);
>> >> >> +     if (c)
>> >> >> +             complete(c);
>> >> >> +}
>> >> >> +
>> >> >> +static void mhu_recv(struct mbox_client *cl, void *data)
>> >> >> +{
>> >> >> +     got_data((u32)data);
>> >> >> +     schedule_work(&scb_work);
>> >> >> +}
>> >> >
>> >> > Why the cast between integer and pointer?
>> >> >
>> >> The common mailbox framework passes around pointers to data packets.
>> >> Its completely between controller and client drivers to decide the
>> >> format of the packet. In my case the packet is a simple u32 value.
>> >
>> > I don't think the mailbox framework should allow that much
>> > flexibility, because that would break portable drivers that
>> > rely on a particular behavior from the mailbox provider.
>> >
>> > I understand that your driver is not portable to another mailbox
>> > provider, but it still seems like a mistake in the API that should
>> > better be fixed sooner than later.
>> >
>> Here is what I remember of many discussions on the point over the last year :)
>> o  We want to support zero-copy receives, which implies the mailbox
>> framework must simply forward the pointer to "data packet" from
>> controller to client driver.
>> o  We could not think of a generic enough structure for 'data packet'
>> that could fit all protocols. So we assume the data packet format is
>> an explicit understanding between the controller(+remote) and the
>> client driver.
>>
>> Or did I miss your point?
>
> Forwarding a pointer is ok, but then I think you should not overload
> the 'void *data' argument. In the case above, you don't actually use
> a pointer at all, but instead you use a 'code' that is taken as
> an index into an array or a flag.
>
> This is particularly broken when you think about 64-bit machines
> on which you cannot cast a pointer to an u32.
>
> What I think you should do is define your own data type for the
> mailbox, which would be specific to your mailbox client and change
> the code above to
>
> struct mhu_mbox_message {
>         u32 code; /* another client could store a pointer here */
> };
>
> static void mhu_recv(struct mbox_client *cl, void *data)
> {
>         struct mhu_mbox_message *msg = data;
>
>         got_data(msg->code);
>         schedule_work(&scp_work);
> }
>
> You get the cost of another register load here, but that should
> be almost free.
>
> There should probably also be some way to ensure that the amount
> of data passed in the structure matches between mbox provider
> and client.
>
Ah ok, I am relieved its only for controller-client, and not for the api :)
Yes I will use mhu_mbox_message as you suggest.

>> >> >> +                     do {
>> >> >> +retry:
>> >> >> +                             /* Wait until we get reply */
>> >> >> +                             count = 0x1000000;
>> >> >> +                             do {
>> >> >> +                                     cpu_relax();
>> >> >> +                                     val = readl_relaxed(
>> >> >> +                                             rx_reg + INTR_STAT_OFS);
>> >> >> +                             } while (--count && !val);
>> >> >> +
>> >> >> +                             if (!val) {
>> >> >> +                                     pr_err("%s:%d SCB didn't reply\n",
>> >> >> +                                            __func__, __LINE__);
>> >> >> +                                     goto retry;
>> >> >
>> >> > It seems like this loop is unbounded and will just print an error every
>> >> > 16M loops but never give up or re-enable interrupts if called with
>> >> > interrupts disabled.
>> >> >
>> >> > It should probably be changed to either enforce being called with interrupts
>> >> > enabled so you can call msleep() inbetween, or you should add error-handling
>> >> > in case the remote side does not reply.
>> >> >
>> >> We can do that for completeness but otherwise my platform is as good
>> >> as dead if the remote doesn't reply for some reason. And there is no
>> >> fool-proof way to recover the state-machine from a failed
>> >> communication.
>> >
>> > Do you know how long it takes normally? If you can prove that the
>> > reply normally comes within a few microseconds, you can instead call
>> > WARN_ON() once after too much time passes, and then continue polling.
>> >
>> > The case to avoid here is just accidentally polling for multiple
>> > milliseconds with interrupts disabled, which would cause a lot of
>> > problems.
>> >
>> From a few hundred micro-sec for CPU reset, to potentially tens of
>> milli-sec for some I2C transaction ... yes we do have for I2C over
>> mailbox! ;)
>>
>> Probably bailing out of the loop and returning -ETIMEOUT to the
>> caller, before a WARN(), is the simplest way to die.
>
> If you can have multiple miliseconds here, I think the code should
> be changed to run in non-atomic context and use msleep(1) or
> usleep_range() as a back-off. Is that possible?
>
I don't think we could sleep there but that should be ok because the
code is used only when we don't have mailbox framework ready i.e, in
very early boot before timers are ready and also as late as during
reboot/poweroff. Also I realize long delays like those for I2C would
never use this code - they would always have mailbox usable during
their lifetime.


>> >> >> +struct mb86s7x_peri_clk {
>> >> >> +     u32 payload_size;
>> >> >> +     u32 cntrlr;
>> >> >> +     u32 domain;
>> >> >> +     u32 port;
>> >> >> +     u32 en;
>> >> >> +     u64 freqency;
>> >> >> +} __packed;
>> >> >
>> >> > Just mark the last member by itself __packed. I assume you didn't
>> >> > actually mean to change the alignment of the data structure to one
>> >> > byte, but just want to say that the last one is misaligned.
>> >> >
>> >> This and others, are data packets that are passed between local and
>> >> remote via SharedMemory. __packed is only meant to specify that these
>> >> data structures have no holes in them.
>> >
>> > That would be '__packed __attribute__((aligned(4)))'. A struct of 'u32'
>> > already has no padding on any architecture that is supported by Linux.
>> > The only reason you need the packing here is because the u64 member is
>> > unaligned. Note that marking the entire structure as packed means that
>> > accesses are no longer atomic because the compiler may prefer to do them
>> > one byte at a time, which can break the protocol on the shared memory
>> > area.
>> >
>> We are not worried about the atomic access because the side sending
>> the data doesn't touch it until the other side indicates it has
>> consumed it.
>
> It's still wrong though ;-)
>
The remote f/w expects data to be contiguous and we can't assume how
it reads the packet. So our firstmost priority is to have no holes in
the region... like, say, USB descriptors.

Thanks for your patience,
-Jassi

^ permalink raw reply

* [PATCH v3 3/5] i2c: exynos5: Remove suspension check
From: Bastian Hecht @ 2014-07-17 16:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405608520-5644-3-git-send-email-hechtb@gmail.com>

2014-07-17 16:48 GMT+02:00 Bastian Hecht <hechtb@gmail.com>:
> We now take care of suspension in the i2c core code. So we can remove this
> check here.
>
> Signed-off-by: Bastian Hecht <hechtb@gmail.com>
> ---
> same as v1
>
>  drivers/i2c/busses/i2c-exynos5.c | 20 +-------------------
>  1 file changed, 1 insertion(+), 19 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
> index 63d2292..a80cf28 100644
> --- a/drivers/i2c/busses/i2c-exynos5.c
> +++ b/drivers/i2c/busses/i2c-exynos5.c
> @@ -145,7 +145,6 @@
>
>  struct exynos5_i2c {
>         struct i2c_adapter      adap;
> -       unsigned int            suspended:1;
>
>         struct i2c_msg          *msg;
>         struct completion       msg_complete;
> @@ -610,11 +609,6 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
>         struct exynos5_i2c *i2c = adap->algo_data;
>         int i = 0, ret = 0, stop = 0;
>
> -       if (i2c->suspended) {
> -               dev_err(i2c->dev, "HS-I2C is not initialized.\n");
> -               return -EIO;
> -       }
> -
>         clk_prepare_enable(i2c->clk);
>
>         for (i = 0; i < num; i++, msgs++) {
> @@ -757,16 +751,6 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
>  }
>
>  #ifdef CONFIG_PM_SLEEP
> -static int exynos5_i2c_suspend_noirq(struct device *dev)
> -{
> -       struct platform_device *pdev = to_platform_device(dev);
> -       struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
> -
> -       i2c->suspended = 1;
> -
> -       return 0;
> -}
> -
>  static int exynos5_i2c_resume_noirq(struct device *dev)
>  {
>         struct platform_device *pdev = to_platform_device(dev);
> @@ -783,14 +767,12 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
>
>         exynos5_i2c_init(i2c);
>         clk_disable_unprepare(i2c->clk);
> -       i2c->suspended = 0;
>
>         return 0;
>  }
>  #endif
>
> -static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq,
> -                        exynos5_i2c_resume_noirq);
> +static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_resume_noirq);

This should be

+static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, NULL,
exynos5_i2c_resume_noirq);

And this is v2, not v3.

>  static struct platform_driver exynos5_i2c_driver = {
>         .probe          = exynos5_i2c_probe,
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v2 5/5] i2c: tegra: Remove suspension check
From: Bastian Hecht @ 2014-07-17 16:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140717145958.GA32534@ulmo>

2014-07-17 16:59 GMT+02:00 Thierry Reding <thierry.reding@gmail.com>:
> On Thu, Jul 17, 2014 at 04:48:40PM +0200, Bastian Hecht wrote:
> [...]
>>  #ifdef CONFIG_PM_SLEEP
>> -static int tegra_i2c_suspend(struct device *dev)
>> -{
>> -     struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
>> -
>> -     i2c_lock_adapter(&i2c_dev->adapter);
>> -     i2c_dev->is_suspended = true;
>> -     i2c_unlock_adapter(&i2c_dev->adapter);
>> -
>> -     return 0;
>> -}
>> -
>>  static int tegra_i2c_resume(struct device *dev)
>>  {
>>       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
>> @@ -842,14 +827,12 @@ static int tegra_i2c_resume(struct device *dev)
>>               return ret;
>>       }
>>
>> -     i2c_dev->is_suspended = false;
>> -
>>       i2c_unlock_adapter(&i2c_dev->adapter);
>>
>>       return 0;
>>  }
>>
>> -static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume);
>> +static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_resume);
>
> Shouldn't this be:
>
>         static SIMPLE_DEV_OPS(tegra_i2c_pm, NULL, tegra_i2c_resume);
>
> instead?

Oh yes thanks. I made the same mistake in [PATCH 3/5] too.

Thanks,

 Bastian



> Thierry

^ permalink raw reply

* [PATCH v7 07/11] arm64: mm: Implement 4 levels of translation tables
From: Catalin Marinas @ 2014-07-17 16:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4A09B481-365B-4BEE-BCC2-FCA24B22CF96@gmail.com>

On Thu, Jul 17, 2014 at 04:04:07PM +0100, Jungseok Lee wrote:
> On Wed, 16 Jul 2014 20:09:48 +0100, Catalin Marinas wrote:
> 
> [ ... ]
> 
> > diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
> > index 69000efa015e..fa324bd5a5c4 100644
> > --- a/arch/arm64/mm/ioremap.c
> > +++ b/arch/arm64/mm/ioremap.c
> > @@ -104,9 +104,12 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
> > EXPORT_SYMBOL(ioremap_cache);
> > 
> > static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
> > -#ifndef CONFIG_ARM64_64K_PAGES
> > +#if CONFIG_ARM64_PGTABLE_LEVELS > 2
> 
> In this patch frame, it causes a compile error since [08/11] patch introduces
> CONFIG_ARM64_PGTABLE_LEVELS. Please ignore my comment if it does not matter.

It matters, thanks.

-- 
Catalin

^ permalink raw reply

* [v3 PATCH 6/6] ARM: dts: omap5: Add prm_resets node
From: Dan Murphy @ 2014-07-17 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615531-15649-1-git-send-email-dmurphy@ti.com>

Add the prm_resets node to the prm parent node.

Add the omap54xx_resets file to define the
omap5 reset lines that are handled by this reset
framework.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v3 - No changes

 arch/arm/boot/dts/omap5.dtsi           |    7 ++++
 arch/arm/boot/dts/omap54xx-resets.dtsi |   66 ++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 arch/arm/boot/dts/omap54xx-resets.dtsi

diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index a4ed549..97bfef5 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -139,6 +139,12 @@
 
 			prm_clockdomains: clockdomains {
 			};
+
+			prm_resets: resets {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#reset-cells = <1>;
+			};
 		};
 
 		cm_core_aon: cm_core_aon at 4a004000 {
@@ -989,3 +995,4 @@
 };
 
 /include/ "omap54xx-clocks.dtsi"
+/include/ "omap54xx-resets.dtsi"
diff --git a/arch/arm/boot/dts/omap54xx-resets.dtsi b/arch/arm/boot/dts/omap54xx-resets.dtsi
new file mode 100644
index 0000000..cba6f52
--- /dev/null
+++ b/arch/arm/boot/dts/omap54xx-resets.dtsi
@@ -0,0 +1,66 @@
+/*
+ * Device Tree Source for OMAP5 reset data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * 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.
+ */
+
+&prm_resets {
+	dsp_rstctrl {
+		reg = <0x1c00>,
+			  <0x1c04>;
+
+		dsp_reset: dsp_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+
+		dsp_mmu_reset: dsp_mmu_reset {
+			control-bit = <0x02>;
+			status-bit = <0x02>;
+		};
+	};
+
+	ipu_rstctrl {
+		reg = <0x910>,
+			  <0x914>;
+
+		ipu_cpu0_reset: ipu_cpu0_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+
+		ipu_cpu1_reset: ipu_cpu1_reset {
+			control-bit = <0x02>;
+			status-bit = <0x02>;
+		};
+
+		ipu_mmu_reset: ipu_mmu_reset {
+			control-bit = <0x04>;
+			status-bit = <0x04>;
+		};
+	};
+
+	iva_rstctrl {
+		reg = <0x1210>,
+			  <0x1214>;
+
+		iva_reset: iva_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	device_rstctrl {
+		reg = <0x1c00>,
+			  <0x1c04>;
+
+		device_reset: device_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+};
-- 
1.7.9.5

^ permalink raw reply related

* [v3 PATCH 5/6] ARM: dts: dra7: Add prm_resets node
From: Dan Murphy @ 2014-07-17 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615531-15649-1-git-send-email-dmurphy@ti.com>

Add the prcm_resets node to the prm parent node.

Add the draxx_resets file to define the
dra7xx reset lines that are handled by this reset
framework.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v3 - No changes

 arch/arm/boot/dts/dra7.dtsi          |    7 +++
 arch/arm/boot/dts/dra7xx-resets.dtsi |   82 ++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+)
 create mode 100644 arch/arm/boot/dts/dra7xx-resets.dtsi

diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 8012763..f3a8819 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -93,6 +93,12 @@
 
 			prm_clockdomains: clockdomains {
 			};
+
+			prm_resets: resets {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#reset-cells = <1>;
+			};
 		};
 
 		cm_core_aon: cm_core_aon at 4a005000 {
@@ -998,3 +1004,4 @@
 };
 
 /include/ "dra7xx-clocks.dtsi"
+/include/ "dra7xx-resets.dtsi"
diff --git a/arch/arm/boot/dts/dra7xx-resets.dtsi b/arch/arm/boot/dts/dra7xx-resets.dtsi
new file mode 100644
index 0000000..4c4966d
--- /dev/null
+++ b/arch/arm/boot/dts/dra7xx-resets.dtsi
@@ -0,0 +1,82 @@
+/*
+ * Device Tree Source for DRA7XX reset data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * 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.
+ */
+
+&prm_resets {
+	dsp_rstctrl {
+		reg = <0x410>,
+			  <0x414>;
+
+		dsp_reset: dsp_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+
+		dsp_mmu_reset: dsp_mmu_reset {
+			control-bit = <0x02>;
+			status-bit = <0x02>;
+		};
+	};
+
+	ipu_rstctrl {
+		reg = <0x510>,
+			  <0x514>;
+
+		ipu_cpu0_reset: ipu_cpu0_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+
+		ipu_cpu1_reset: ipu_cpu1_reset {
+			control-bit = <0x02>;
+			status-bit = <0x02>;
+		};
+
+		ipu_mmu_reset: ipu_mmu_reset {
+			control-bit = <0x04>;
+			status-bit = <0x04>;
+		};
+	};
+
+	iva_rstctrl {
+		reg = <0xf10>,
+			  <0xf14>;
+
+		iva_reset: iva_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	pcie_rstctrl {
+		reg = <0x1310>,
+			  <0x1314>;
+
+		pcie1_reset: pcie1_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+
+		pcie2_reset: pcie2_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	device_rstctrl {
+		reg = <0x1D00>,
+			  <0x1D04>;
+
+		device_reset: device_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+};
-- 
1.7.9.5

^ permalink raw reply related

* [v3 PATCH 4/6] ARM: dts: am4372: Add prcm_resets node
From: Dan Murphy @ 2014-07-17 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615531-15649-1-git-send-email-dmurphy@ti.com>

Add the prcm_resets node to the prcm parent node.

Add the am34xx_resets file to define the
am34xx reset lines that are handled by this reset
framework.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v3 - No changes

 arch/arm/boot/dts/am4372.dtsi        |    7 +++++
 arch/arm/boot/dts/am43xx-resets.dtsi |   52 ++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)
 create mode 100644 arch/arm/boot/dts/am43xx-resets.dtsi

diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index 49fa596..d0aa9c9 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -88,6 +88,12 @@
 
 			prcm_clockdomains: clockdomains {
 			};
+
+			prcm_resets: resets {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#reset-cells = <1>;
+			};
 		};
 
 		scrm: scrm at 44e10000 {
@@ -892,3 +898,4 @@
 };
 
 /include/ "am43xx-clocks.dtsi"
+/include/ "am43xx-resets.dtsi"
diff --git a/arch/arm/boot/dts/am43xx-resets.dtsi b/arch/arm/boot/dts/am43xx-resets.dtsi
new file mode 100644
index 0000000..ef338ba
--- /dev/null
+++ b/arch/arm/boot/dts/am43xx-resets.dtsi
@@ -0,0 +1,52 @@
+/*
+ * Device Tree Source for AM43XX reset data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * 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.
+ */
+
+&prcm_resets {
+	icss_rstctrl {
+		reg = <0x810>,
+			  <0x814>;
+
+		icss_reset: icss_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	gfx_rstctrl {
+		reg = <0x410>,
+			  <0x414>;
+
+		gfx_reset: gfx_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	per_rstctrl {
+		reg = <0x2010>,
+			  <0x2014>;
+
+		iva_reset: iva_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	device_rstctrl {
+		reg = <0x4000>,
+			  <0x4004>;
+
+		device_reset: device_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+};
-- 
1.7.9.5

^ permalink raw reply related

* [v3 PATCH 3/6] ARM: dts: am33xx: Add prcm_resets node
From: Dan Murphy @ 2014-07-17 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615531-15649-1-git-send-email-dmurphy@ti.com>

Add the prcm_resets node to the prcm parent node.

Add the am33xx_resets file to define the
am33xx reset lines that are handled by this reset
framework.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v3 - No changes

 arch/arm/boot/dts/am33xx-resets.dtsi |   42 ++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/am33xx.dtsi        |    7 ++++++
 2 files changed, 49 insertions(+)
 create mode 100644 arch/arm/boot/dts/am33xx-resets.dtsi

diff --git a/arch/arm/boot/dts/am33xx-resets.dtsi b/arch/arm/boot/dts/am33xx-resets.dtsi
new file mode 100644
index 0000000..9260626
--- /dev/null
+++ b/arch/arm/boot/dts/am33xx-resets.dtsi
@@ -0,0 +1,42 @@
+/*
+ * Device Tree Source for AM33XX reset data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * 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.
+ */
+
+&prcm_resets {
+	gfx_rstctrl {
+		reg = <0x1104>,
+			  <0x1114>;
+
+		gfx_reset: gfx_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+	per_rstctrl {
+		reg = <0xD00>,
+			  <0xD0C>;
+
+		iva_reset: iva_reset {
+			control-bit = <0x04>;
+			status-bit = <0x10>;
+		};
+	};
+
+	device_rstctrl {
+		reg = <0xf00>,
+			  <0xf08>;
+
+		device_reset: device_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+
+};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 4a4e02d..5cdc8f0 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -117,6 +117,12 @@
 
 			prcm_clockdomains: clockdomains {
 			};
+
+			prcm_resets: resets {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#reset-cells = <1>;
+			};
 		};
 
 		scrm: scrm at 44e10000 {
@@ -834,3 +840,4 @@
 };
 
 /include/ "am33xx-clocks.dtsi"
+/include/ "am33xx-resets.dtsi"
-- 
1.7.9.5

^ permalink raw reply related

* [v3 PATCH 2/6] dt: TI: Describe the ti reset DT entries
From: Dan Murphy @ 2014-07-17 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615531-15649-1-git-send-email-dmurphy@ti.com>

Describe the TI reset DT entries for TI SoC's.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v3 - Changed Headline no other changes

 .../devicetree/bindings/reset/ti,reset.txt         |  103 ++++++++++++++++++++
 1 file changed, 103 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/ti,reset.txt

diff --git a/Documentation/devicetree/bindings/reset/ti,reset.txt b/Documentation/devicetree/bindings/reset/ti,reset.txt
new file mode 100644
index 0000000..9d5c29c
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/ti,reset.txt
@@ -0,0 +1,103 @@
+Texas Instruments Reset Controller
+======================================
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Specifying the reset entries for the IP module
+==============================================
+Parent module:
+This is the module node that contains the reset registers and bits.
+
+example:
+			prcm_resets: resets {
+				compatible = "ti,dra7-resets";
+				#reset-cells = <1>;
+			};
+
+Required parent properties:
+- compatible : Should be one of,
+		"ti,omap4-prm" for OMAP4 PRM instances
+		"ti,omap5-prm" for OMAP5 PRM instances
+		"ti,dra7-prm" for DRA7xx PRM instances
+		"ti,am4-prcm" for AM43xx PRCM instances
+		"ti,am3-prcm" for AM33xx PRCM instances
+
+Required child reset property:
+- compatible : Should be
+		"resets" for All TI SoCs
+
+example:
+		prm: prm at 4ae06000 {
+			compatible = "ti,omap5-prm";
+			reg = <0x4ae06000 0x3000>;
+
+			prm_resets: resets {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#reset-cells = <1>;
+			};
+		};
+
+
+Reset node declaration
+==============================================
+The reset node is declared in a parent child relationship.  The main parent
+is the PRCM module which contains the base address.  The first child within
+the reset parent declares the target modules reset name.  This is followed by
+the control and status offsets.
+
+Within the first reset child node is a secondary child node which declares the
+reset signal of interest.  Under this node the control and status bits
+are declared.  These bits declare the bit mask for the target reset.
+
+
+Required properties:
+reg - This is the register offset from the PRCM parent.
+	This must be declared as:
+
+	reg = <control register offset>,
+		  <status register offset>;
+
+control-bit - This is the bit within the register which controls the reset
+	of the target module.  This is declared as a bit mask for the register.
+status-bit - This is the bit within the register which contains the status of
+	the reset of the target module.
+	This is declared as a bit mask for the register.
+
+example:
+&prm_resets {
+	dsp_rstctrl {
+		reg = <0x1c00>,
+			  <0x1c04>;
+
+		dsp_reset: dsp_reset {
+			control-bit = <0x01>;
+			status-bit = <0x01>;
+		};
+	};
+};
+
+
+
+Client Node Declaration
+==============================================
+This is the consumer of the parent node to declare what resets this
+particular module is interested in.
+
+example:
+	src: src at 55082000 {
+		    resets = <&reset_src phandle>;
+			reset-names = "<reset_name>";
+	};
+
+Required Properties:
+reset_src - This is the parent DT entry for the reset controller
+phandle - This is the phandle of the specific reset to be used by the clien
+	driver.
+reset-names - This is the reset name of module that the device driver
+	needs to be able to reset.  This value must correspond to a value within
+	the reset controller array.
+
+example:
+resets = <&prm_resets &dsp_mmu_reset>;
+reset-names = "dsp_mmu_reset";
-- 
1.7.9.5

^ permalink raw reply related

* [v3 PATCH 1/6] drivers: reset: TI: SoC reset controller support.
From: Dan Murphy @ 2014-07-17 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

The TI SoC reset controller support utilizes the
reset controller framework to give device drivers or
function drivers a common set of APIs to call to reset
a module.

The reset-ti is a common interface to the reset framework.
 The register data is retrieved during initialization
 of the reset driver through the reset-ti-data
file.  The array of data is associated with the compatible from the
respective DT entry.

Once the data is available then this is derefenced within the common
interface.

The device driver has the ability to assert, deassert or perform a
complete reset.

This code was derived from previous work by Rajendra Nayak and Afzal Mohammed.
The code was changed to adopt to the reset core and abstract away the SoC information.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v3 - Resolved comments from v2.  To many to call out here - https://patchwork.kernel.org/patch/4116941/

 drivers/reset/Kconfig    |    9 ++
 drivers/reset/Makefile   |    1 +
 drivers/reset/reset-ti.c |  373 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 383 insertions(+)
 create mode 100644 drivers/reset/reset-ti.c

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 0615f50..31a5a79 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -12,4 +12,13 @@ menuconfig RESET_CONTROLLER
 
 	  If unsure, say no.
 
+config RESET_TI
+	depends on RESET_CONTROLLER && ARCH_OMAP || COMPILE_TEST
+	bool "TI reset controller"
+	help
+	  Reset controller support for TI SoC's
+
+	  Reset controller found in TI's AM series of SoC's like
+	  AM335x and AM43x and OMAP SoC's like OMAP5 and DRA7
+
 source "drivers/reset/sti/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 60fed3d..a5986b9 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
+obj-$(CONFIG_RESET_TI) += reset-ti.o
 obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-ti.c b/drivers/reset/reset-ti.c
new file mode 100644
index 0000000..e9d4039
--- /dev/null
+++ b/drivers/reset/reset-ti.c
@@ -0,0 +1,373 @@
+/*
+ * reset-ti.c - PRCM reset driver for TI SoC's
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "prcm_reset_ti"
+#define MAX_RESET_SIGNALS 255
+
+/**
+ * struct ti_reset_reg_data - Structure of the reset register information
+ *		for a particular SoC.
+ * @rstctrl_offs: This is the reset control offset value from
+ *		from the parent reset node.
+ * @rstst_offs: This is the reset status offset value from
+ *		from the parent reset node.
+ * @rstctrl_bit: This is the reset control bit for the module.
+ * @rstst_bit: This is the reset status bit for the module.
+ *
+ * Longer description of this structure.
+ */
+struct ti_reset_reg_data {
+	phandle handle;
+	u32	rstctrl_offs;
+	u32	rstst_offs;
+	u32	rstctrl_bit;
+	u32	rstst_bit;
+};
+
+/**
+ * struct ti_reset_data - Structure that contains the reset register data
+ *	as well as the total number of resets for a particular SoC.
+ * @ti_data:	Pointer to this structure to be dereferenced
+ * @reg_data:	Pointer to the register data structure.
+ * @rcdev:		Reset controller device instance
+ * @dev:		Pointer to the devive structure
+ * @ti_reg_data: Array of register data.  Only reset signal with valid
+ *				phandles will be stored in this array.
+ * @reg_base:	Parent register base address
+ * @lock:		Spinlock for accessing the registers
+ * @nr_resets:	Total number of resets for the SoC in the reset array.
+ *
+ * This structure contains a pointer to the register data and the modules
+ * register base.  The number of resets and reset controller device data is
+ * stored within this structure.
+ *
+ */
+struct ti_reset_data {
+	struct ti_reset_data *ti_data;
+	struct ti_reset_reg_data *reg_data;
+	struct reset_controller_dev rcdev;
+	struct device *dev;
+	struct ti_reset_reg_data ti_reg_data[MAX_RESET_SIGNALS];
+	void __iomem *reg_base;
+	spinlock_t lock;
+	int nr_resets;
+};
+
+static int ti_reset_wait_on_reset(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct ti_reset_data *reset_data = container_of(rcdev,
+						     struct ti_reset_data,
+						     rcdev);
+	void __iomem *status_reg = reset_data->reg_base;
+	u32 bit_mask = 0;
+	u32 val = 0;
+	unsigned long flags;
+	int i = 1000;
+	int ret = 0;
+
+	spin_lock_irqsave(&reset_data->lock, flags);
+	/* Clear the reset status bit to reflect the current status */
+	status_reg = reset_data->reg_base + reset_data->ti_reg_data[id].rstst_offs;
+	bit_mask = reset_data->ti_reg_data[id].rstst_bit;
+
+	do {
+		val = readl(status_reg);
+	} while (--i && (val & (1 << bit_mask)));
+
+	if (i == 0 && val & (1 << bit_mask)) {
+		dev_err(reset_data->dev, "%s: Reset failed\n", __func__);
+		ret = -EIO;
+	}
+
+	spin_unlock_irqrestore(&reset_data->lock, flags);
+	return ret;
+}
+
+static int ti_reset_assert(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	struct ti_reset_data *reset_data = container_of(rcdev,
+						     struct ti_reset_data,
+						     rcdev);
+	void __iomem *reg;
+	void __iomem *status_reg;
+	u32 status_bit = 0;
+	u32 bit_mask = 0;
+	u32 val = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&reset_data->lock, flags);
+
+	/* Clear the reset status bit to reflect the current status */
+	status_reg = reset_data->reg_base + reset_data->ti_reg_data[id].rstst_offs;
+	status_bit = reset_data->ti_reg_data[id].rstst_bit;
+	writel(1 << status_bit, status_reg);
+
+	reg = reset_data->reg_base + reset_data->ti_reg_data[id].rstctrl_offs;
+	bit_mask = reset_data->ti_reg_data[id].rstctrl_bit;
+	val = readl(reg);
+	if (!(val & bit_mask)) {
+		val |= bit_mask;
+		writel(val, reg);
+	}
+
+	spin_unlock_irqrestore(&reset_data->lock, flags);
+	return 0;
+}
+
+static int ti_reset_deassert(struct reset_controller_dev *rcdev,
+			     unsigned long id)
+{
+
+	struct ti_reset_data *reset_data = container_of(rcdev,
+						     struct ti_reset_data,
+						     rcdev);
+	void __iomem *reg;
+	void __iomem *status_reg;
+	u32 status_bit = 0;
+	u32 bit_mask = 0;
+	u32 val = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&reset_data->lock, flags);
+
+	/* Clear the reset status bit to reflect the current status */
+	status_reg = reset_data->reg_base + reset_data->ti_reg_data[id].rstst_offs;
+	status_bit = reset_data->ti_reg_data[id].rstst_bit;
+	writel(1 << status_bit, status_reg);
+
+	reg = reset_data->reg_base + reset_data->ti_reg_data[id].rstctrl_offs;
+	bit_mask = reset_data->ti_reg_data[id].rstctrl_bit;
+	val = readl(reg);
+	if (val & bit_mask) {
+		val &= ~bit_mask;
+		writel(val, reg);
+	}
+
+	spin_unlock_irqrestore(&reset_data->lock, flags);
+
+	return 0;
+}
+
+static int ti_reset_reset(struct reset_controller_dev *rcdev,
+			  unsigned long id)
+{
+	ti_reset_assert(rcdev, id);
+	ti_reset_deassert(rcdev, id);
+
+	return ti_reset_wait_on_reset(rcdev, id);
+}
+
+static int ti_reset_xlate(struct reset_controller_dev *rcdev,
+			const struct of_phandle_args *reset_spec)
+{
+
+	struct ti_reset_data *reset_data = container_of(rcdev,
+						     struct ti_reset_data,
+						     rcdev);
+	struct device_node *dev_node;
+	int i;
+
+	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
+		return -EINVAL;
+
+	/* Verify that the phandle exists */
+	dev_node = of_find_node_by_phandle((phandle) reset_spec->args[0]);
+	if (!dev_node) {
+		dev_err(reset_data->dev,
+				"%s: Cannot find phandle node\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i <= reset_data->nr_resets; i++) {
+		if (reset_data->ti_reg_data[i].handle == dev_node->phandle)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static struct reset_control_ops ti_reset_ops = {
+	.reset = ti_reset_reset,
+	.assert = ti_reset_assert,
+	.deassert = ti_reset_deassert,
+};
+
+static int ti_reset_populate_child(struct ti_reset_data *reset_data,
+					struct device_node *reset_child,
+					u32 ctrl_offs, u32 status_offs)
+{
+	struct device_node *next_reset_child = NULL;
+	int i = reset_data->nr_resets;
+	int ret;
+	u32 ctrl_bit;
+
+	while ((next_reset_child = of_get_next_child(reset_child, next_reset_child))) {
+		if (next_reset_child->phandle) {
+			/* Get the bits of each sub-reset */
+			ret = of_property_read_u32(next_reset_child, "control-bit",
+						&ctrl_bit);
+				if (ret < 0) {
+					dev_err(reset_data->dev,
+						"%s: No entry in %s for rstctrl_offs\n",
+						__func__, next_reset_child->name);
+
+				return -ENODEV;
+			}
+
+			ret = of_property_read_u32(next_reset_child, "status-bit",
+						&reset_data->ti_reg_data[i].rstst_bit);
+				if (ret < 0) {
+					dev_err(reset_data->dev,
+							"%s: No entry in %s for rstst_offs\n",
+							__func__, next_reset_child->name);
+
+				return -ENODEV;
+			}
+
+			reset_data->ti_reg_data[i].rstctrl_offs = ctrl_offs;
+			reset_data->ti_reg_data[i].rstst_offs = status_offs;
+			reset_data->ti_reg_data[i].handle = next_reset_child->phandle;
+			i++;
+		}
+	};
+
+	reset_data->nr_resets = i;
+
+	return 0;
+}
+
+static int ti_reset_get_of_data(struct ti_reset_data *reset_data,
+				struct device_node *dev_node)
+{
+	struct device_node *reset_child = NULL;
+	int ret = -EINVAL;
+	u32 ctrl_offs, status_offs;
+
+	/* Loop through all the children and populate a lookup array */
+	while ((reset_child = of_get_next_child(dev_node, reset_child))) {
+		ret = of_property_read_u32_index(reset_child, "reg", 0,
+						 &ctrl_offs);
+		if (ret)
+			return ret;
+
+		ret = of_property_read_u32_index(reset_child, "reg", 1,
+						 &status_offs);
+		if (ret)
+			return ret;
+
+		ret = ti_reset_populate_child(reset_data, reset_child,
+							ctrl_offs, status_offs);
+		if (ret)
+			return ret;
+	};
+
+	return 0;
+}
+
+static int ti_reset_probe(struct platform_device *pdev)
+{
+	struct device_node *resets;
+	struct ti_reset_data *reset_data;
+	struct resource *res;
+	int ret;
+
+	reset_data = devm_kzalloc(&pdev->dev, sizeof(*reset_data), GFP_KERNEL);
+	if (!reset_data)
+		return -ENOMEM;
+
+	resets = of_find_node_by_name(NULL, "resets");
+	if (!resets) {
+		dev_err(&pdev->dev, "%s: missing 'resets' child node.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reset_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(reset_data->reg_base)) {
+		dev_err(&pdev->dev, "%s: Cannot map reset parent.\n", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_init(&reset_data->lock);
+	reset_data->dev = &pdev->dev;
+	ret = ti_reset_get_of_data(reset_data, resets);
+	if (ret)
+		return -EINVAL;
+
+	reset_data->rcdev.owner = THIS_MODULE;
+	reset_data->rcdev.of_node = resets;
+	reset_data->rcdev.ops = &ti_reset_ops;
+
+	reset_data->rcdev.of_reset_n_cells = 1;
+	reset_data->rcdev.of_xlate = &ti_reset_xlate;
+
+	reset_data->ti_data = reset_data;
+
+	platform_set_drvdata(pdev, reset_data);
+
+	reset_controller_register(&reset_data->rcdev);
+
+	return 0;
+}
+
+static int ti_reset_remove(struct platform_device *pdev)
+{
+	struct ti_reset_data *reset_data;
+
+	reset_data = platform_get_drvdata(pdev);
+	reset_controller_unregister(&reset_data->rcdev);
+
+	return 0;
+}
+
+static const struct of_device_id ti_reset_of_match[] = {
+	{ .compatible = "ti,omap5-prm" },
+	{ .compatible =	"ti,omap4-prm" },
+	{ .compatible =	"ti,omap5-prm" },
+	{ .compatible =	"ti,dra7-prm" },
+	{ .compatible = "ti,am4-prcm" },
+	{ .compatible =	"ti,am3-prcm" },
+	{},
+};
+
+static struct platform_driver ti_reset_driver = {
+	.probe	= ti_reset_probe,
+	.remove	= ti_reset_remove,
+	.driver	= {
+		.name		= DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= of_match_ptr(ti_reset_of_match),
+	},
+};
+module_platform_driver(ti_reset_driver);
+
+MODULE_DESCRIPTION("PRCM reset driver for TI SoCs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v3 7/7] ARM: dts: exynos4: Add nodes for L2 cache controller
From: Tomasz Figa @ 2014-07-17 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

This patch adds device tree nodes for L2 cache controller present on
Exynos4 SoCs.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 arch/arm/boot/dts/exynos4210.dtsi |  9 +++++++++
 arch/arm/boot/dts/exynos4x12.dtsi | 14 ++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index ee3001f..99970ab 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -54,6 +54,15 @@
 		reg = <0x10023CA0 0x20>;
 	};
 
+	l2c: l2-cache-controller at 10502000 {
+		compatible = "arm,pl310-cache";
+		reg = <0x10502000 0x1000>;
+		cache-unified;
+		cache-level = <2>;
+		arm,tag-latency = <2 2 1>;
+		arm,data-latency = <2 2 1>;
+	};
+
 	gic: interrupt-controller at 10490000 {
 		cpu-offset = <0x8000>;
 	};
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index c5a943d..ddffefe 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -60,6 +60,20 @@
 		reg = <0x10023CA0 0x20>;
 	};
 
+	l2c: l2-cache-controller at 10502000 {
+		compatible = "arm,pl310-cache";
+		reg = <0x10502000 0x1000>;
+		cache-unified;
+		cache-level = <2>;
+		arm,tag-latency = <2 2 1>;
+		arm,data-latency = <3 2 1>;
+		arm,double-linefill = <1>;
+		arm,double-linefill-incr = <0>;
+		arm,double-linefill-wrap = <1>;
+		arm,prefetch-drop = <1>;
+		arm,prefetch-offset = <7>;
+	};
+
 	clock: clock-controller at 10030000 {
 		compatible = "samsung,exynos4412-clock";
 		reg = <0x10030000 0x20000>;
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 6/7] ARM: EXYNOS: Add support for non-secure L2X0 resume
From: Tomasz Figa @ 2014-07-17 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

On Exynos SoCs it is necessary to resume operation of L2C early in
assembly code, because otherwise certain systems will crash. This patch
adds necessary code to non-secure resume handler.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 arch/arm/mach-exynos/common.h   |  1 +
 arch/arm/mach-exynos/firmware.c |  2 ++
 arch/arm/mach-exynos/sleep.S    | 41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index a3f3061..2540827 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -113,6 +113,7 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK)
 
 extern u32 cp15_save_diag;
 extern u32 cp15_save_power;
+extern unsigned long l2x0_regs_phys;
 
 extern void __iomem *sysram_ns_base_addr;
 extern void __iomem *sysram_base_addr;
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index 554b350..09131d3 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -103,6 +103,8 @@ static int exynos_suspend(void)
 	writel(virt_to_phys(exynos_cpu_resume_ns),
 		sysram_ns_base_addr + EXYNOS_BOOT_ADDR);
 
+	l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
+
 	return cpu_suspend(0, exynos_cpu_suspend);
 }
 
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S
index e3c3730..b8ce8f0 100644
--- a/arch/arm/mach-exynos/sleep.S
+++ b/arch/arm/mach-exynos/sleep.S
@@ -16,6 +16,8 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
 #include "smc.h"
 
 #define CPU_MASK	0xff0ffff0
@@ -74,6 +76,40 @@ ENTRY(exynos_cpu_resume_ns)
 	mov	r0, #SMC_CMD_C15RESUME
 	dsb
 	smc	#0
+#ifdef CONFIG_CACHE_L2X0
+	adr	r0, l2x0_regs_phys
+	ldr	r0, [r0]
+	cmp	r0, #0
+	beq	skip_l2x0
+
+	ldr	r1, [r0, #L2X0_R_PHY_BASE]
+	ldr	r2, [r1, #L2X0_CTRL]
+	tst	r2, #0x1
+	bne	skip_l2x0
+
+	ldr	r1, [r0, #L2X0_R_TAG_LATENCY]
+	ldr	r2, [r0, #L2X0_R_DATA_LATENCY]
+	ldr	r3, [r0, #L2X0_R_PREFETCH_CTRL]
+	mov	r0, #SMC_CMD_L2X0SETUP1
+	smc	#0
+
+	/* Reload saved regs pointer because smc corrupts registers. */
+	adr	r0, l2x0_regs_phys
+	ldr	r0, [r0]
+
+	ldr	r1, [r0, #L2X0_R_PWR_CTRL]
+	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
+	mov	r0, #SMC_CMD_L2X0SETUP2
+	smc	#0
+
+	mov	r0, #SMC_CMD_L2X0INVALL
+	smc	#0
+
+	mov	r1, #1
+	mov	r0, #SMC_CMD_L2X0CTRL
+	smc	#0
+skip_l2x0:
+#endif /* CONFIG_CACHE_L2X0 */
 skip_cp15:
 	b	cpu_resume
 ENDPROC(exynos_cpu_resume_ns)
@@ -83,3 +119,8 @@ cp15_save_diag:
 	.globl cp15_save_power
 cp15_save_power:
 	.long	0	@ cp15 power control
+#ifdef CONFIG_CACHE_L2X0
+	.globl l2x0_regs_phys
+l2x0_regs_phys:
+	.long	0	@ phys address of l2x0 save struct
+#endif /* CONFIG_CACHE_L2X0 */
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 5/7] ARM: EXYNOS: Add .write_sec outer cache callback for L2C-310
From: Tomasz Figa @ 2014-07-17 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

Exynos4 SoCs equipped with an L2C-310 cache controller and running under
secure firmware require certain registers of aforementioned IP to be
accessed only from secure mode. This means that SMC calls are required
for certain register writes. To handle this, an implementation of
.write_sec and .configure callbacks is provided by this patch.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 arch/arm/mach-exynos/firmware.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index f5e626d..554b350 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -17,6 +17,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cputype.h>
 #include <asm/firmware.h>
+#include <asm/hardware/cache-l2x0.h>
 #include <asm/suspend.h>
 
 #include <mach/map.h>
@@ -120,6 +121,31 @@ static const struct firmware_ops exynos_firmware_ops = {
 	.resume			= exynos_resume,
 };
 
+static void exynos_l2_write_sec(unsigned long val, unsigned reg)
+{
+	switch (reg) {
+	case L2X0_CTRL:
+		if (val & L2X0_CTRL_EN)
+			exynos_smc(SMC_CMD_L2X0INVALL, 0, 0, 0);
+		exynos_smc(SMC_CMD_L2X0CTRL, val, 0, 0);
+		break;
+
+	case L2X0_DEBUG_CTRL:
+		exynos_smc(SMC_CMD_L2X0DEBUG, val, 0, 0);
+		break;
+
+	default:
+		WARN_ONCE(1, "%s: ignoring write to reg 0x%x\n", __func__, reg);
+	}
+}
+
+static void exynos_l2_configure(const struct l2x0_regs *regs)
+{
+	exynos_smc(SMC_CMD_L2X0SETUP1, regs->tag_latency, regs->data_latency,
+			regs->prefetch_ctrl);
+	exynos_smc(SMC_CMD_L2X0SETUP2, regs->pwr_ctrl, regs->aux_ctrl, 0);
+}
+
 void __init exynos_firmware_init(void)
 {
 	struct device_node *nd;
@@ -139,4 +165,16 @@ void __init exynos_firmware_init(void)
 	pr_info("Running under secure firmware.\n");
 
 	register_firmware_ops(&exynos_firmware_ops);
+
+	/*
+	 * Exynos 4 SoCs (based on Cortex A9 and equipped with L2C-310),
+	 * running under secure firmware, require certain registers of L2
+	 * cache controller to be written in secure mode. Here .write_sec
+	 * callback is provided to perform necessary SMC calls.
+	 */
+	if (IS_ENABLED(CONFIG_CACHE_L2X0)
+	    && read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
+		outer_cache.write_sec = exynos_l2_write_sec;
+		outer_cache.configure = exynos_l2_configure;
+	}
 }
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 4/7] ARM: l2c: Add support for overriding prefetch settings
From: Tomasz Figa @ 2014-07-17 16:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

Firmware on certain boards (e.g. ODROID-U3) can leave incorrect L2C prefetch
settings configured in registers leading to crashes if L2C is enabled
without overriding them. This patch introduces bindings to enable
prefetch settings to be specified from DT and necessary support in the
driver.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 Documentation/devicetree/bindings/arm/l2cc.txt | 10 +++++++
 arch/arm/mm/cache-l2x0.c                       | 39 ++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index af527ee..3443d2d 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -47,6 +47,16 @@ Optional properties:
 - cache-id-part: cache id part number to be used if it is not present
   on hardware
 - wt-override: If present then L2 is forced to Write through mode
+- arm,double-linefill : Override double linefill enable setting. Enable if
+  non-zero, disable if zero.
+- arm,double-linefill-incr : Override double linefill on INCR read. Enable
+  if non-zero, disable if zero.
+- arm,double-linefill-wrap : Override double linefill on WRAP read. Enable
+  if non-zero, disable if zero.
+- arm,prefetch-drop : Override prefetch drop enable setting. Enable if non-zero,
+  disable if zero.
+- arm,prefetch-offset : Override prefetch offset value. Valid values are
+  0-7, 15, 23, and 31.
 
 Example:
 
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 21a625a0..6274803 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1055,6 +1055,8 @@ static void __init l2c310_of_parse(const struct device_node *np,
 	u32 data[3] = { 0, 0, 0 };
 	u32 tag[3] = { 0, 0, 0 };
 	u32 filter[2] = { 0, 0 };
+	u32 prefetch;
+	u32 val;
 
 	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
 	if (tag[0] && tag[1] && tag[2])
@@ -1079,6 +1081,43 @@ static void __init l2c310_of_parse(const struct device_node *np,
 		l2x0_saved_regs.filter_start = (filter[0] & ~(SZ_1M - 1))
 					| L310_ADDR_FILTER_EN;
 	}
+
+	prefetch = l2x0_saved_regs.prefetch_ctrl;
+
+	if (!of_property_read_u32(np, "arm,double-linefill", &val)) {
+		if (val)
+			prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL;
+		else
+			prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL;
+	}
+
+	if (!of_property_read_u32(np, "arm,double-linefill-incr", &val)) {
+		if (val)
+			prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_INCR;
+		else
+			prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_INCR;
+	}
+
+	if (!of_property_read_u32(np, "arm,double-linefill-wrap", &val)) {
+		if (!val)
+			prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP;
+		else
+			prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP;
+	}
+
+	if (!of_property_read_u32(np, "arm,prefetch-drop", &val)) {
+		if (val)
+			prefetch |= L310_PREFETCH_CTRL_PREFETCH_DROP;
+		else
+			prefetch &= ~L310_PREFETCH_CTRL_PREFETCH_DROP;
+	}
+
+	if (!of_property_read_u32(np, "arm,prefetch-offset", &val)) {
+		prefetch &= ~L310_PREFETCH_CTRL_OFFSET_MASK;
+		prefetch |= val & L310_PREFETCH_CTRL_OFFSET_MASK;
+	}
+
+	l2x0_saved_regs.prefetch_ctrl = prefetch;
 }
 
 static const struct l2c_init_data of_l2c310_data __initconst = {
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 3/7] ARM: l2c: Get outer cache .write_sec callback from mach_desc only if not NULL
From: Tomasz Figa @ 2014-07-17 16:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

Certain platforms (i.e. Exynos) might need to set .write_sec callback
from firmware initialization which is happenning in .init_early callback
of machine descriptor. However current code will overwrite the pointer
with whatever is present in machine descriptor, even though it can be
already set earlier. This patch fixes this by making the assignment
conditional, depending on whether current .write_sec callback is NULL.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 arch/arm/kernel/irq.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 2c42576..e7383b9 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -125,7 +125,8 @@ void __init init_IRQ(void)
 
 	if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) &&
 	    (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) {
-		outer_cache.write_sec = machine_desc->l2c_write_sec;
+		if (!outer_cache.write_sec)
+			outer_cache.write_sec = machine_desc->l2c_write_sec;
 		ret = l2x0_of_init(machine_desc->l2c_aux_val,
 				   machine_desc->l2c_aux_mask);
 		if (ret)
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 2/7] ARM: l2c: Add interface to ask hypervisor to configure L2C
From: Tomasz Figa @ 2014-07-17 16:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

Because certain secure hypervisor do not allow writes to individual L2C
registers, but rather expect set of parameters to be passed as argument
to secure monitor calls, there is a need to provide an interface for the
L2C driver to ask the firmware to configure the hardware according to
specified parameters. This patch adds such.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 arch/arm/include/asm/outercache.h | 3 +++
 arch/arm/mm/cache-l2x0.c          | 5 +++++
 2 files changed, 8 insertions(+)

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 891a56b..563b92f 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -23,6 +23,8 @@
 
 #include <linux/types.h>
 
+struct l2x0_regs;
+
 struct outer_cache_fns {
 	void (*inv_range)(unsigned long, unsigned long);
 	void (*clean_range)(unsigned long, unsigned long);
@@ -36,6 +38,7 @@ struct outer_cache_fns {
 
 	/* This is an ARM L2C thing */
 	void (*write_sec)(unsigned long, unsigned);
+	void (*configure)(const struct l2x0_regs *);
 };
 
 extern struct outer_cache_fns outer_cache;
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 385c047..21a625a0 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -109,6 +109,11 @@ static inline void l2c_unlock(void __iomem *base, unsigned num)
 
 static void l2c_configure(void __iomem *base)
 {
+	if (outer_cache.configure) {
+		outer_cache.configure(&l2x0_saved_regs);
+		return;
+	}
+
 	if (l2x0_data->configure)
 		l2x0_data->configure(base);
 
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 1/7] ARM: l2c: Refactor the driver to use commit-like interface
From: Tomasz Figa @ 2014-07-17 16:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405615142-21426-1-git-send-email-t.figa@samsung.com>

Certain implementations of secure hypervisors (namely the one found on
Samsung Exynos-based boards) do not provide access to individual L2C
registers. This makes the .write_sec()-based interface insufficient and
provoking ugly hacks.

This patch is first step to make the driver not rely on availability of
writes to individual registers. This is achieved by refactoring the
driver to use a commit-like operation scheme: all register values are
prepared first and stored in an instance of l2x0_regs struct and then a
single callback is responsible to flush those values to the hardware.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
 arch/arm/mm/cache-l2x0.c | 201 ++++++++++++++++++++++++++---------------------
 1 file changed, 110 insertions(+), 91 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 5f2c988..385c047 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -40,12 +40,14 @@ struct l2c_init_data {
 	void (*enable)(void __iomem *, u32, unsigned);
 	void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
 	void (*save)(void __iomem *);
+	void (*configure)(void __iomem *);
 	struct outer_cache_fns outer_cache;
 };
 
 #define CACHE_LINE_SIZE		32
 
 static void __iomem *l2x0_base;
+static const struct l2c_init_data *l2x0_data;
 static DEFINE_RAW_SPINLOCK(l2x0_lock);
 static u32 l2x0_way_mask;	/* Bitmask of active ways */
 static u32 l2x0_size;
@@ -105,6 +107,14 @@ static inline void l2c_unlock(void __iomem *base, unsigned num)
 	}
 }
 
+static void l2c_configure(void __iomem *base)
+{
+	if (l2x0_data->configure)
+		l2x0_data->configure(base);
+
+	l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
+}
+
 /*
  * Enable the L2 cache controller.  This function must only be
  * called when the cache controller is known to be disabled.
@@ -113,7 +123,12 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
 {
 	unsigned long flags;
 
-	l2c_write_sec(aux, base, L2X0_AUX_CTRL);
+	/* Do not touch the controller if already enabled. */
+	if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)
+		return;
+
+	l2x0_saved_regs.aux_ctrl = aux;
+	l2c_configure(base);
 
 	l2c_unlock(base, num_lock);
 
@@ -207,6 +222,12 @@ static void l2c_save(void __iomem *base)
 	l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 }
 
+static void l2c_resume(void)
+{
+	l2x0_data->enable(l2x0_base, l2x0_saved_regs.aux_ctrl,
+				l2x0_data->num_lock);
+}
+
 /*
  * L2C-210 specific code.
  *
@@ -287,14 +308,6 @@ static void l2c210_sync(void)
 	__l2c210_cache_sync(l2x0_base);
 }
 
-static void l2c210_resume(void)
-{
-	void __iomem *base = l2x0_base;
-
-	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
-		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1);
-}
-
 static const struct l2c_init_data l2c210_data __initconst = {
 	.type = "L2C-210",
 	.way_size_0 = SZ_8K,
@@ -308,7 +321,7 @@ static const struct l2c_init_data l2c210_data __initconst = {
 		.flush_all = l2c210_flush_all,
 		.disable = l2c_disable,
 		.sync = l2c210_sync,
-		.resume = l2c210_resume,
+		.resume = l2c_resume,
 	},
 };
 
@@ -465,7 +478,7 @@ static const struct l2c_init_data l2c220_data = {
 		.flush_all = l2c220_flush_all,
 		.disable = l2c_disable,
 		.sync = l2c220_sync,
-		.resume = l2c210_resume,
+		.resume = l2c_resume,
 	},
 };
 
@@ -614,39 +627,29 @@ static void __init l2c310_save(void __iomem *base)
 							L310_POWER_CTRL);
 }
 
-static void l2c310_resume(void)
+static void l2c310_configure(void __iomem *base)
 {
-	void __iomem *base = l2x0_base;
+	unsigned revision;
 
-	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		unsigned revision;
-
-		/* restore pl310 setup */
-		writel_relaxed(l2x0_saved_regs.tag_latency,
-			       base + L310_TAG_LATENCY_CTRL);
-		writel_relaxed(l2x0_saved_regs.data_latency,
-			       base + L310_DATA_LATENCY_CTRL);
-		writel_relaxed(l2x0_saved_regs.filter_end,
-			       base + L310_ADDR_FILTER_END);
-		writel_relaxed(l2x0_saved_regs.filter_start,
-			       base + L310_ADDR_FILTER_START);
-
-		revision = readl_relaxed(base + L2X0_CACHE_ID) &
-				L2X0_CACHE_ID_RTL_MASK;
-
-		if (revision >= L310_CACHE_ID_RTL_R2P0)
-			l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base,
-				      L310_PREFETCH_CTRL);
-		if (revision >= L310_CACHE_ID_RTL_R3P0)
-			l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base,
-				      L310_POWER_CTRL);
-
-		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
-
-		/* Re-enable full-line-of-zeros for Cortex-A9 */
-		if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO)
-			set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
-	}
+	/* restore pl310 setup */
+	writel_relaxed(l2x0_saved_regs.tag_latency,
+		       base + L310_TAG_LATENCY_CTRL);
+	writel_relaxed(l2x0_saved_regs.data_latency,
+		       base + L310_DATA_LATENCY_CTRL);
+	writel_relaxed(l2x0_saved_regs.filter_end,
+		       base + L310_ADDR_FILTER_END);
+	writel_relaxed(l2x0_saved_regs.filter_start,
+		       base + L310_ADDR_FILTER_START);
+
+	revision = readl_relaxed(base + L2X0_CACHE_ID) &
+				 L2X0_CACHE_ID_RTL_MASK;
+
+	if (revision >= L310_CACHE_ID_RTL_R2P0)
+		l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base,
+			      L310_PREFETCH_CTRL);
+	if (revision >= L310_CACHE_ID_RTL_R3P0)
+		l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base,
+			      L310_POWER_CTRL);
 }
 
 static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data)
@@ -698,6 +701,23 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
 		aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP);
 	}
 
+	/* r3p0 or later has power control register */
+	if (rev >= L310_CACHE_ID_RTL_R3P0)
+		l2x0_saved_regs.pwr_ctrl = L310_DYNAMIC_CLK_GATING_EN |
+						L310_STNDBY_MODE_EN;
+
+	/*
+	 * Always enable non-secure access to the lockdown registers -
+	 * we write to them as part of the L2C enable sequence so they
+	 * need to be accessible.
+	 */
+	aux |= L310_AUX_CTRL_NS_LOCKDOWN;
+
+	l2c_enable(base, aux, num_lock);
+
+	/* Read back resulting AUX_CTRL value as it could have been altered. */
+	aux = readl_relaxed(base + L2X0_AUX_CTRL);
+
 	if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) {
 		u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL);
 
@@ -711,23 +731,12 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
 	if (rev >= L310_CACHE_ID_RTL_R3P0) {
 		u32 power_ctrl;
 
-		l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN,
-			      base, L310_POWER_CTRL);
 		power_ctrl = readl_relaxed(base + L310_POWER_CTRL);
 		pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n",
 			power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis",
 			power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis");
 	}
 
-	/*
-	 * Always enable non-secure access to the lockdown registers -
-	 * we write to them as part of the L2C enable sequence so they
-	 * need to be accessible.
-	 */
-	aux |= L310_AUX_CTRL_NS_LOCKDOWN;
-
-	l2c_enable(base, aux, num_lock);
-
 	if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) {
 		set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
 		cpu_notifier(l2c310_cpu_enable_flz, 0);
@@ -759,11 +768,11 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 
 	if (revision >= L310_CACHE_ID_RTL_R3P0 &&
 	    revision < L310_CACHE_ID_RTL_R3P2) {
-		u32 val = readl_relaxed(base + L310_PREFETCH_CTRL);
+		u32 val = l2x0_saved_regs.prefetch_ctrl;
 		/* I don't think bit23 is required here... but iMX6 does so */
 		if (val & (BIT(30) | BIT(23))) {
 			val &= ~(BIT(30) | BIT(23));
-			l2c_write_sec(val, base, L310_PREFETCH_CTRL);
+			l2x0_saved_regs.prefetch_ctrl = val;
 			errata[n++] = "752271";
 		}
 	}
@@ -799,6 +808,15 @@ static void l2c310_disable(void)
 	l2c_disable();
 }
 
+static void l2c310_resume(void)
+{
+	l2c_resume();
+
+	/* Re-enable full-line-of-zeros for Cortex-A9 */
+	if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO)
+		set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
+}
+
 static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.type = "L2C-310",
 	.way_size_0 = SZ_8K,
@@ -806,6 +824,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.enable = l2c310_enable,
 	.fixup = l2c310_fixup,
 	.save = l2c310_save,
+	.configure = l2c310_configure,
 	.outer_cache = {
 		.inv_range = l2c210_inv_range,
 		.clean_range = l2c210_clean_range,
@@ -825,6 +844,12 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	u32 aux, old_aux;
 
 	/*
+	 * Save the pointer globally so that callbacks which do not receive
+	 * context from callers can access the structure.
+	 */
+	l2x0_data = data;
+
+	/*
 	 * Sanity check the aux values.  aux_mask is the bits we preserve
 	 * from reading the hardware register, and aux_val is the bits we
 	 * set.
@@ -935,6 +960,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		break;
 	}
 
+	/* Read back current (default) hardware configuration */
+	if (data->save)
+		data->save(l2x0_base);
+
 	__l2c_init(data, aux_val, aux_mask, cache_id);
 }
 
@@ -993,7 +1022,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
 		.flush_all   = l2c210_flush_all,
 		.disable     = l2c_disable,
 		.sync        = l2c210_sync,
-		.resume      = l2c210_resume,
+		.resume      = l2c_resume,
 	},
 };
 
@@ -1011,7 +1040,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = {
 		.flush_all   = l2c220_flush_all,
 		.disable     = l2c_disable,
 		.sync        = l2c220_sync,
-		.resume      = l2c210_resume,
+		.resume      = l2c_resume,
 	},
 };
 
@@ -1024,28 +1053,26 @@ static void __init l2c310_of_parse(const struct device_node *np,
 
 	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
 	if (tag[0] && tag[1] && tag[2])
-		writel_relaxed(
+		l2x0_saved_regs.tag_latency =
 			L310_LATENCY_CTRL_RD(tag[0] - 1) |
 			L310_LATENCY_CTRL_WR(tag[1] - 1) |
-			L310_LATENCY_CTRL_SETUP(tag[2] - 1),
-			l2x0_base + L310_TAG_LATENCY_CTRL);
+			L310_LATENCY_CTRL_SETUP(tag[2] - 1);
 
 	of_property_read_u32_array(np, "arm,data-latency",
 				   data, ARRAY_SIZE(data));
 	if (data[0] && data[1] && data[2])
-		writel_relaxed(
+		l2x0_saved_regs.data_latency =
 			L310_LATENCY_CTRL_RD(data[0] - 1) |
 			L310_LATENCY_CTRL_WR(data[1] - 1) |
-			L310_LATENCY_CTRL_SETUP(data[2] - 1),
-			l2x0_base + L310_DATA_LATENCY_CTRL);
+			L310_LATENCY_CTRL_SETUP(data[2] - 1);
 
 	of_property_read_u32_array(np, "arm,filter-ranges",
 				   filter, ARRAY_SIZE(filter));
 	if (filter[1]) {
-		writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
-			       l2x0_base + L310_ADDR_FILTER_END);
-		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN,
-			       l2x0_base + L310_ADDR_FILTER_START);
+		l2x0_saved_regs.filter_end =
+					ALIGN(filter[0] + filter[1], SZ_1M);
+		l2x0_saved_regs.filter_start = (filter[0] & ~(SZ_1M - 1))
+					| L310_ADDR_FILTER_EN;
 	}
 }
 
@@ -1057,6 +1084,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = {
 	.enable = l2c310_enable,
 	.fixup = l2c310_fixup,
 	.save  = l2c310_save,
+	.configure = l2c310_configure,
 	.outer_cache = {
 		.inv_range   = l2c210_inv_range,
 		.clean_range = l2c210_clean_range,
@@ -1085,6 +1113,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = {
 	.enable = l2c310_enable,
 	.fixup = l2c310_fixup,
 	.save  = l2c310_save,
+	.configure = l2c310_configure,
 	.outer_cache = {
 		.inv_range   = l2c210_inv_range,
 		.clean_range = l2c210_clean_range,
@@ -1199,16 +1228,6 @@ static void aurora_save(void __iomem *base)
 	l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL);
 }
 
-static void aurora_resume(void)
-{
-	void __iomem *base = l2x0_base;
-
-	if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL);
-		writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL);
-	}
-}
-
 /*
  * For Aurora cache in no outer mode, enable via the CP15 coprocessor
  * broadcasting of cache commands to L2.
@@ -1270,7 +1289,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
 		.sync        = l2x0_cache_sync,
-		.resume      = aurora_resume,
+		.resume      = l2c_resume,
 	},
 };
 
@@ -1283,7 +1302,7 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
 	.fixup = aurora_fixup,
 	.save  = aurora_save,
 	.outer_cache = {
-		.resume      = aurora_resume,
+		.resume      = l2c_resume,
 	},
 };
 
@@ -1431,6 +1450,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.of_parse = l2c310_of_parse,
 	.enable = l2c310_enable,
 	.save  = l2c310_save,
+	.configure = l2c310_configure,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
 		.clean_range = bcm_clean_range,
@@ -1452,18 +1472,12 @@ static void __init tauros3_save(void __iomem *base)
 		readl_relaxed(base + L310_PREFETCH_CTRL);
 }
 
-static void tauros3_resume(void)
+static void tauros3_configure(void __iomem *base)
 {
-	void __iomem *base = l2x0_base;
-
-	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		writel_relaxed(l2x0_saved_regs.aux2_ctrl,
-			       base + TAUROS3_AUX2_CTRL);
-		writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-			       base + L310_PREFETCH_CTRL);
-
-		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
-	}
+	writel_relaxed(l2x0_saved_regs.aux2_ctrl,
+		       base + TAUROS3_AUX2_CTRL);
+	writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
+		       base + L310_PREFETCH_CTRL);
 }
 
 static const struct l2c_init_data of_tauros3_data __initconst = {
@@ -1472,9 +1486,10 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.save  = tauros3_save,
+	.configure = tauros3_configure,
 	/* Tauros3 broadcasts L1 cache operations to L2 */
 	.outer_cache = {
-		.resume      = tauros3_resume,
+		.resume      = l2c_resume,
 	},
 };
 
@@ -1530,6 +1545,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	if (!of_property_read_bool(np, "cache-unified"))
 		pr_err("L2C: device tree omits to specify unified cache\n");
 
+	/* Read back current (default) hardware configuration */
+	if (data->save)
+		data->save(l2x0_base);
+
 	/* L2 configuration can only be changed if the cache is disabled */
 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
 		if (data->of_parse)
-- 
1.9.3

^ permalink raw reply related

* [PATCH v3 0/7] Enable L2 cache support on Exynos4210/4x12 SoCs
From: Tomasz Figa @ 2014-07-17 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

This series intends to add support for L2 cache on Exynos4 SoCs on boards
running under secure firmware, which requires certain initialization steps
to be done with help of firmware, as selected registers are writable only
from secure mode.

First four patches extend existing support for secure write in L2C driver
to account for design of secure firmware running on Exynos. Namely:
 1) direct read access to certain registers is needed on Exynos, because
    secure firmware calls set several registers at once,
 2) not all boards are running secure firmware, so .write_sec callback
    needs to be installed in Exynos firmware ops initialization code,
 3) write access to {DATA,TAG}_LATENCY_CTRL registers fron non-secure world
    is not allowed and so must use l2c_write_sec as well,
 4) on certain boards, default value of prefetch register is incorrect
    and must be overridden at L2C initialization.
For boards running with firmware that provides access to individual
L2C registers this series should introduce no functional changes. However
since the driver is widely used on other platforms I'd like to kindly ask
any interested people for testing.

Further two patches add impelmentation of .write_sec for Exynos secure
firmware and necessary DT nodes to enable L2 cache.

Tested on Exynos4210-based Universal C210 and Trats (both without secure
firmware) and Exynos4412-based TRATS2 and ODROID-U3 boards (both with secure
firmware).

Depends on:
 - [PATCH] ARM: make it easier to check the CPU part number correctly
   (http://thread.gmane.org/gmane.linux.ports.arm.kernel/335126
    already in linux-next)
 - [PATCH v2 0/2] Firmware-assisted suspend/resume of Exynos SoCs
   (https://lkml.org/lkml/2014/7/17/431)

Changes since v2:
(https://lkml.org/lkml/2014/6/25/416)
 - refactored L2C driver to use commit-like interface and make it no longer
   depend on availability of writes to individual registers,
 - moved L2C resume to assembly code, because doing it later makes some
   systems unstable - this is also needed for deeper cpuidle modes,
 - dropped unnecessary patch hacking around the .write_sec interface,
 - dropped patch making the driver use l2c_write_sec() for LATENCY_CTRL
   registers as Exynos is no longer affected and I'm not aware of any
   reports that this is also needed on other platforms (can be applied
   separately if it turns out to be so),
 - rebased onto next-20140717 tag of linux-next tree.

Changes since v1:
(https://www.mail-archive.com/linux-omap at vger.kernel.org/msg106323.html)
 - rebased onto for-next branch of linux-samsung tree,
 - changed argument order of outer_cache.write_sec() callback to match
   l2c_write_sec() function in cache-l2x0.c,
 - added support of overriding of prefetch settings to work around incorrect
   default settings on certain Exynos4x12-based boards,
 - added call to firmware to invalidate whole L2 cache before setting enable
   bit in L2C control register (required by Exynos secure firmware).

Tomasz Figa (7):
  ARM: l2c: Refactor the driver to use commit-like interface
  ARM: l2c: Add interface to ask hypervisor to configure L2C
  ARM: l2c: Get outer cache .write_sec callback from mach_desc only if
    not NULL
  ARM: l2c: Add support for overriding prefetch settings
  ARM: EXYNOS: Add .write_sec outer cache callback for L2C-310
  ARM: EXYNOS: Add support for non-secure L2X0 resume
  ARM: dts: exynos4: Add nodes for L2 cache controller

 Documentation/devicetree/bindings/arm/l2cc.txt |  10 +
 arch/arm/boot/dts/exynos4210.dtsi              |   9 +
 arch/arm/boot/dts/exynos4x12.dtsi              |  14 ++
 arch/arm/include/asm/outercache.h              |   3 +
 arch/arm/kernel/irq.c                          |   3 +-
 arch/arm/mach-exynos/common.h                  |   1 +
 arch/arm/mach-exynos/firmware.c                |  40 ++++
 arch/arm/mach-exynos/sleep.S                   |  41 +++++
 arch/arm/mm/cache-l2x0.c                       | 245 ++++++++++++++++---------
 9 files changed, 274 insertions(+), 92 deletions(-)

-- 
1.9.3

^ permalink raw reply

* [PATCH] arm64: audit: Fix build for audit changes
From: Richard Guy Briggs @ 2014-07-17 16:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405596402-23844-1-git-send-email-broonie@kernel.org>

On 14/07/17, Mark Brown wrote:
> From: Mark Brown <broonie@linaro.org>
> 
> Commit 3efe33f5d2 (audit: x86: drop arch from __audit_syscall_entry()
> interface) removed the arch parameter from __audit_syscall_entry() and
> updated the only current user in mainline but this breaks the ARMv8 audit
> code that has been added in -next. Fix this by making the equivalent
> update to ARMv8.
> 
> Signed-off-by: Mark Brown <broonie@linaro.org>

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>

I'm not sure the best way to propagate this patch, but it will be
necessary.

> ---
>  arch/arm64/kernel/ptrace.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 70526cfda056..310842e3d477 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -1115,8 +1115,8 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
>  	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>  		trace_sys_enter(regs, regs->syscallno);
>  
> -	audit_syscall_entry(syscall_get_arch(), regs->syscallno,
> -		regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]);
> +	audit_syscall_entry(regs->syscallno, regs->orig_x0, regs->regs[1],
> +			    regs->regs[2], regs->regs[3]);
>  
>  	return regs->syscallno;
>  }
> -- 
> 2.0.1
> 

- RGB

--
Richard Guy Briggs <rbriggs@redhat.com>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545

^ permalink raw reply

* [RFC 1/4] ARM: tegra: Move SoC drivers to drivers/soc/tegra
From: Olof Johansson @ 2014-07-17 16:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140717093149.GB3180@arm.com>

On Thu, Jul 17, 2014 at 2:31 AM, Catalin Marinas
<catalin.marinas@arm.com> wrote:
> On Wed, Jul 16, 2014 at 08:31:00PM +0100, Olof Johansson wrote:
>> [ Gee, I had completely missed this thread because nobody bothered to
>> cc me. Seems to be standard procedure on 64-bit these days. :( ]
>
> Just to clarify this point, as per prior agreement I'm expecting the
> arm-soc guys to help reviewing/merging arm64-soc as well, even though
> there are no arch/arm64/{mach,plat}-* directories. That means that
> arm-soc folks should also be cc'ed on such patches.
>
> However, the "ARM SUB-ARCHITECTURES" MAINTAINERS entry does not mention
> arm at kernel.org (neither Olof nor Arnd). Was this not meant as an arm-soc
> email alias?

Yes, however we've been reluctant to add it because we don't want
people to post patches directly to us, we mostly expect maintainers to
send pull request and/or direct patches there.

We can do it and add annotation to not send patches directly there.
I'll post a patch for that update.


-Olof

^ permalink raw reply

* [PATCH 03/14] ARM: sunxi: sun5i: Enforce max frequency on PLL6
From: Emilio López @ 2014-07-17 16:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405588134-2396-4-git-send-email-maxime.ripard@free-electrons.com>

Hi Maxime,

El 17/07/14 06:08, Maxime Ripard escribi?:
> PLL6 out of reset is running at 2.4GHz, which is outside of its operating
> boundaries.
>
> Enforce its maximum frequency as set in the datasheet to make sure we stays
> within these bounds.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>   arch/arm/boot/dts/sun5i-a13.dtsi | 1 +
>   1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
> index bf86e65dd167..de89edc5e5b3 100644
> --- a/arch/arm/boot/dts/sun5i-a13.dtsi
> +++ b/arch/arm/boot/dts/sun5i-a13.dtsi
> @@ -97,6 +97,7 @@
>   			reg = <0x01c20028 0x4>;
>   			clocks = <&osc24M>;
>   			clock-output-names = "pll6_sata", "pll6_other", "pll6";
> +			clock-max-frequency = <1200000000>;
>   		};
>
>   		/* dummy is 200M */
>

This patch itself is ok, but I'm not seeing so far where is 
"clock-max-frequency" read from the DT and passed to the clock for later 
verification. Did you leave that out by mistake when shuffling patches?

Cheers!

Emilio

^ permalink raw reply

* [PATCH 4/5] tty: serial: 8250 core: add runtime pm
From: Felipe Balbi @ 2014-07-17 16:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53C7F4A3.5080508@linutronix.de>

Hi,

On Thu, Jul 17, 2014 at 06:06:59PM +0200, Sebastian Andrzej Siewior wrote:
> On 07/17/2014 06:02 PM, Felipe Balbi wrote:
> >> diff --git a/drivers/tty/serial/8250/8250_core.c
> >> b/drivers/tty/serial/8250/8250_core.c index 2e4a93b..480a1c0
> >> 100644 --- a/drivers/tty/serial/8250/8250_core.c +++
> >> b/drivers/tty/serial/8250/8250_core.c @@ -1283,6 +1283,9 @@
> >> static inline void __stop_tx(struct uart_8250_port *p) if (p->ier
> >> & UART_IER_THRI) { p->ier &= ~UART_IER_THRI; serial_out(p,
> >> UART_IER, p->ier); + +		pm_runtime_mark_last_busy(p->port.dev); +
> >> pm_runtime_put_autosuspend(p->port.dev); } }
> >> 
> >> @@ -1310,12 +1313,12 @@ static void serial8250_start_tx(struct
> >> uart_port *port) struct uart_8250_port *up = container_of(port,
> >> struct uart_8250_port, port);
> >> 
> >> -	pm_runtime_get_sync(port->dev); if (up->dma &&
> >> !serial8250_tx_dma(up)) { goto out; } else if (!(up->ier &
> >> UART_IER_THRI)) { up->ier |= UART_IER_THRI; +
> >> pm_runtime_get_sync(port->dev); serial_port_out(port, UART_IER,
> >> up->ier);
> >> 
> >> if (up->bugs & UART_BUG_TXEN) { unsigned char lsr;
> > 
> > this looks better. So we get on start_tx() and put on stop_tx().
> > 
> >> @@ -1500,9 +1503,10 @@ void serial8250_tx_chars(struct
> >> uart_8250_port *up) uart_write_wakeup(port);
> >> 
> >> DEBUG_INTR("THRE..."); - +#if 0 if (uart_circ_empty(xmit)) 
> >> __stop_tx(up); +#endif } EXPORT_SYMBOL_GPL(serial8250_tx_chars);
> > 
> > is it so that start_tx() gets called one and stop_tx() might be
> > called N times ? That looks unbalanced to me. If the calls are
> > balanced, then you shouldn't need to care because pm_runtime will
> > handle reference counting for you, right?
> 
> No, this is okay. If you look, it checks for "up->ier &
> UART_IER_THRI". On the second invocation it will see that this bit is
> already set and therefore won't call get_sync() for the second time.
> That bit is removed in the _stop_tx() path.

oh, right. But that's actually unnecessary. Calling pm_runtime_get()
multiple times will just increment the usage counter multiple times,
which means you can call __stop_tx() multiple times too and everything
gets balanced, right ?

> >> and now I need to come up with something that is not if (port !=
> >> omap) for that #if 0 block. The code disables the TX FIFO empty
> >> interrupt once the transfer is complete. I want to call
> >> __stop_tx() once the tx fifo is empty. Felipe, Would a check for
> >> dev->power.use_autosuspend be the right thing to do?
> > 
> > probably not, as that's internal to the pm_runtime code. But I
> > wonder if start/stop tx calls are balanced, if they are then we're
> > good. Unless I'm missing something else.
> 
> Do you have other ideas? It doesn't look like this is exported at all.
> If we call _stop_tx() right away, then we have 64 bytes in the TX fifo
> in the worst case. They should be gone "soon" but the HW-flow control
> may delay it (in theory for a long time)).

this can be problematic, specially for OMAP which can go into OFF while
idle. Whatever is in the FIFO would get lost. It seems like omap-serial
solved this within transmit_chars().

See how transmit_chars() is called from within IRQ handler with clocks
enabled then it conditionally calls serial_omap_stop_tx() which will
pm_runtime_get_sync() -> do_the_harlem_shake() ->
pm_runtime_put_autosuspend(). That leaves one unbalanced
pm_runtime_get() which is balanced when we're exitting the IRQ handler.

This seems work fine and dandy without DMA, but for DMA work, I think we
need to make sure this IP stays powered until we get DMA completion
callback. But that's future, I guess.

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140717/ca4927f5/attachment-0001.sig>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox