* [PATCH v5 02/16] dt/bindings: Update binding for PM domain idle states
From: Brendan Jackman @ 2016-09-21 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160920161748.GB46914@linaro.org>
On Tue, Sep 20 2016 at 17:17, Lina Iyer <lina.iyer@linaro.org> wrote:
> On Mon, Sep 19 2016 at 09:09 -0600, Brendan Jackman wrote:
>>
>>On Fri, Sep 16 2016 at 18:39, Sudeep Holla <sudeep.holla@arm.com> wrote:
>>> Hi Kevin,
>>>
>>> Thanks for looking at this and simplifying various discussions we had so
>>> far. I was thinking of summarizing something very similar. I couldn't
>>> due to lack of time.
>>>
>>> On 16/09/16 18:13, Kevin Hilman wrote:
>>>
>>> [...]
>>>
>>>> I think we're having some terminology issues...
>>>>
>>>> FWIW, the kernel terminolgy is actually "PM domain", not power domain.
>>>> This was intentional because the goal of the PM domain was to group
>>>> devices that some PM features. To be very specific to the kernel, they
>>>> us the same set of PM callbacks. Today, this is most commonly used to
>>>> model power domains, where a group of devices share a power rail, but it
>>>> does not need to be limited to that.
>>>>
>>>
>>> Agreed/Understood.
>>>
>>>> That being said, I'm having a hard time understanding the root of the
>>>> disagreement.
>>>>
>>>
>>> Yes. I tried to convey the same earlier, but have failed. The only
>>> disagreement is about a small part of this DT bindings. We would like to
>>> make it completely hierarchical up to CPU nodes. More comments on that
>>> below.
>>>
>>>> It seems that you and Sudeep would like to use domain-idle-states to
>>>> replace/superceed cpu-idle-states with the primary goal (and benefit)
>>>> being that it simplifies the DT bindings. Is that correct?
>>>>
>>>
>>> Correct, we want to deprecate cpu-idle-states with the introduction of
>>> this hierarchical PM bindings. Yes IMO, it simplifies things and avoids
>>> any ABI break we might trigger if we miss to consider some use-case now.
>>>
>>>> The objections have come in because that means that implies that CPUs
>>>> become their own domains, which may not be the case in hardware in the
>>>> sense that they share a power rail.
>>>>
>>>
>>> Agreed.
>>>
>>>> However, IMO, thinking of a CPU as it's own "PM domain" may make some
>>>> sense based on the terminology above.
>>>>
>>>
>>> Thanks for that, we do understand that it may not be 100% correct when
>>> we strictly considers hardware terminologies instead of above ones.
>>> As along as we see no issues with the above terminologies it should be fine.
>>>
>>>> I think the other objection may be that using a genpd to model domain
>>>> with only a single device in it may be overkill, and I agree with that.
>>>
>>> I too agree with that. Just because we represent that in DT in that way
>>> doesn't mean we need to create a genpd to model domain. We can always
>>> skip that if not required. That's pure implementation specifics and I
>>> have tried to convey the same in my previous emails. I must say you have
>>> summarized it very clearly in this email. Thanks again for that.
>>>
>>>> But, I'm not sure if making CPUs use domain-idle-states implies that
>>>> they necessarily have to use genpd is what you are proposing. Maybe
>>>> someone could clarify that?
>>>>
>>>
>>> No, I have not proposing anything around implementation in the whole
>>> discussion so far. I have constrained myself just to DT bindings so far.
>>> That's the main reason why I was opposed to mentions of OS vs platform
>>> co-ordinated modes of CPU suspend in this discussion. IMO that's
>>> completely out of scope of this DT binding we are defining here.
>>>
> Fair. But understand the PM Domain bindings do not impose any
> requirements of hierarchy. Domain idle states are defined by the
> property domain-idle-states in the domain node. How the DT bindings are
> organized is immaterial to the PM Domain core.
>
> It is a different exercise all together to look at CPU PSCI modes and
> have a unified way of representing them in DT. The current set of
> patches does not dictate where the domain idle states be located (pardon
> my example in the patch, which was not updated to reflect that). That
> said, I do require that domains that are controlled by the PSCI f/w be
> defined under the 'psci' node in DT, which is fair. All the domain needs
> are phandles to the idle state definitions; how the nodes are arranged
> in DT is not of consequence to the driver.
>
> In my mind providing a structure to CPU PM domains that can be used for
> both OSI and PC is a separate effort.
Do you mean a structure in the kernel or in DT? If the former, I agree,
if the latter I strongly disagree. I think DT bindings should be totally
unaware of PSCI suspend modes.
> It may also club what Brendan
> mentions below as part of the effort. The hierarchy that is presented in
> [1] is inherent in the PM domain hierarchy and idle states don't have to
> duplicate that information.
>
>>> Hope that helps/clarifies the misunderstanding/disagreement.
>>
>>Indeed. My intention was that the proposal would result in the exact
>>same kernel behaviour as Lina's current patchset, i.e. there is one
>>genpd per cluster, and CPU-level idle states are still handled by
>>cpuidle.
>>
>>The only change from the current patchset would be in initialisation
>>code: some coordination would need to be done to determine which idle
>>states go into cpuidle and which go into the genpds (whereas with the
>>current bindings, states from cpu-idle-states go into cpuidle and states
>>from domain-idle-states go into genpd). So you could say that this would
>>be a trade-off between binding simplicity and implementation simplicity.
>>
> I would not oppose the idea of virtual domains around CPUs (I admit I am
> not comfortable with the idea though), if that is the right thing to do.
> But the scope of that work is extensive and should not be clubbed as
> part of this proposal. It is an extensive code rework spanning cpuidle
> drivers and PSCI and there are hooks in this code to help you achieve
> that.
If we want to take the per-CPU domains approach, we _have_ to do it as
part of this proposal; it's a different set of semantics for the
cpu-idle-states/domain-idle-states properties. It would mean
cpu-idle-states is _superseded_ by domain idle states - implementing one
solution (where cpu-idle-states and domain idle states are both taken
into consideration by the implementation) then later switching to the
alternative (where cpu-idle-states is ignored when a CPU PM domain tree
is present) wouldn't make sense from a backward-compatibility
perspective.
You're right that implementing the alternative proposal in the Linux
kernel would mean quite a big rework. But, idealistically speaking,
Linux-specific implementation realities shouldn't be a factor in Device
Tree binding designs, right?
If people think that using both cpu-idle-states and domain-idle-states
is the pragmatic choice (or object fundamentally to the idea of devices
with idle states as being in their own PM domain) then that's fine IMO,
but it's a one-time decision and I think we should be clear about why
we're making it.
Cheers,
Brendan
^ permalink raw reply
* [PATCH 3/4] ARM: tegra: nyan-big: Include compatible revisions for proper detection
From: Paul Kocialkowski @ 2016-09-21 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5461eb20-9372-7fa1-0e48-3d0143393b8c@nvidia.com>
Resending with the right CC chain.
Le mercredi 21 septembre 2016 ? 10:15 +0100, Jon Hunter a ?crit?:
>
> On 21/09/16 08:43, Paul Kocialkowski wrote:
>
> ...
>
> > > > > > > > Depthcharge (the payload used with cros devices) will attempt to
> > > > > > > > detect
> > > > > > > > boards using their revision. This includes all the known
> > > > > > > > revisions
> > > > > > > > for
> > > > > > > > the nyan-big board so that the dtb can be selected preferably.
> > > > > > >
> > > > > > > May be I am missing something here, but for the mainline there is
> > > > > > > only
> > > > > > > one dtb available and so why is this needed for the mainline?
> > > > > >
> > > > > > There is indeed a single dts in mainline, but depthcharge will use
> > > > > > the
> > > > > > revision
> > > > > > to match the compatible string (e.g. it will look for google,nyan-
> > > > > > big-
> > > > > > rev5,
> > > > > > not
> > > > > > google,nyan-big), so we need to list them all in that single dts.
> > > > > > Otherwise,
> > > > > > depthcharge will fall back to the default config, which may or may
> > > > > > not
> > > > > > be
> > > > > > suitable for nyan.
> > > > >
> > > > > Is tegra124-nyan-big.dtb not the default?
> > > >
> > > > You can't expect that to always be the case. The image format allows
> > > > many
> > > > different dts to be provided, so I could easily build with
> > > > multi_v7_defconfig
> > > > and have various dts for various devices in the same image, and just
> > > > select
> > > > a
> > > > random one as default.
> > >
> > > Really? Sounds odd. I was hoping that tegra124-nyan-big.dtb would be a
> > > catch all.
>
> I meant I was hoping that compatible = "google,nyan-big" would be the
> catchall not the dtb file name ;-)
Yeah, I figured :)
>
> >
> > Yes, the image format (FIT) allows specifying multiple dtb and zImage
> > combinations in the same image[0].
>
> Yes I am aware of that. Typically, I have been testing using a FIT image
> with single zImage and dtb. Hence no problems.
>
> So are you wanting to create a FIT image to support multiple boards and
> use the single FIT image for all? If so then I can see why you want
> this. Again please describe the motivation for the changes in the
> changelog so it is clear why we are adding this.
Fair enough, will do in v2.
--
Paul Kocialkowski, developer of low-level free software for embedded devices
Website: https://www.paulk.fr/
Coding blog: https://code.paulk.fr/
Git repositories: https://git.paulk.fr/ https://git.code.paulk.fr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160921/3e5c3e2d/attachment.sig>
^ permalink raw reply
* [PATCH 1/4] ARM: tegra: nyan: Use proper IRQ type definitions
From: Paul Kocialkowski @ 2016-09-21 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <eb7540c0-4abd-86c0-7777-78fe1f12bc59@nvidia.com>
Resending with the right CC chain.
Le mercredi 21 septembre 2016 ? 10:06 +0100, Jon Hunter a ?crit?:
> On 21/09/16 09:26, Paul Kocialkowski wrote:
> >
> >
> > * PGP Signed by an unknown key
> >
> > Le mercredi 21 septembre 2016 ? 08:52 +0100, Jon Hunter a ?crit :
> > >
> > >
> > > On 20/09/16 19:14, Paul Kocialkowski wrote:
> > > >
> > > >
> > > >
> > > > >
> > > > >
> > > > > Old Signed by an unknown key
> > > >
> > > > Le mardi 20 septembre 2016 ? 18:15 +0100, Jon Hunter a ?crit :
> > > > >
> > > > >
> > > > >
> > > > > On 28/08/16 18:32, Paul Kocialkowski wrote:
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > > This switches a few interrupt definitions that were using
> > > > > > GPIO_ACTIVE_HIGH as IRQ type, which is invalid.
> > > > >
> > > > > May be you are right, but this does not describe why this is invalid.
> > > > > Can you elaborate?
> > > >
> > > > GPIO_ACTIVE_HIGH is simply not the right kind of define to use in the
> > > > "interrupts" devicetree property. Values provided there are understood
> > > > as
> > > > IRQ_TYPE_ defines.
> > >
> > > Right, but you are changing the type as GPIO_ACTIVE_HIGH = 0 and
> > > IRQ_TYPE_EDGE_FALLING = 2 and there is no comment about why this has
> > > been changed. It might be correct, but you need to explain it.
> >
> > This actually makes the IRQ trigger values consistent with the drivers, that
> > define them regardless of devicetree anyway. The max98090 driver
> > has IRQF_TRIGGER_FALLING and bq24735 has IRQF_TRIGGER_RISING |
> > IRQF_TRIGGER_FALLING.
> >
> > This is really more of a cosmetic change, it doesn't impact actual use.
>
> So you are saying that the drivers don't actually use the DT types?
It appears so. At least they are hardcoded in the kernel driver.
>
> ?May be that is ok, and yes this is cosmetic, but this should be stated in
> the changelog as it is not clear what is going on here.
Fair enough, will do in v2.
--
Paul Kocialkowski, developer of low-level free software for embedded devices
Website: https://www.paulk.fr/
Coding blog: https://code.paulk.fr/
Git repositories: https://git.paulk.fr/ https://git.code.paulk.fr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160921/c34cbaae/attachment-0001.sig>
^ permalink raw reply
* [PATCH V3 1/4] ARM64 LPC: Indirect ISA port IO introduced
From: zhichang @ 2016-09-21 9:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5264074.nuyDhEuOR4@wuerfel>
Hi, Arnd,
On 2016?09?14? 22:23, Arnd Bergmann wrote:
> On Wednesday, September 14, 2016 10:16:28 PM CEST zhichang.yuan wrote:
>>>
>>> No need to guard includes with an #ifdef.
>> If remove #ifdef here, extio.h should not contain any function external declarations whose definitions are in
>> extio.c compiled only when CONFIG_ARM64_INDIRECT_PIO is yes.
>
> There is no problem with making declarations visible for functions that
> are not part of the kernel, we do that all the time.
>
>>>> +#define BUILDS_RW(bwl, type) \
>>>> +static inline void reads##bwl(const volatile void __iomem *addr, \
>>>> + void *buffer, unsigned int count) \
>>>> +{ \
>>>> + if (count) { \
>>>> + type *buf = buffer; \
>>>> + \
>>>> + do { \
>>>> + type x = __raw_read##bwl(addr); \
>>>> + *buf++ = x; \
>>>> + } while (--count); \
>>>> + } \
>>>> +} \
>>>> + \
>>>> +static inline void writes##bwl(volatile void __iomem *addr, \
>>>> + const void *buffer, unsigned int count) \
>>>> +{ \
>>>> + if (count) { \
>>>> + const type *buf = buffer; \
>>>> + \
>>>> + do { \
>>>> + __raw_write##bwl(*buf++, addr); \
>>>> + } while (--count); \
>>>> + } \
>>>> +}
>>>> +
>>>> +BUILDS_RW(b, u8)
>>>
>>> Why is this in here?
>> the readsb/writesb are defined in asm-generic/io.h which is included later, but the redefined insb/outsb need
>> to call them. Without these readsb/writesb definition before insb/outsb redefined, compile error occur.
>>
>> It seems that copy all the definitions of "asm-generic/io.h" is not a good idea, so I move the definitions of
>> those function needed here....
>>
>> Ok. I think your idea below defining in(s)/out(s) in a c file can solve this issue.
>>
>> #ifdef CONFIG_ARM64_INDIRECT_PIO
>> #define inb inb
>> extern u8 inb(unsigned long addr);
>>
>> #define outb outb
>> extern void outb(u8 value, unsigned long addr);
>>
>> #define insb insb
>> extern void insb(unsigned long addr, void *buffer, unsigned int count);
>>
>> #define outsb outsb
>> extern void outsb(unsigned long addr, const void *buffer, unsigned int count);
>> #endif
>>
>> and definitions of all these functions are in extio.c :
>>
>> u8 inb(unsigned long addr)
>> {
>> if (!arm64_extio_ops || arm64_extio_ops->start > addr ||
>> arm64_extio_ops->end < addr)
>> return readb(PCI_IOBASE + addr);
>> else
>> return arm64_extio_ops->pfin ?
>> arm64_extio_ops->pfin(arm64_extio_ops->devpara,
>> addr + arm64_extio_ops->ptoffset, NULL,
>> sizeof(u8), 1) : -1;
>> }
>> .....
>
> Yes, sounds good.
>
>>>> @@ -149,6 +185,60 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
>>>> #define IO_SPACE_LIMIT (PCI_IO_SIZE - 1)
>>>> #define PCI_IOBASE ((void __iomem *)PCI_IO_START)
>>>>
>>>> +
>>>> +/*
>>>> + * redefine the in(s)b/out(s)b for indirect-IO.
>>>> + */
>>>> +#define inb inb
>>>> +static inline u8 inb(unsigned long addr)
>>>> +{
>>>> +#ifdef CONFIG_ARM64_INDIRECT_PIO
>>>> + if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
>>>> + addr <= arm64_extio_ops->end)
>>>> + return extio_inb(addr);
>>>> +#endif
>>>> + return readb(PCI_IOBASE + addr);
>>>> +}
>>>> +
>>>
>>> Looks ok, but you only seem to do this for the 8-bit
>>> accessors, when it should be done for 16-bit and 32-bit
>>> ones as well for consistency.
>> Hip06 LPC only support 8-bit I/O operations on the designated port.
>
> That is an interesting limitation. Maybe still call the extio operations
> and have them do WARN_ON_ONCE() instead?
>
> If you get a driver that calls inw/outw on the range that is owned
> by the LPC bus, you otherwise get an unhandled page fault in kernel
> space, which is not as nice.
As for this issue, I provided a wrong reply in the last email.
After double-checking with SoC guys, the inw(l)/outw(l) are OK with multiple 8-bit transfers to consecutive
I/O addresses.
Sorry for the wrong information!
Will support inw(l)/outw(l) in V4.
Best,
Zhichang
>
>>>> diff --git a/drivers/bus/extio.c b/drivers/bus/extio.c
>>>> new file mode 100644
>>>> index 0000000..1e7a9c5
>>>> --- /dev/null
>>>> +++ b/drivers/bus/extio.c
>>>> @@ -0,0 +1,66 @@
>>>
>>> This is in a globally visible directory
>>>
>>>> +
>>>> +struct extio_ops *arm64_extio_ops;
>>>
>>> But the identifier uses an architecture specific prefix. Either
>>> move the whole file into arch/arm64, or make the naming so that
>>> it can be used for everything.
>>
>> I perfer to move the whole file into arch/arm64, extio.h will be moved to arch/arm64/include/asm;
>
> Ok, that simplifies it a lot, you can just do everything in asm/io.h then.
>
> Arnd
>
^ permalink raw reply
* [PATCH 3/4] ARM: tegra: nyan-big: Include compatible revisions for proper detection
From: Jon Hunter @ 2016-09-21 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474443809.1239.4.camel@paulk.fr>
On 21/09/16 08:43, Paul Kocialkowski wrote:
...
>>>>>>> Depthcharge (the payload used with cros devices) will attempt to
>>>>>>> detect
>>>>>>> boards using their revision. This includes all the known revisions
>>>>>>> for
>>>>>>> the nyan-big board so that the dtb can be selected preferably.
>>>>>>
>>>>>> May be I am missing something here, but for the mainline there is only
>>>>>> one dtb available and so why is this needed for the mainline?
>>>>>
>>>>> There is indeed a single dts in mainline, but depthcharge will use the
>>>>> revision
>>>>> to match the compatible string (e.g. it will look for google,nyan-big-
>>>>> rev5,
>>>>> not
>>>>> google,nyan-big), so we need to list them all in that single dts.
>>>>> Otherwise,
>>>>> depthcharge will fall back to the default config, which may or may not
>>>>> be
>>>>> suitable for nyan.
>>>>
>>>> Is tegra124-nyan-big.dtb not the default?
>>>
>>> You can't expect that to always be the case. The image format allows many
>>> different dts to be provided, so I could easily build with
>>> multi_v7_defconfig
>>> and have various dts for various devices in the same image, and just select
>>> a
>>> random one as default.
>>
>> Really? Sounds odd. I was hoping that tegra124-nyan-big.dtb would be a
>> catch all.
I meant I was hoping that compatible = "google,nyan-big" would be the
catchall not the dtb file name ;-)
> Yes, the image format (FIT) allows specifying multiple dtb and zImage
> combinations in the same image[0].
Yes I am aware of that. Typically, I have been testing using a FIT image
with single zImage and dtb. Hence no problems.
So are you wanting to create a FIT image to support multiple boards and
use the single FIT image for all? If so then I can see why you want
this. Again please describe the motivation for the changes in the
changelog so it is clear why we are adding this.
Cheers
Jon
--
nvpublic
^ permalink raw reply
* ftrace function_graph causes system crash
From: Jisheng Zhang @ 2016-09-21 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0e38f79fdc1f4671943da74764c15050@SIWEX5A.sing.micron.com>
Hi Bean,
On Wed, 21 Sep 2016 07:50:58 +0000 "Bean Huo (beanhuo)" wrote:
> > From: linux-arm-kernel [mailto:linux-arm-kernel-bounces at lists.infradead.org]
> > On Behalf Of Steven Rostedt
> > Sent: Dienstag, 20. September 2016 16:07
> > To: Bean Huo (beanhuo) <beanhuo@micron.com>
> > Cc: Zoltan Szubbocsev (zszubbocsev) <zszubbocsev@micron.com>;
> > catalin.marinas at arm.com; will.deacon at arm.com; rfi at lists.rocketboards.org;
> > linux-kernel at vger.kernel.org; mingo at redhat.com; linux-arm-
> > kernel at lists.infradead.org
> > Subject: Re: ftrace function_graph causes system crash
> >
> > On Tue, 20 Sep 2016 13:10:39 +0000
> > "Bean Huo (beanhuo)" <beanhuo@micron.com> wrote:
> >
> > > Hi, all
> > > I just use ftrace to do some latency study, found that function_graph
> > > can not Work, as long as enable it, will cause kernel panic. I searched this
> > online.
> > > Found that there are also some cause the same as mine. I am a newer of
> > ftrace.
> > > I want to know who know what root cause? Here is some partial log:
> > >
> > >
> >
> > Can you do a function bisect to find what function this is.
> >
> > This script is used to help find functions that are being traced by function tracer
> > or function graph tracing that causes the machine to reboot, hang, or crash.
> > Here's the steps to take.
> >
> > First, determine if function graph is working with a single function:
> >
> > # cd /sys/kernel/debug/tracing
> > # echo schedule > set_ftrace_filter
> > # echo function_graph > current_tracer
> >
> > If this works, then we know that something is being traced that shouldn't be.
> >
> > # echo nop > current_tracer
> >
> > # cat available_filter_functions > ~/full-file # ftrace-bisect ~/full-file ~/test-file
> > ~/non-test-file # cat ~/test-file > set_ftrace_filter
> >
> > *** Note *** this will take several minutes. Setting multiple functions is an
> > O(n^2) operation, and we are dealing with thousands of functions.
> > So go have coffee, talk with your coworkers, read facebook. And eventually,
> > this operation will end.
> >
> > # echo function_graph > current_tracer
> >
> > If it crashes, we know that ~/test-file has a bad function.
> >
> > Reboot back to test kernel.
> >
> > # cd /sys/kernel/debug/tracing
> > # mv ~/test-file ~/full-file
> >
> > If it didn't crash.
> >
> > # echo nop > current_tracer
> > # mv ~/non-test-file ~/full-file
> >
> > Get rid of the other test file from previous run (or save them off somewhere.
> > # rm -f ~/test-file ~/non-test-file
> >
> > And start again:
> >
> > # ftrace-bisect ~/full-file ~/test-file ~/non-test-file
> >
> > The good thing is, because this cuts the number of functions in ~/test-file by half,
> > the cat of it into set_ftrace_filter takes half as long each iteration, so don't talk
> > so much at the water cooler the second time.
> >
> > Eventually, if you did this correctly, you will get down to the problem function,
> > and all we need to do is to notrace it.
> >
> > The way to figure out if the problem function is bad, just do:
> >
> > # echo <problem-function> > set_ftrace_notrace # echo > set_ftrace_filter #
> > echo function_graph > current_tracer
> >
> > And if it doesn't crash, we are done.
> >
> > -- Steve
>
>
> Hi, Steve
> Thanks very much! This is a very useful trace tool, I now know the problem function,
> It is gt_counter_read, if not trace this function, ftrace function_graph work well.
I'm not sure whether the commit d6df3576e6b4 ("clocksource/drivers/arm_global_timer
: Prevent ftrace recursion") can fix this issue.
this commit is merged since v4.3, I noticed your kernel version is v4.0
Thanks,
Jisheng
> Do you know now how to deeply debug and trace which line is wrong through Ftrace?
>
> --Bean
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/4] ARM: tegra: nyan: Use proper IRQ type definitions
From: Jon Hunter @ 2016-09-21 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446366.1239.17.camel@paulk.fr>
On 21/09/16 09:26, Paul Kocialkowski wrote:
> * PGP Signed by an unknown key
>
> Le mercredi 21 septembre 2016 ? 08:52 +0100, Jon Hunter a ?crit :
>> On 20/09/16 19:14, Paul Kocialkowski wrote:
>>>
>>>> Old Signed by an unknown key
>>>
>>> Le mardi 20 septembre 2016 ? 18:15 +0100, Jon Hunter a ?crit :
>>>>
>>>> On 28/08/16 18:32, Paul Kocialkowski wrote:
>>>>>
>>>>>
>>>>> This switches a few interrupt definitions that were using
>>>>> GPIO_ACTIVE_HIGH as IRQ type, which is invalid.
>>>>
>>>> May be you are right, but this does not describe why this is invalid.
>>>> Can you elaborate?
>>>
>>> GPIO_ACTIVE_HIGH is simply not the right kind of define to use in the
>>> "interrupts" devicetree property. Values provided there are understood as
>>> IRQ_TYPE_ defines.
>>
>> Right, but you are changing the type as GPIO_ACTIVE_HIGH = 0 and
>> IRQ_TYPE_EDGE_FALLING = 2 and there is no comment about why this has
>> been changed. It might be correct, but you need to explain it.
>
> This actually makes the IRQ trigger values consistent with the drivers, that
> define them regardless of devicetree anyway. The max98090 driver
> has IRQF_TRIGGER_FALLING and bq24735 has IRQF_TRIGGER_RISING |
> IRQF_TRIGGER_FALLING.
>
> This is really more of a cosmetic change, it doesn't impact actual use.
So you are saying that the drivers don't actually use the DT types? May
be that is ok, and yes this is cosmetic, but this should be stated in
the changelog as it is not clear what is going on here.
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [PATCH v3 3/3] clk: mvebu: migrate CP110 system controller to clk_hw API and registration
From: Marcin Wojtas @ 2016-09-21 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474448759-24482-1-git-send-email-mw@semihalf.com>
Now that we have clk_hw based provider APIs to register clks, we
can get rid of struct clk pointers while registering clks in Armada
CP110 system controller driver. This commit introduces new
API and registration for all clocks in CP110 HW blocks.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
drivers/clk/mvebu/cp110-system-controller.c | 150 +++++++++++++---------------
1 file changed, 72 insertions(+), 78 deletions(-)
diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c
index f2303da..842bddd 100644
--- a/drivers/clk/mvebu/cp110-system-controller.c
+++ b/drivers/clk/mvebu/cp110-system-controller.c
@@ -87,7 +87,7 @@ struct cp110_gate_clk {
u8 bit_idx;
};
-#define to_cp110_gate_clk(clk) container_of(clk, struct cp110_gate_clk, hw)
+#define to_cp110_gate_clk(hw) container_of(hw, struct cp110_gate_clk, hw)
static int cp110_gate_enable(struct clk_hw *hw)
{
@@ -123,13 +123,14 @@ static const struct clk_ops cp110_gate_ops = {
.is_enabled = cp110_gate_is_enabled,
};
-static struct clk *cp110_register_gate(const char *name,
- const char *parent_name,
- struct regmap *regmap, u8 bit_idx)
+static struct clk_hw *cp110_register_gate(const char *name,
+ const char *parent_name,
+ struct regmap *regmap, u8 bit_idx)
{
struct cp110_gate_clk *gate;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
@@ -146,39 +147,37 @@ static struct clk *cp110_register_gate(const char *name,
gate->bit_idx = bit_idx;
gate->hw.init = &init;
- clk = clk_register(NULL, &gate->hw);
- if (IS_ERR(clk))
+ hw = &gate->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(gate);
+ hw = ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
-static void cp110_unregister_gate(struct clk *clk)
+static void cp110_unregister_gate(struct clk_hw *hw)
{
- struct clk_hw *hw;
-
- hw = __clk_get_hw(clk);
- if (!hw)
- return;
-
- clk_unregister(clk);
+ clk_hw_unregister(hw);
kfree(to_cp110_gate_clk(hw));
}
-static struct clk *cp110_of_clk_get(struct of_phandle_args *clkspec, void *data)
+static struct clk_hw *cp110_of_clk_get(struct of_phandle_args *clkspec,
+ void *data)
{
- struct clk_onecell_data *clk_data = data;
+ struct clk_hw_onecell_data *clk_data = data;
unsigned int type = clkspec->args[0];
unsigned int idx = clkspec->args[1];
if (type == CP110_CLK_TYPE_CORE) {
if (idx > CP110_MAX_CORE_CLOCKS)
return ERR_PTR(-EINVAL);
- return clk_data->clks[idx];
+ return clk_data->hws[idx];
} else if (type == CP110_CLK_TYPE_GATABLE) {
if (idx > CP110_MAX_GATABLE_CLOCKS)
return ERR_PTR(-EINVAL);
- return clk_data->clks[CP110_MAX_CORE_CLOCKS + idx];
+ return clk_data->hws[CP110_MAX_CORE_CLOCKS + idx];
}
return ERR_PTR(-EINVAL);
@@ -189,8 +188,8 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
struct regmap *regmap;
struct device_node *np = pdev->dev.of_node;
const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name;
- struct clk_onecell_data *cp110_clk_data;
- struct clk *clk, **cp110_clks;
+ struct clk_hw_onecell_data *cp110_clk_data;
+ struct clk_hw *hw, **cp110_clks;
u32 nand_clk_ctrl;
int i, ret;
@@ -203,80 +202,75 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
if (ret)
return ret;
- cp110_clks = devm_kcalloc(&pdev->dev, sizeof(struct clk *),
- CP110_CLK_NUM, GFP_KERNEL);
- if (!cp110_clks)
- return -ENOMEM;
-
- cp110_clk_data = devm_kzalloc(&pdev->dev,
- sizeof(*cp110_clk_data),
+ cp110_clk_data = devm_kcalloc(&pdev->dev, sizeof(*cp110_clk_data),
+ sizeof(struct clk_hw *) * CP110_CLK_NUM,
GFP_KERNEL);
if (!cp110_clk_data)
return -ENOMEM;
- cp110_clk_data->clks = cp110_clks;
- cp110_clk_data->clk_num = CP110_CLK_NUM;
+ cp110_clks = cp110_clk_data->hws;
+ cp110_clk_data->num = CP110_CLK_NUM;
- /* Register the APLL which is the root of the clk tree */
+ /* Register the APLL which is the root of the hw tree */
of_property_read_string_index(np, "core-clock-output-names",
CP110_CORE_APLL, &apll_name);
- clk = clk_register_fixed_rate(NULL, apll_name, NULL, 0,
- 1000 * 1000 * 1000);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
+ hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0,
+ 1000 * 1000 * 1000);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
goto fail0;
}
- cp110_clks[CP110_CORE_APLL] = clk;
+ cp110_clks[CP110_CORE_APLL] = hw;
/* PPv2 is APLL/3 */
of_property_read_string_index(np, "core-clock-output-names",
CP110_CORE_PPV2, &ppv2_name);
- clk = clk_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
+ hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
goto fail1;
}
- cp110_clks[CP110_CORE_PPV2] = clk;
+ cp110_clks[CP110_CORE_PPV2] = hw;
/* EIP clock is APLL/2 */
of_property_read_string_index(np, "core-clock-output-names",
CP110_CORE_EIP, &eip_name);
- clk = clk_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
+ hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
goto fail2;
}
- cp110_clks[CP110_CORE_EIP] = clk;
+ cp110_clks[CP110_CORE_EIP] = hw;
/* Core clock is EIP/2 */
of_property_read_string_index(np, "core-clock-output-names",
CP110_CORE_CORE, &core_name);
- clk = clk_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
+ hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
goto fail3;
}
- cp110_clks[CP110_CORE_CORE] = clk;
+ cp110_clks[CP110_CORE_CORE] = hw;
/* NAND can be either APLL/2.5 or core clock */
of_property_read_string_index(np, "core-clock-output-names",
CP110_CORE_NAND, &nand_name);
if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK)
- clk = clk_register_fixed_factor(NULL, nand_name,
- apll_name, 0, 2, 5);
+ hw = clk_hw_register_fixed_factor(NULL, nand_name,
+ apll_name, 0, 2, 5);
else
- clk = clk_register_fixed_factor(NULL, nand_name,
- core_name, 0, 1, 1);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
+ hw = clk_hw_register_fixed_factor(NULL, nand_name,
+ core_name, 0, 1, 1);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
goto fail4;
}
- cp110_clks[CP110_CORE_NAND] = clk;
+ cp110_clks[CP110_CORE_NAND] = hw;
for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) {
const char *parent, *name;
@@ -335,16 +329,16 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
break;
}
- clk = cp110_register_gate(name, parent, regmap, i);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
+ hw = cp110_register_gate(name, parent, regmap, i);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
goto fail_gate;
}
- cp110_clks[CP110_MAX_CORE_CLOCKS + i] = clk;
+ cp110_clks[CP110_MAX_CORE_CLOCKS + i] = hw;
}
- ret = of_clk_add_provider(np, cp110_of_clk_get, cp110_clk_data);
+ ret = of_clk_add_hw_provider(np, cp110_of_clk_get, cp110_clk_data);
if (ret)
goto fail_clk_add;
@@ -355,44 +349,44 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
fail_clk_add:
fail_gate:
for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) {
- clk = cp110_clks[CP110_MAX_CORE_CLOCKS + i];
+ hw = cp110_clks[CP110_MAX_CORE_CLOCKS + i];
- if (clk)
- cp110_unregister_gate(clk);
+ if (hw)
+ cp110_unregister_gate(hw);
}
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]);
fail4:
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]);
fail3:
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]);
fail2:
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]);
fail1:
- clk_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]);
+ clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]);
fail0:
return ret;
}
static int cp110_syscon_clk_remove(struct platform_device *pdev)
{
- struct clk **cp110_clks = platform_get_drvdata(pdev);
+ struct clk_hw **cp110_clks = platform_get_drvdata(pdev);
int i;
of_clk_del_provider(pdev->dev.of_node);
for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) {
- struct clk *clk = cp110_clks[CP110_MAX_CORE_CLOCKS + i];
+ struct clk_hw *hw = cp110_clks[CP110_MAX_CORE_CLOCKS + i];
- if (clk)
- cp110_unregister_gate(clk);
+ if (hw)
+ cp110_unregister_gate(hw);
}
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]);
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]);
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]);
- clk_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]);
- clk_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]);
+ clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]);
+ clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]);
return 0;
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 2/3] clk: mvebu: dynamically allocate resources in Armada CP110 system controller
From: Marcin Wojtas @ 2016-09-21 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474448759-24482-1-git-send-email-mw@semihalf.com>
Original commit, which added support for Armada CP110 system controller
used global variables for storing all clock information. It worked
fine for Armada 7k SoC, with single CP110 block. After dual-CP110 Armada 8k
was introduced, the data got overwritten and corrupted.
This patch fixes the issue by allocating resources dynamically in the
driver probe and storing it as platform drvdata.
Fixes: d3da3eaef7f4 ("clk: mvebu: new driver for Armada CP110 system ...")
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Reviewed-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
CC: <stable@vger.kernel.org>
---
drivers/clk/mvebu/cp110-system-controller.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c
index 59fe76e..f2303da 100644
--- a/drivers/clk/mvebu/cp110-system-controller.c
+++ b/drivers/clk/mvebu/cp110-system-controller.c
@@ -81,13 +81,6 @@ enum {
#define CP110_GATE_EIP150 25
#define CP110_GATE_EIP197 26
-static struct clk *cp110_clks[CP110_CLK_NUM];
-
-static struct clk_onecell_data cp110_clk_data = {
- .clks = cp110_clks,
- .clk_num = CP110_CLK_NUM,
-};
-
struct cp110_gate_clk {
struct clk_hw hw;
struct regmap *regmap;
@@ -196,7 +189,8 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
struct regmap *regmap;
struct device_node *np = pdev->dev.of_node;
const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name;
- struct clk *clk;
+ struct clk_onecell_data *cp110_clk_data;
+ struct clk *clk, **cp110_clks;
u32 nand_clk_ctrl;
int i, ret;
@@ -209,6 +203,20 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
if (ret)
return ret;
+ cp110_clks = devm_kcalloc(&pdev->dev, sizeof(struct clk *),
+ CP110_CLK_NUM, GFP_KERNEL);
+ if (!cp110_clks)
+ return -ENOMEM;
+
+ cp110_clk_data = devm_kzalloc(&pdev->dev,
+ sizeof(*cp110_clk_data),
+ GFP_KERNEL);
+ if (!cp110_clk_data)
+ return -ENOMEM;
+
+ cp110_clk_data->clks = cp110_clks;
+ cp110_clk_data->clk_num = CP110_CLK_NUM;
+
/* Register the APLL which is the root of the clk tree */
of_property_read_string_index(np, "core-clock-output-names",
CP110_CORE_APLL, &apll_name);
@@ -336,10 +344,12 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev)
cp110_clks[CP110_MAX_CORE_CLOCKS + i] = clk;
}
- ret = of_clk_add_provider(np, cp110_of_clk_get, &cp110_clk_data);
+ ret = of_clk_add_provider(np, cp110_of_clk_get, cp110_clk_data);
if (ret)
goto fail_clk_add;
+ platform_set_drvdata(pdev, cp110_clks);
+
return 0;
fail_clk_add:
@@ -366,6 +376,7 @@ fail0:
static int cp110_syscon_clk_remove(struct platform_device *pdev)
{
+ struct clk **cp110_clks = platform_get_drvdata(pdev);
int i;
of_clk_del_provider(pdev->dev.of_node);
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 1/3] clk: mvebu: fix setting unwanted flags in CP110 gate clock
From: Marcin Wojtas @ 2016-09-21 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474448759-24482-1-git-send-email-mw@semihalf.com>
Armada CP110 system controller comprises its own routine responsble
for registering gate clocks. Among others 'flags' field in
struct clk_init_data was not set, using a random values, which
may cause an unpredicted behavior.
This patch fixes the problem by resetting all fields of clk_init_data
before assigning values for all gated clocks of Armada 7k/8k SoCs family.
Fixes: d3da3eaef7f4 ("clk: mvebu: new driver for Armada CP110 system ...")
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
CC: <stable@vger.kernel.org>
---
drivers/clk/mvebu/cp110-system-controller.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c
index 7fa42d6..59fe76e 100644
--- a/drivers/clk/mvebu/cp110-system-controller.c
+++ b/drivers/clk/mvebu/cp110-system-controller.c
@@ -142,6 +142,8 @@ static struct clk *cp110_register_gate(const char *name,
if (!gate)
return ERR_PTR(-ENOMEM);
+ memset(&init, 0, sizeof(init));
+
init.name = name;
init.ops = &cp110_gate_ops;
init.parent_names = &parent_name;
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 0/3] Armada 7k/8k CP110 system controller fixes
From: Marcin Wojtas @ 2016-09-21 9:05 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
Here is the third version of the patchset adding fixes to CP110
system controller clock driver. Comparing to v2, the only change
is return value on alloc failures.
Any feedback would be very welcome.
Best regards,
Marcin
Changelog:
v3 -> v2
* return -ENOMEM on alloc failures
v1 -> v2
* replace setting CLK_IS_BASIC flag with clearing init structure fields
with memset
* minor improvements of allocation and error checking
* add migration to clk_hw
Marcin Wojtas (3):
clk: mvebu: fix setting unwanted flags in CP110 gate clock
clk: mvebu: dynamically allocate resources in Armada CP110 system
controller
clk: mvebu: migrate CP110 system controller to clk_hw API and
registration
drivers/clk/mvebu/cp110-system-controller.c | 155 +++++++++++++++-------------
1 file changed, 81 insertions(+), 74 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [GIT PULL] Allwinner late DT changes for 4.9
From: Maxime Ripard @ 2016-09-21 8:58 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd, Olof, Kevin,
This is a late (and last) PR for the Allwinner device trees.
It comes on top of the previous one (so it still has the dependency in
the clock changes).
Let me know if you have any questions,
Maxime
The following changes since commit 7a988a4dd29a8cfcf405a12441533d765d25a6b8:
ARM: dts: gr8: Add support for the GR8 evaluation board (2016-09-11 22:23:17 +0200)
are available in the git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git tags/sunxi-dt-for-4.9-3
for you to fetch changes up to 90cb4b8c7e3af989c78227954e01455fc7c1e767:
ARM: dts: sun8i: Add accelerometer to polaroid-mid2407pxe03 (2016-09-21 11:48:09 +0300)
----------------------------------------------------------------
Allwinner DT changes for 4.9, late edition
Here is a bunch of late changes for the 4.9 merge window, mostly:
- Added a bunch of touchscreens nodes to tablets
- Added support for the AXP806 PMIC found in the A80 boards
- Enabled a few pinmux options for the H3
----------------------------------------------------------------
Chen-Yu Tsai (5):
ARM: dts: sun9i: a80-optimus: Declare AXP809 SW regulator as unused
ARM: dts: sun9i: cubieboard4: Declare AXP809 SW regulator as unused
ARM: dts: sun9i: a80-optimus: Add AXP806 PMIC device node and regulators
ARM: dts: sun9i: cubieboard4: Add AXP806 PMIC device node and regulators
ARM: dts: sun9i: a80-optimus: Disable EHCI1
Hans de Goede (6):
ARM: dts: sun8i: Add touchscreen node for sun8i-a23-gt90h
ARM: dts: sun8i: Add touchscreen node for sun8i-a23-inet86dz
ARM: dts: sun8i: Add touchscreen node for sun8i-a23-polaroid-mid2407pxe03
ARM: dts: sun8i: Add touchscreen node for sun8i-a23-polaroid-mid2809pxe04
ARM: dts: sun8i: Add touchscreen node for sun8i-a33-ga10h
ARM: dts: sun8i: Add accelerometer to polaroid-mid2407pxe03
Icenowy Zheng (2):
ARM: dts: sun8i: add pinmux for UART1 at PG
ARM: dts: sun8i: enable UART1 for iNet D978 Rev2 board
Jorik Jonker (5):
dts: sun8i-h3: add pinmux definitions for UART2-3
dts: sun8i-h3: split off RTS/CTS for UART1 in seperate pinmux
dts: sun8i-h3: associate exposed UARTs on Orange Pi Boards
dts: sun8i-h3: add pinmux definitions for I2C0-2
dts: sun8i-h3: add I2C0-2 peripherals to H3 SOC
arch/arm/boot/dts/sun8i-a23-a33.dtsi | 10 ++
arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts | 9 ++
arch/arm/boot/dts/sun8i-a23-inet86dz.dts | 9 ++
.../boot/dts/sun8i-a23-polaroid-mid2407pxe03.dts | 26 +++++
.../boot/dts/sun8i-a23-polaroid-mid2809pxe04.dts | 9 ++
arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts | 10 ++
arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts | 20 ++++
arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts | 2 +-
arch/arm/boot/dts/sun8i-h3-orangepi-2.dts | 18 +++
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 18 +++
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 18 +++
arch/arm/boot/dts/sun8i-h3.dtsi | 85 +++++++++++++-
arch/arm/boot/dts/sun9i-a80-cubieboard4.dts | 116 +++++++++++++++++++
arch/arm/boot/dts/sun9i-a80-optimus.dts | 123 ++++++++++++++++++++-
14 files changed, 468 insertions(+), 5 deletions(-)
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160921/3be903f5/attachment.sig>
^ permalink raw reply
* [PATCH v2] arm64: kgdb: handle read-only text / modules
From: Mark Rutland @ 2016-09-21 8:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160921071955.21792-1-takahiro.akashi@linaro.org>
On Wed, Sep 21, 2016 at 04:19:55PM +0900, AKASHI Takahiro wrote:
> Handle read-only cases (CONFIG_DEBUG_RODATA/CONFIG_DEBUG_SET_MODULE_RONX)
> by using aarch64_insn_write() instead of probe_kernel_write().
> See how this works:
> commit 2f896d586610 ("arm64: use fixmap for text patching")
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Jason Wessel <jason.wessel@windriver.com>
> Cc: <stable@vger.kernel.org> # 3.18-3.19: 2f896d5: arm64: use fixmap
> Cc: <stable@vger.kernel.org> # 4.0-
For v3.18-v3.19, we also need commit f6242cac10427c54 ("arm64: Fix text
patching logic when using fixmap"), so as to not break the
!CONFIG_DEBUG_SET_MODULE_RONX case.
With that:
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Thanks,
Mark.
> ---
> arch/arm64/include/asm/debug-monitors.h | 2 --
> arch/arm64/kernel/kgdb.c | 36 ++++++++++++++++++++++-----------
> 2 files changed, 24 insertions(+), 14 deletions(-)
>
> diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
> index 4b6b3f7..b71420a 100644
> --- a/arch/arm64/include/asm/debug-monitors.h
> +++ b/arch/arm64/include/asm/debug-monitors.h
> @@ -61,8 +61,6 @@
>
> #define AARCH64_BREAK_KGDB_DYN_DBG \
> (AARCH64_BREAK_MON | (KGDB_DYN_DBG_BRK_IMM << 5))
> -#define KGDB_DYN_BRK_INS_BYTE(x) \
> - ((AARCH64_BREAK_KGDB_DYN_DBG >> (8 * (x))) & 0xff)
>
> #define CACHE_FLUSH_IS_SAFE 1
>
> diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
> index 6732a27..b06a7a2 100644
> --- a/arch/arm64/kernel/kgdb.c
> +++ b/arch/arm64/kernel/kgdb.c
> @@ -19,6 +19,7 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/bug.h>
> #include <linux/cpumask.h>
> #include <linux/irq.h>
> #include <linux/irq_work.h>
> @@ -26,6 +27,8 @@
> #include <linux/kgdb.h>
> #include <linux/kprobes.h>
> #include <linux/percpu.h>
> +#include <asm/debug-monitors.h>
> +#include <asm/insn.h>
> #include <asm/ptrace.h>
> #include <asm/traps.h>
>
> @@ -370,15 +373,24 @@ void kgdb_arch_exit(void)
> unregister_die_notifier(&kgdb_notifier);
> }
>
> -/*
> - * ARM instructions are always in LE.
> - * Break instruction is encoded in LE format
> - */
> -struct kgdb_arch arch_kgdb_ops = {
> - .gdb_bpt_instr = {
> - KGDB_DYN_BRK_INS_BYTE(0),
> - KGDB_DYN_BRK_INS_BYTE(1),
> - KGDB_DYN_BRK_INS_BYTE(2),
> - KGDB_DYN_BRK_INS_BYTE(3),
> - }
> -};
> +struct kgdb_arch arch_kgdb_ops;
> +
> +int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
> +{
> + int err;
> +
> + BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
> +
> + err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
> + if (err)
> + return err;
> +
> + return aarch64_insn_write((void *)bpt->bpt_addr,
> + (u32)AARCH64_BREAK_KGDB_DYN_DBG);
> +}
> +
> +int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
> +{
> + return aarch64_insn_write((void *)bpt->bpt_addr,
> + *(u32 *)bpt->saved_instr);
> +}
> --
> 2.10.0
>
^ permalink raw reply
* [RFC] irqchip/gic-v3: Implement suspend and resume callbacks
From: Lingutla Chandrasekhar @ 2016-09-21 8:42 UTC (permalink / raw)
To: linux-arm-kernel
Implement suspend and resume syscore_ops to disable and
enable non wake up capable interrupts.
When system enters suspend, enable only wakeup capable
interrupts. While resuming, enable previously enabled interrupts
and show triggered/pending interrupts.
Signed-off-by: Lingutla Chandrasekhar <clingutla@codeaurora.org>
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index ede5672..511a5a1 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -33,6 +33,7 @@
#include <linux/irqchip/arm-gic-common.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irqchip/irq-partition-percpu.h>
+#include <linux/syscore_ops.h>
#include <asm/cputype.h>
#include <asm/exception.h>
@@ -57,6 +58,10 @@ struct gic_chip_data {
u32 nr_redist_regions;
unsigned int irq_nr;
struct partition_desc *ppi_descs[16];
+#ifdef CONFIG_PM
+ unsigned int wakeup_irqs[32];
+ unsigned int enabled_irqs[32];
+#endif
};
static struct gic_chip_data gic_data __read_mostly;
@@ -330,6 +335,81 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
return 0;
}
+#ifdef CONFIG_PM
+static int gic_suspend(void)
+{
+ unsigned int i;
+ void __iomem *base = gic_data.dist_base;
+
+ for (i = 0; i * 32 < gic->irq_nr; i++) {
+ gic->enabled_irqs[i]
+ = readl_relaxed(base + GICD_ISENABLER + i * 4);
+ /* disable all of them */
+ writel_relaxed(0xffffffff, base + GICD_ICENABLER + i * 4);
+ /* enable the wakeup set */
+ writel_relaxed(gic->wakeup_irqs[i],
+ base + GICD_ISENABLER + i * 4);
+ }
+ return 0;
+}
+
+static void gic_show_pending(void)
+{
+ unsigned int i;
+ u32 enabled;
+ u32 pending[32];
+ void __iomem *base = gic_data.dist_base;
+
+ for (i = 0; i * 32 < gic->irq_nr; i++) {
+ enabled = readl_relaxed(base + GICD_ICENABLER + i * 4);
+ pending[i] = readl_relaxed(base + GICD_ISPENDR + i * 4);
+ pending[i] &= enabled;
+ }
+
+ for_each_set_bit(i, (unsigned long *)pending, gic->irq_nr) {
+ unsigned int irq = irq_find_mapping(gic->domain, i);
+ struct irq_desc *desc = irq_to_desc(irq);
+ const char *name = "null";
+
+ if (desc == NULL)
+ name = "stray irq";
+ else if (desc->action && desc->action->name)
+ name = desc->action->name;
+
+ pr_debug("Pending IRQ: %d [%s]\n", __func__, irq, name);
+ }
+}
+
+static void gic_resume(void)
+{
+ unsigned int i;
+ void __iomem *base = gic_data.dist_base;
+
+ gic_show_pending();
+
+ for (i = 0; i * 32 < gic->irq_nr; i++) {
+ /* disable all of them */
+ writel_relaxed(0xffffffff, base + GICD_ICENABLER + i * 4);
+ /* enable the enabled set */
+ writel_relaxed(gic->enabled_irqs[i],
+ base + GICD_ISENABLER + i * 4);
+ }
+}
+
+static struct syscore_ops gic_syscore_ops = {
+ .suspend = gic_suspend,
+ .resume = gic_resume,
+};
+
+static int __init gic_init_sys(void)
+{
+ register_syscore_ops(&gic_syscore_ops);
+ return 0;
+}
+device_initcall(gic_init_sys);
+
+#endif
+
static u64 gic_mpidr_to_affinity(unsigned long mpidr)
{
u64 aff;
@@ -666,6 +746,32 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
#define gic_smp_init() do { } while(0)
#endif
+#ifdef CONFIG_PM
+int gic_set_wake(struct irq_data *d, unsigned int on)
+{
+ int ret = -ENXIO;
+ unsigned int reg_offset, bit_offset;
+ unsigned int gicirq = gic_irq(d);
+ struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+
+ /* per-cpu interrupts cannot be wakeup interrupts */
+ WARN_ON(gicirq < 32);
+
+ reg_offset = gicirq / 32;
+ bit_offset = gicirq % 32;
+
+ if (on)
+ gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
+ else
+ gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
+
+ return ret;
+}
+
+#else
+#define gic_set_wake NULL
+#endif
+
#ifdef CONFIG_CPU_PM
/* Check whether it's single security state view */
static bool gic_dist_security_disabled(void)
@@ -707,6 +813,7 @@ static struct irq_chip gic_chip = {
.irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
.irq_set_affinity = gic_set_affinity,
+ .irq_set_wake = gic_set_wake,
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.flags = IRQCHIP_SET_TYPE_MASKED,
@@ -723,6 +830,7 @@ static struct irq_chip gic_eoimode1_chip = {
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity,
.flags = IRQCHIP_SET_TYPE_MASKED,
+ .irq_set_wake = gic_set_wake,
};
#define GIC_ID_NR (1U << gic_data.rdists.id_bits)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project.
^ permalink raw reply related
* [PATCH 1/4] ARM: tegra: nyan: Use proper IRQ type definitions
From: Paul Kocialkowski @ 2016-09-21 8:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0ca614bf-4d27-9948-03e3-472d059f2153@nvidia.com>
Le mercredi 21 septembre 2016 ? 08:52 +0100, Jon Hunter a ?crit?:
> On 20/09/16 19:14, Paul Kocialkowski wrote:
> >
> > * PGP Signed by an unknown key
> >
> > Le mardi 20 septembre 2016 ? 18:15 +0100, Jon Hunter a ?crit :
> > >
> > > On 28/08/16 18:32, Paul Kocialkowski wrote:
> > > >
> > > >
> > > > This switches a few interrupt definitions that were using
> > > > GPIO_ACTIVE_HIGH as IRQ type, which is invalid.
> > >
> > > May be you are right, but this does not describe why this is invalid.
> > > Can you elaborate?
> >
> > GPIO_ACTIVE_HIGH is simply not the right kind of define to use in the
> > "interrupts" devicetree property. Values provided there are understood as
> > IRQ_TYPE_ defines.
>
> Right, but you are changing the type as GPIO_ACTIVE_HIGH = 0 and
> IRQ_TYPE_EDGE_FALLING = 2 and there is no comment about why this has
> been changed. It might be correct, but you need to explain it.
This actually makes the IRQ trigger values consistent with the drivers, that
define them regardless of devicetree anyway. The max98090 driver
has?IRQF_TRIGGER_FALLING and bq24735 has IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING.
This is really more of a cosmetic change, it doesn't impact actual use.
--
Paul Kocialkowski, developer of low-level free software for embedded devices
Website: https://www.paulk.fr/
Coding blog: https://code.paulk.fr/
Git repositories: https://git.paulk.fr/ https://git.code.paulk.fr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160921/989111ff/attachment.sig>
^ permalink raw reply
* [v12, 7/8] base: soc: introduce soc_device_match() interface
From: Peter Rosin @ 2016-09-21 8:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474444574.270880035@f136.i.mail.ru>
On 2016-09-21 09:56, Alexander Shiyan wrote:
>> ?????, 21 ???????? 2016, 9:57 +03:00 ?? Yangbo Lu <yangbo.lu@nxp.com>:
>>
>> From: Arnd Bergmann < arnd@arndb.de >
>>
>> We keep running into cases where device drivers want to know the exact
>> version of the a SoC they are currently running on. In the past, this has
>> usually been done through a vendor specific API that can be called by a
>> driver, or by directly accessing some kind of version register that is
>> not part of the device itself but that belongs to a global register area
>> of the chip.
> ...
>> +const struct soc_device_attribute *soc_device_match(
>> +const struct soc_device_attribute *matches)
>> +{
>> +int ret = 0;
>> +
>> +if (!matches)
>> +return NULL;
>> +
>> +while (!ret) {
>> +if (!(matches->machine || matches->family ||
>> + matches->revision || matches->soc_id))
>> +break;
>> +ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
>> + soc_device_match_one);
>> +if (!ret)
>> +matches++;
>
> So, what happen if next "matches" (after increment) will be NULL?
A crash?
> I think you should use while(matches) at the start of this procedure.
*arrgh*
*If* matches wrap, you indeed have *big* problems. *Elsewhere*
Hint: Please read the review comments on the previous version of this
series [1] before commenting further.
Cheers,
Peter
[1] https://www.mail-archive.com/netdev at vger.kernel.org/msg126617.html
^ permalink raw reply
* [PATCH V7 6/6] ARM64: bcm2835: add thermal driver to default_config
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446227-1147-1-git-send-email-kernel@martin.sperl.org>
From: Martin Sperl <kernel@martin.sperl.org>
Add the thermal driver for bcm2837 to list of compiled modules
in the default config.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index eadf485..372f981 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -252,6 +252,7 @@ CONFIG_SENSORS_INA2XX=m
CONFIG_SENSORS_ARM_SCPI=y
CONFIG_THERMAL=y
CONFIG_THERMAL_EMULATION=y
+CONFIG_BCM2835_THERMAL=y
CONFIG_EXYNOS_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_RENESAS_WDT=y
--
2.1.4
^ permalink raw reply related
* [PATCH V7 5/6] ARM: bcm2835: add thermal driver to default_config
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446227-1147-1-git-send-email-kernel@martin.sperl.org>
From: Martin Sperl <kernel@martin.sperl.org>
Add the thermal driver to list of compiled modules
in the default config for bcm2835.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
---
arch/arm/configs/bcm2835_defconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig
index 79de828..4b89f4e 100644
--- a/arch/arm/configs/bcm2835_defconfig
+++ b/arch/arm/configs/bcm2835_defconfig
@@ -73,6 +73,8 @@ CONFIG_SPI_BCM2835=y
CONFIG_SPI_BCM2835AUX=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_BCM2835_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_BCM2835_WDT=y
CONFIG_DRM=y
--
2.1.4
^ permalink raw reply related
* [PATCH V7 4/6] ARM64: bcm2835: dts: add thermal node to device-tree of bcm2837
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446227-1147-1-git-send-email-kernel@martin.sperl.org>
From: Martin Sperl <kernel@martin.sperl.org>
Add the node for the thermal sensor of the bcm2837-soc
to the device tree.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
---
arch/arm64/boot/dts/broadcom/bcm2837.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/broadcom/bcm2837.dtsi b/arch/arm64/boot/dts/broadcom/bcm2837.dtsi
index f2a31d0..2b0cfc7 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2837.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2837.dtsi
@@ -74,3 +74,9 @@
interrupt-parent = <&local_intc>;
interrupts = <8>;
};
+
+/* enable thermal sensor with the correct compatible property set */
+&thermal {
+ compatible = "brcm,bcm2837-thermal";
+ status = "okay";
+};
--
2.1.4
^ permalink raw reply related
* [PATCH V7 3/6] ARM: bcm2835: dts: add thermal node to device-tree of bcm283x
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446227-1147-1-git-send-email-kernel@martin.sperl.org>
From: Martin Sperl <kernel@martin.sperl.org>
Add the node for the thermal sensor of the bcm2835-soc
to the device tree.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
Changelog:
V1 -> V5: generic settings is shared in bcm283x.dtsi, but disabled
moved the compatible string to the SOC specific dtsi
for arm and arm64
V5 -> V6: fix remove 0x prefix from thermal at 0x7e212000
Note: there is no arm/boot/dts/bcm2837.dtsi as of now,
so the 32-bit rpi3 dt is not modified.
---
arch/arm/boot/dts/bcm2835.dtsi | 6 ++++++
arch/arm/boot/dts/bcm2836.dtsi | 6 ++++++
arch/arm/boot/dts/bcm283x.dtsi | 7 +++++++
3 files changed, 19 insertions(+)
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index a78759e..0890d97 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -23,3 +23,9 @@
};
};
};
+
+/* enable thermal sensor with the correct compatible property set */
+&thermal {
+ compatible = "brcm,bcm2835-thermal";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm2836.dtsi b/arch/arm/boot/dts/bcm2836.dtsi
index 9d0651d..519a44f 100644
--- a/arch/arm/boot/dts/bcm2836.dtsi
+++ b/arch/arm/boot/dts/bcm2836.dtsi
@@ -76,3 +76,9 @@
interrupt-parent = <&local_intc>;
interrupts = <8>;
};
+
+/* enable thermal sensor with the correct compatible property set */
+&thermal {
+ compatible = "brcm,bcm2836-thermal";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index b982522..d9acf21 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -186,6 +186,13 @@
interrupts = <2 14>; /* pwa1 */
};
+ thermal: thermal at 7e212000 {
+ compatible = "brcm,bcm2835-thermal";
+ reg = <0x7e212000 0x8>;
+ clocks = <&clocks BCM2835_CLOCK_TSENS>;
+ status = "disabled";
+ };
+
aux: aux at 0x7e215000 {
compatible = "brcm,bcm2835-aux";
#clock-cells = <1>;
--
2.1.4
^ permalink raw reply related
* [PATCH V7 2/6] thermal: bcm2835: add thermal driver for bcm2835 soc
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446227-1147-1-git-send-email-kernel@martin.sperl.org>
From: Martin Sperl <kernel@martin.sperl.org>
Add basic thermal driver for bcm2835 SOC.
This driver currently relies on the firmware setting up the
tsense HW block and does not set it up itself.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Acked-by: Eric Anholt <eric@anholt.net>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
ChangeLog:
V1 -> V2: added specific settings depending on compatiblity
added trip point based on register
setting up ctrl-register if HW is not enabled by firmware
as per recommendation of Eric (untested)
check that clock frequency is in range
(1.9 - 5MHz - as per comment in clk-bcm2835.c)
V2 -> V4: moved back to thermal (not using bcm sub-directory)
set polling interval to 1second (was 0ms, so interrupt driven)
V5 -> V6: added correct depends in KConfig
removed defined default for RESET_DELAY
removed obvious comments
clarify HW setup comments if not set up by FW already
move clk_prepare_enable to an earlier stage and add error handling
clarify warning when TS-clock runs out of recommended range
clk_disable_unprepare added in bcm2835_thermal_remove
added comment on recommended temperature ranges for SOC
V6 -> V7: removed depends on ARCH_BCM2836 || ARCH_BCM2837 in Kconfig
---
drivers/thermal/Kconfig | 8 +
drivers/thermal/Makefile | 1 +
drivers/thermal/bcm2835_thermal.c | 340 ++++++++++++++++++++++++++++++++++++++
3 files changed, 349 insertions(+)
create mode 100644 drivers/thermal/bcm2835_thermal.c
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2d702ca..1bc8b14 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -399,4 +399,12 @@ config GENERIC_ADC_THERMAL
to this driver. This driver reports the temperature by reading ADC
channel and converts it to temperature based on lookup table.
+config BCM2835_THERMAL
+ tristate "Thermal sensors on bcm2835 SoC"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on OF
+ help
+ Support for thermal sensors on Broadcom bcm2835 SoCs.
+
endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 10b07c1..c26343e 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
+obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
diff --git a/drivers/thermal/bcm2835_thermal.c b/drivers/thermal/bcm2835_thermal.c
new file mode 100644
index 0000000..3468c7b
--- /dev/null
+++ b/drivers/thermal/bcm2835_thermal.c
@@ -0,0 +1,340 @@
+/*
+ * Driver for Broadcom BCM2835 soc temperature sensor
+ *
+ * Copyright (C) 2016 Martin Sperl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#define BCM2835_TS_TSENSCTL 0x00
+#define BCM2835_TS_TSENSSTAT 0x04
+
+#define BCM2835_TS_TSENSCTL_PRWDW BIT(0)
+#define BCM2835_TS_TSENSCTL_RSTB BIT(1)
+#define BCM2835_TS_TSENSCTL_CTRL_BITS 3
+#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2
+#define BCM2835_TS_TSENSCTL_CTRL_MASK \
+ GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT)
+#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1
+#define BCM2835_TS_TSENSCTL_EN_INT BIT(5)
+#define BCM2835_TS_TSENSCTL_DIRECT BIT(6)
+#define BCM2835_TS_TSENSCTL_CLR_INT BIT(7)
+#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8
+#define BCM2835_TS_TSENSCTL_THOLD_BITS 10
+#define BCM2835_TS_TSENSCTL_THOLD_MASK \
+ GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT)
+#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18
+#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8
+#define BCM2835_TS_TSENSCTL_REGULEN BIT(26)
+
+#define BCM2835_TS_TSENSSTAT_DATA_BITS 10
+#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0
+#define BCM2835_TS_TSENSSTAT_DATA_MASK \
+ GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \
+ BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
+ BCM2835_TS_TSENSSTAT_DATA_SHIFT)
+#define BCM2835_TS_TSENSSTAT_VALID BIT(10)
+#define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11)
+
+struct bcm2835_thermal_info {
+ int offset;
+ int slope;
+ int trip_temp;
+};
+
+struct bcm2835_thermal_data {
+ const struct bcm2835_thermal_info *info;
+ void __iomem *regs;
+ struct clk *clk;
+ struct dentry *debugfsdir;
+};
+
+static int bcm2835_thermal_adc2temp(
+ const struct bcm2835_thermal_info *info, u32 adc)
+{
+ return info->offset + (adc * info->slope);
+}
+
+static int bcm2835_thermal_temp2adc(
+ const struct bcm2835_thermal_info *info, int temp)
+{
+ temp -= info->offset;
+ temp /= info->slope;
+
+ if (temp < 0)
+ temp = 0;
+ if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
+ temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
+
+ return temp;
+}
+
+static int bcm2835_thermal_get_trip_type(
+ struct thermal_zone_device *tz, int trip,
+ enum thermal_trip_type *type)
+{
+ *type = THERMAL_TRIP_CRITICAL;
+ return 0;
+}
+
+static int bcm2835_thermal_get_trip_temp(
+ struct thermal_zone_device *tz, int trip, int *temp)
+{
+ struct bcm2835_thermal_data *data = tz->devdata;
+ u32 val = readl(data->regs + BCM2835_TS_TSENSCTL);
+
+ /* get the THOLD bits */
+ val &= BCM2835_TS_TSENSCTL_THOLD_MASK;
+ val >>= BCM2835_TS_TSENSCTL_THOLD_SHIFT;
+
+ /* if it is zero then use the info value */
+ if (val)
+ *temp = bcm2835_thermal_adc2temp(data->info, val);
+ else
+ *temp = data->info->trip_temp;
+
+ return 0;
+}
+
+static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
+ int *temp)
+{
+ struct bcm2835_thermal_data *data = tz->devdata;
+ u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
+
+ if (!(val & BCM2835_TS_TSENSSTAT_VALID))
+ return -EIO;
+
+ val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
+
+ *temp = bcm2835_thermal_adc2temp(data->info, val);
+
+ return 0;
+}
+
+static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
+ {
+ .name = "ctl",
+ .offset = 0
+ },
+ {
+ .name = "stat",
+ .offset = 4
+ }
+};
+
+static void bcm2835_thermal_debugfs(struct platform_device *pdev)
+{
+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);
+ struct bcm2835_thermal_data *data = tz->devdata;
+ struct debugfs_regset32 *regset;
+
+ data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
+ if (!data->debugfsdir)
+ return;
+
+ regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
+ if (!regset)
+ return;
+
+ regset->regs = bcm2835_thermal_regs;
+ regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
+ regset->base = data->regs;
+
+ debugfs_create_regset32("regset", S_IRUGO,
+ data->debugfsdir, regset);
+}
+
+static struct thermal_zone_device_ops bcm2835_thermal_ops = {
+ .get_temp = bcm2835_thermal_get_temp,
+ .get_trip_temp = bcm2835_thermal_get_trip_temp,
+ .get_trip_type = bcm2835_thermal_get_trip_type,
+};
+
+static const struct of_device_id bcm2835_thermal_of_match_table[];
+static int bcm2835_thermal_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct thermal_zone_device *tz;
+ struct bcm2835_thermal_data *data;
+ struct resource *res;
+ int err;
+ u32 val;
+ unsigned long rate;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ match = of_match_device(bcm2835_thermal_of_match_table,
+ &pdev->dev);
+ if (!match)
+ return -EINVAL;
+ data->info = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->regs)) {
+ err = PTR_ERR(data->regs);
+ dev_err(&pdev->dev, "Could not get registers: %d\n", err);
+ return err;
+ }
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ err = PTR_ERR(data->clk);
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get clk: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(data->clk);
+ if (err)
+ return err;
+
+ rate = clk_get_rate(data->clk);
+ if ((rate < 1920000) || (rate > 5000000))
+ dev_warn(&pdev->dev,
+ "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",
+ data->clk, data->clk);
+
+ /*
+ * right now the FW does set up the HW-block, so we are not
+ * touching the configuration registers.
+ * But if the HW is not enabled, then set it up
+ * using "sane" values used by the firmware right now.
+ */
+ val = readl(data->regs + BCM2835_TS_TSENSCTL);
+ if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
+ /* the basic required flags */
+ val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
+ BCM2835_TS_TSENSCTL_REGULEN;
+
+ /*
+ * reset delay using the current firmware value of 14
+ * - units of time are unknown.
+ */
+ val |= (14 << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
+
+ /* trip_adc value from info */
+ val |= bcm2835_thermal_temp2adc(data->info,
+ data->info->trip_temp) <<
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT;
+
+ /* write the value back to the register as 2 steps */
+ writel(val, data->regs + BCM2835_TS_TSENSCTL);
+ val |= BCM2835_TS_TSENSCTL_RSTB;
+ writel(val, data->regs + BCM2835_TS_TSENSCTL);
+ }
+
+ /* register thermal zone with 1 trip point an 1s polling */
+ tz = thermal_zone_device_register("bcm2835_thermal",
+ 1, 0, data,
+ &bcm2835_thermal_ops,
+ NULL,
+ 0, 1000);
+ if (IS_ERR(tz)) {
+ clk_disable_unprepare(data->clk);
+ err = PTR_ERR(tz);
+ dev_err(&pdev->dev,
+ "Failed to register the thermal device: %d\n",
+ err);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, tz);
+
+ bcm2835_thermal_debugfs(pdev);
+
+ return 0;
+}
+
+static int bcm2835_thermal_remove(struct platform_device *pdev)
+{
+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);
+ struct bcm2835_thermal_data *data = tz->devdata;
+
+ debugfs_remove_recursive(data->debugfsdir);
+ thermal_zone_device_unregister(tz);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+/*
+ * Note: as per Raspberry Foundation FAQ
+ * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)
+ * the recommended temperature range for the SOC -40C to +85C
+ * so the trip limit is set to 80C.
+ * this applies to all the BCM283X SOC
+ */
+
+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
+ {
+ .compatible = "brcm,bcm2835-thermal",
+ .data = &(struct bcm2835_thermal_info) {
+ .offset = 407000,
+ .slope = -538,
+ .trip_temp = 80000
+ }
+ },
+ {
+ .compatible = "brcm,bcm2836-thermal",
+ .data = &(struct bcm2835_thermal_info) {
+ .offset = 407000,
+ .slope = -538,
+ .trip_temp = 80000
+ }
+ },
+ {
+ .compatible = "brcm,bcm2837-thermal",
+ .data = &(struct bcm2835_thermal_info) {
+ /* the bcm2837 needs adjustment of +5C */
+ .offset = 407000 + 5000,
+ .slope = -538,
+ .trip_temp = 80000
+ }
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
+
+static struct platform_driver bcm2835_thermal_driver = {
+ .probe = bcm2835_thermal_probe,
+ .remove = bcm2835_thermal_remove,
+ .driver = {
+ .name = "bcm2835_thermal",
+ .of_match_table = bcm2835_thermal_of_match_table,
+ },
+};
+module_platform_driver(bcm2835_thermal_driver);
+
+MODULE_AUTHOR("Martin Sperl");
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
+MODULE_LICENSE("GPL");
--
2.1.4
^ permalink raw reply related
* [PATCH V7 1/6] dt: bindings: add thermal device driver for bcm2835
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474446227-1147-1-git-send-email-kernel@martin.sperl.org>
From: Martin Sperl <kernel@martin.sperl.org>
Add dt-binding documentation for bcm2835 SOC thermal sensor.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Acked-by: Eric Anholt <eric@anholt.net>
Acked-by: Rob Herring <robh@kernel.org>
Changelog:
V1 -> V2: renamed file to follow naming conventions
V2 -> V3: removed 0x in node name
---
.../bindings/thermal/brcm,bcm2835-thermal.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt
diff --git a/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt b/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt
new file mode 100644
index 0000000..474531d
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt
@@ -0,0 +1,17 @@
+Binding for Thermal Sensor driver for BCM2835 SoCs.
+
+Required parameters:
+-------------------
+
+compatible: should be one of: "brcm,bcm2835-thermal",
+ "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal"
+reg: Address range of the thermal registers.
+clocks: Phandle of the clock used by the thermal sensor.
+
+Example:
+
+thermal: thermal at 7e212000 {
+ compatible = "brcm,bcm2835-thermal";
+ reg = <0x7e212000 0x8>;
+ clocks = <&clocks BCM2835_CLOCK_TSENS>;
+};
--
2.1.4
^ permalink raw reply related
* [PATCH V7 0/6] thermal: bcm2835: add thermal driver
From: kernel at martin.sperl.org @ 2016-09-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
From: Martin Sperl <kernel@martin.sperl.org>
Add a thermal driver for the TSENSE device of the bcm2835/6/7 SOC.
If the firmware enables the HW, then the configuration is not touched.
In case the firmware has not enabled the device, then we try to set
it up correctly (which unfortunately can not get tested).
It exposes temperature and a critical trip point
(using a hardcoded default of 80C or the temperature configured
in the control register by the firmware, which reads as
407C currently)
The calibrations are (potentially) different for bcm2835, bcm2836
and bcm2837 and can get selected by the compatible property
in the device tree.
The driver also exposes the registers via debugfs.
Possible future enhancements:
* the device has the ability to trigger interrupts on reaching
the programmed critical temperature.
I have no knowledge which interrupt could be responsible
for this on the ARM side, so if we get to know which irq
it is we can implement that.
Instead the driver right now implements polling in 1 second intervals
* the device can also reset the HW after the trip point
has been reached (also with some delay, so that corrective
actions can get taken) - this is currently not enabled by the
firmware, but could.
* we could define more trip points for THERMAL_TRIP_HOT
* make the trip point limits modifiable (ops.set_trip_temp)
Note:
No support for 32-bit arm bcm2837, as there is no
arch/arm/boot/dts/bcm2836.dtsi upstream as of now.
64-bit arm support is not tested
Changelog:
V1 -> V2: renamed dt-binding documentation file
added specific settings depending on compatible
added trip point based on register
setting up ctrl-register if HW is not enabled by firmware
as per recommendation of Eric (untested)
check that clock frequency is in range
(1.9 - 5MHz - as per comment in clk-bcm2835.c)
added driver to multi_v7_defconfig
V2 -> V3: made a module in multi_v7_defconfig
fixed typo in dt-binding document
V3 -> V4: moved driver back to thermal (not using bcm sub-directory)
set polling interval to 1second (was 0ms, so interrupt driven)
V4 -> V5: use correct compatiblity for different soc versions in dt
support ARM64 for bcm2837 in devicetree and defconfig
V5 -> V6: incorporated changes recommended by Stefan Wahren
V6 -> V7: removed depends on ARCH_BCM2836 || ARCH_BCM2837 in Kconfig
Martin Sperl (6):
dt: bindings: add thermal device driver for bcm2835
thermal: bcm2835: add thermal driver for bcm2835 soc
ARM: bcm2835: dts: add thermal node to device-tree of bcm283x
ARM64: bcm2835: dts: add thermal node to device-tree of bcm2837
ARM: bcm2835: add thermal driver to default_config
ARM64: bcm2835: add thermal driver to default_config
.../bindings/thermal/brcm,bcm2835-thermal.txt | 17 ++
arch/arm/boot/dts/bcm2835.dtsi | 6 +
arch/arm/boot/dts/bcm2836.dtsi | 6 +
arch/arm/boot/dts/bcm283x.dtsi | 7 +
arch/arm/configs/bcm2835_defconfig | 2 +
arch/arm64/boot/dts/broadcom/bcm2837.dtsi | 6 +
arch/arm64/configs/defconfig | 1 +
drivers/thermal/Kconfig | 8 +
drivers/thermal/Makefile | 1 +
drivers/thermal/bcm2835_thermal.c | 340 +++++++++++++++++++++
10 files changed, 394 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt
create mode 100644 drivers/thermal/bcm2835_thermal.c
--
2.1.4
^ permalink raw reply
* [PATCH] spi: atmel: use managed resource for gpio chip select
From: Geert Uytterhoeven @ 2016-09-21 8:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160921075528.14452-1-nicolas.ferre@atmel.com>
Hi Nicolas,
On Wed, Sep 21, 2016 at 9:55 AM, Nicolas Ferre <nicolas.ferre@atmel.com> wrote:
> Use the managed gpio CS pin request so that we avoid having trouble
> in the cleanup code.
> In fact, if module was configured with DT, cleanup code released
> invalid pin. Since resource wasn't freed, module cannot be reinserted.
>
> Reported-by: Alexander Morozov <linux@meltdown.ru>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
> drivers/spi/spi-atmel.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
> index 8feac599e9ab..4e3f2345844a 100644
> --- a/drivers/spi/spi-atmel.c
> +++ b/drivers/spi/spi-atmel.c
> @@ -1248,7 +1248,8 @@ static int atmel_spi_setup(struct spi_device *spi)
> return -ENOMEM;
>
> if (as->use_cs_gpios) {
> - ret = gpio_request(npcs_pin, dev_name(&spi->dev));
> + ret = devm_gpio_request(&spi->dev,
> + npcs_pin, dev_name(&spi->dev));
Note that spi_master.setup() can be called multiple times during the lifetime
of the spi_device.
> if (ret) {
> kfree(asd);
> return ret;
> @@ -1471,13 +1472,11 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
> static void atmel_spi_cleanup(struct spi_device *spi)
> {
> struct atmel_spi_device *asd = spi->controller_state;
> - unsigned gpio = (unsigned long) spi->controller_data;
>
> if (!asd)
> return;
>
> spi->controller_state = NULL;
> - gpio_free(gpio);
> kfree(asd);
> }
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [GIT PULL] ARM: mvebu: soc for v4.9 (#1)
From: Arnd Bergmann @ 2016-09-21 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87eg4e5xop.fsf@free-electrons.com>
On Tuesday, September 20, 2016 6:43:34 PM CEST Gregory CLEMENT wrote:
>
> Do you mean board-wnr854t.c?
Yes.
> If it is the case then I can just drop the patch adding this file because
> the only things done in this file are about the PCI.
Ah, that's perfect. Just for more background, I think it shouldn't be too
hard to convert the existing orion5x PCI support into a proper host driver,
and I can assist anyone willing to work on this and test it.
I think the steps here would roughly be:
- change PCI (not PCIe) host initialization to call
pci_scan_root_bus() directly, bypassing the pci_common_init
logic
- move PCI code into a separate file
- change PCI code into a driver by adding platform_device based
probing
- add DT support for that driver.
For the PCIe code, the obvious strategy is to replace it with
the existing pcie-mvebu driver, adding any missing parts
in the process.
Arnd
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox