* [PATCH v2 2/3] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Chen-Yu Tsai @ 2016-12-02 16:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <324c8820-aeea-3fad-0e02-1bdb8f675677@arm.com>
On Sat, Dec 3, 2016 at 12:10 AM, Andre Przywara <andre.przywara@arm.com> wrote:
> Hi,
>
> On 02/12/16 14:32, Icenowy Zheng wrote:
>>
>>
>> 02.12.2016, 22:30, "Hans de Goede" <hdegoede@redhat.com>:
>>> Hi,
>>>
>>> On 02-12-16 15:22, Icenowy Zheng wrote:
>>>> 01.12.2016, 17:36, "Maxime Ripard" <maxime.ripard@free-electrons.com>:
>>>>> On Mon, Nov 28, 2016 at 12:29:07AM +0000, Andr? Przywara wrote:
>>>>>> > Something more interesting happened.
>>>>>> >
>>>>>> > Xunlong made a add-on board for Orange Pi Zero, which exposes the
>>>>>> > two USB Controllers exported at expansion bus as USB Type-A
>>>>>> > connectors.
>>>>>> >
>>>>>> > Also it exposes a analog A/V jack and a microphone.
>>>>>> >
>>>>>> > Should I enable {e,o}hci{2.3} in the device tree?
>>>>>>
>>>>>> Actually we should do this regardless of this extension board. The USB
>>>>>> pins are not multiplexed and are exposed on user accessible pins (just
>>>>>> not soldered, but that's a detail), so I think they qualify for DT
>>>>>> enablement. And even if a user can't use them, it doesn't hurt to have
>>>>>> them (since they are not multiplexed).
>>>>>
>>>>> My main concern about this is that we'll leave regulators enabled by
>>>>> default, for a minority of users. And that minority will prevent to do
>>>>> a proper power management when the times come since we'll have to keep
>>>>> that behaviour forever.
>>>>
>>>> I think these users can add a 'fdt set /xxx/xxx status "disabled" ' .
>>>
>>> I don't think that will be necessary I'm pretty sure these extra usb
>>> ports do not have a regulator for the Vbus, they just hook directly
>>> to the 5V rail, can someone with a schematic check ?
>>
>> We seems to have still no schematics for the add-on board.
>
> From looking at the picture of that expansion board on the Aliexpress
> page and chasing the tracks, there is clearly no voltage regulator on
> there, it's just passive components. The 5V pin from the headers is
> routed forth and back between the two layers via some vias directly to
> the 5V pins of the USB sockets.
>
>> But something is sure is that there's no any regulator-related pins
>> on the add-on pinout. There's only USB DM and DP pins.
>>
>> So the Vbus must be directly connected to +5V.
>
> So yes, it is.
>
> But I think the question is moot anyways, since we don't provide DT
> support for that add-on board at that point anyways.
> One could imagine another board, though, which has regulators switched
> by GPIOs, but that would be their problem and they would have regulators
> specified in their specific DT snippet, then.
>
> So to summarize:
> - For that specific Orange Pi Zero board which we discuss the DT for
> there is no regulator support for the additional USB ports. Thus nothing
> we could turn off to save power.
> - A user could just take these USB brackets with pin headers that are so
> common in PCs to connect additional USB ports to the back of the box.
> One just needs to re-sort the pins, which is a matter of a minute.
> - As long as we don't provide any easy way of handling DT changes, we
> should enable the USB ports for the sake of the users of either those
> brackets or the expansion board. Any more sophisticated USB expansion
> board with regulators would need to amend the DT anyway.
>
> Does that make sense?
Sounds good to me.
ChenYu
^ permalink raw reply
* [PATCH v2 1/2] arm64: dts: zx: Fix gic GICR property
From: Arnd Bergmann @ 2016-12-02 16:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAAQ0ZWQkU6T=Fm4oZ1R5-zJEzErjroYAAJqU2TeNHfz=3UhYrg@mail.gmail.com>
On Monday, November 28, 2016 10:08:18 PM CET Shawn Guo wrote:
> On Sat, Nov 26, 2016 at 6:03 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Monday, October 17, 2016 1:49:19 PM CET Olof Johansson wrote:
> >> On Thu, Oct 13, 2016 at 08:31:20PM +0800, Jun Nie wrote:
> >> > GICR for multiple CPU can be described with start address and stride,
> >> > or with multiple address. Current multiple address and stride are
> >> > both used. Fix it.
> >> >
> >> > vmalloc patch 727a7f5a9 triggered this bug:
> >> > [ 0.097146] Unable to handle kernel paging request at virtual address ffff000008060008
> >> > [ 0.097150] pgd = ffff000008602000
> >> > [ 0.097160] [ffff000008060008] *pgd=000000007fffe003, *pud=000000007fffd003, *pmd=000000007fffc003, *pte=0000000000000000
> >> > [ 0.097165] Internal error: Oops: 96000007 [#1] PREEMPT SMP
> >> > [ 0.097170] Modules linked in:
> >> > [ 0.097177] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0+ #1474
> >> > [ 0.097179] Hardware name: ZTE zx296718 evaluation board (DT)
> >> > [ 0.097183] task: ffff80003e8c8b80 task.stack: ffff80003e8d0000
> >> > [ 0.097197] PC is at gic_populate_rdist+0x74/0x15c
> >> > [ 0.097202] LR is at gic_starting_cpu+0xc/0x20
> >> > [ 0.097206] pc : [<ffff0000082b1b18>] lr : [<ffff0000082b26e0>] pstate: 600001c5
> >> >
> >> > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> >>
> >> A Fixes: tag would be useful on a patch like this, to tell what patch
> >> introduced the problem. Please consider using them in the future.
> >>
> >> I've applied this one to fixes now.
> >
> > Hi Olof,
> >
> > I happened to still have this one in my todo folder as I must have
> > missed your reply, and I stumbled over it while looking for things
> > that may have gone missing.
> >
> > I don't see it in v4.9-rc6, did it get dropped accidentally?
>
> Please help get this into v4.9 if possible, as it is required to get
> v4.9 kernel boot up on ZTE ZX296718 SoC. Thanks.
>
> Shawn
>
Ok, applied both. Thanks,
Arnd
^ permalink raw reply
* [PATCH] imx_v6_v7_defconfig: enable SPIDEV module
From: Javier Martinez Canillas @ 2016-12-02 16:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202161359.y3mzvdxsfb2dyok7@t450s.lan>
Hello Gary,
On Fri, Dec 2, 2016 at 1:13 PM, Gary Bisson
<gary.bisson@boundarydevices.com> wrote:
> Hi Javier,
>
> Thanks for the quick feedback on the matter.
>
You are welcome.
> On Fri, Dec 02, 2016 at 12:44:42PM -0300, Javier Martinez Canillas wrote:
>> Hello Gary,
>>
>> On Fri, Dec 2, 2016 at 12:27 PM, Gary Bisson
>> <gary.bisson@boundarydevices.com> wrote:
>> > Hi Fabio,
>> >
>> > On Fri, Dec 02, 2016 at 01:18:42PM -0200, Fabio Estevam wrote:
>> >> Hi Gary,
>> >>
>> >> On Fri, Dec 2, 2016 at 12:56 PM, Gary Bisson
>> >> <gary.bisson@boundarydevices.com> wrote:
>> >> > Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
>> >> > ---
>> >> > Hi,
>> >> >
>> >> > Seems that this configuration is missing, especially since many
>> >> > device trees are already using "spidev" nodes.
>> >>
>>
>> This seems to have been added just because people weren't looking that
>> closer to DT patches at the beginning, but now is forbidden. That's
>> why the kernel now warns about it.
>>
>> >> Then they will trigger the following warning below (from the spidev
>> >> probe function):
>> >>
>> >> /*
>> >> * spidev should never be referenced in DT without a specific
>> >> * compatible string, it is a Linux implementation thing
>> >> * rather than a description of the hardware.
>> >> */
>> >> if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
>> >> dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
>> >> WARN_ON(spi->dev.of_node &&
>> >> !of_match_device(spidev_dt_ids, &spi->dev));
>> >> }
>> >
>> > Yes I've seen this WARN_ON when doing the dt-overlay testing. But is
>> > disabling the SPIDEV configuration a solution?
>> >
>> > To be honest I disagree with that WARN_ON. Ok it means that the hardware
>> > isn't fully described in the device tree but for development platforms
>> > (such as ours or any rpi-like boards) the user can design his own
>> > daugher board with whatever SPI device on it. Then using the spidev
>> > interface is very convenient, so I don't understand what we are trying
>> > to forbid here.
>> >
>>
>> AFAICT, what we are trying to forbid is to have a Linux implementation
>> detail to creep into a Device Tree.
>>
>> It's OK to use the spidev interface but that's orthogonal on how the
>> device is instantiated from the DT. If you want to do that, the
>> correct approach is AFAIU to add a OF device ID entry in
>> drivers/spi/spidev.c and use that compatible string in your DT.
>
> I understand that the device tree isn't supposed to describe such
> generic "spidev" concept.
>
> And that argument to me is ok for final products where the hardware is
> fully defined. However I still believe that for development platforms
> this cannot be applied. My customers want to use the SPI bus to connect
> any device they want, and most of those customers don't want to mess
> with the kernel. For them, having a spidev node, just like it exists for
> i2cdev nodes, is ideal.
>
Yes, they are free to do it in their vendor tree DTBs. They just
shouldn't try to post their DTS for mainline inclusion :)
>> That way, the DT will describe the hardware instead of just a "spidev"
>> but you could use the spidev interface to access your SPI device.
>
> But then aren't you afraid that the person will use the first compatible
> that shows up (let's say "rohm,dh2228fv") and use it for all his spidev?
> In that case the driver is happy although the fact remains that any hw
> will be plugged behind. Or at the opposite, if everybody that uses
> spidev adds its own compatible I'm not sure it will benefit the drive
> code.
>
I agree with you that people adding random compatible strings to the
spidev OF device ID table will not scale either. I don't really have
an answer to that, I just mentioned what the SPI maintainers told me
last time I tried to do something similar for a different platform a
couple of years ago:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-November/303348.html
> Anyway, I appreciate your feedback.
>
> Regards,
> Gary
Best regards,
Javier
^ permalink raw reply
* [PATCH] soc: ti: qmss: fix the case when !SMP
From: Santosh Shilimkar @ 2016-12-02 16:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <b6c6e9c3-6534-9f20-73bb-84c4e31de5e5@oracle.com>
On 11/30/2016 9:14 AM, Santosh Shilimkar wrote:
> On 11/30/2016 9:10 AM, Grygorii Strashko wrote:
>>
[...]
>>
>> For some reason you e-email is not working - delivery failure
>> ssantosh at kernel.org
>>
> Weird. I was getting all the emails. Thanks for bouncing the thread.
> I will check.
>
Seems like there was issue with kernel.org mail host which I have
been told fixed now. You shouldn't see those bouncing anymore.
Regards,
Santosh
^ permalink raw reply
* [linux-sunxi] [PATCH v3 -next 2/2] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Chen-Yu Tsai @ 2016-12-02 16:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202150513.34691-2-icenowy@aosc.xyz>
Hi,
On Fri, Dec 2, 2016 at 11:05 PM, Icenowy Zheng <icenowy@aosc.xyz> wrote:
> Orange Pi Zero is a board that came with the new Allwinner H2+ SoC and a
> SDIO Wi-Fi chip by Allwinner (XR819).
>
> Add a device tree file for it.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
> ---
> Changes since v2:
> - Merged SDIO Wi-Fi patch into it.
> - SDIO Wi-Fi: add a ethernet1 alias to it, as it has no internal NVRAM.
> - SDIO Wi-Fi: changed pinctrl binding to generic pinconf
> - removed all gpio pinctrl nodes
> - changed h2plus to h2-plus
> Changes since v1:
> - Convert to generic pinconf bindings.
> - SDIO Wi-Fi: add patch.
>
> Some notes:
> - The uart1 and uart2 is available on the unsoldered gpio header.
> - The onboard USB connector has its Vbus directly connected to DCIN-5V (the
> power jack)
>
> arch/arm/boot/dts/Makefile | 1 +
> arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts | 159 ++++++++++++++++++++++
> 2 files changed, 160 insertions(+)
> create mode 100644 arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
>
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index 6447abc..59f6e86 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -844,6 +844,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
> sun8i-a33-sinlinx-sina33.dtb \
> sun8i-a83t-allwinner-h8homlet-v2.dtb \
> sun8i-a83t-cubietruck-plus.dtb \
> + sun8i-h2-plus-orangepi-zero.dtb \
> sun8i-h3-bananapi-m2-plus.dtb \
> sun8i-h3-nanopi-neo.dtb \
> sun8i-h3-orangepi-2.dtb \
> diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
> new file mode 100644
> index 0000000..d18807f
> --- /dev/null
> +++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
> @@ -0,0 +1,159 @@
> +/*
> + * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz>
> + *
> + * Based on sun8i-h3-orangepi-one.dts, which is:
> + * Copyright (C) 2016 Hans de Goede <hdegoede@redhat.com>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This file 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 file 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.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/dts-v1/;
> +#include "sun8i-h3.dtsi"
> +#include "sunxi-common-regulators.dtsi"
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/input.h>
> +#include <dt-bindings/pinctrl/sun4i-a10.h>
> +
> +/ {
> + model = "Xunlong Orange Pi Zero";
> + compatible = "xunlong,orangepi-zero", "allwinner,sun8i-h2-plus";
> +
> + aliases {
> + serial0 = &uart0;
> + /* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
> + ethernet1 = &xr819;
> + };
> +
> + chosen {
> + stdout-path = "serial0:115200n8";
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> +
> + pwr_led {
> + label = "orangepi:green:pwr";
> + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
> + default-state = "on";
> + };
> +
> + status_led {
> + label = "orangepi:red:status";
> + gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>;
> + };
> + };
> +
> + reg_vcc_wifi: reg_vcc_wifi {
> + compatible = "regulator-fixed";
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-name = "vcc-wifi";
> + enable-active-high;
> + gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>;
> + };
> +
> + wifi_pwrseq: wifi_pwrseq {
> + compatible = "mmc-pwrseq-simple";
> + reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>;
> + };
> +};
> +
> +&ehci1 {
> + status = "okay";
> +};
> +
> +&mmc0 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&mmc0_pins_a>;
> + vmmc-supply = <®_vcc3v3>;
> + bus-width = <4>;
> + cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
> + cd-inverted;
> + status = "okay";
> +};
> +
> +&mmc1 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&mmc1_pins_a>;
> + vmmc-supply = <®_vcc_wifi>;
> + mmc-pwrseq = <&wifi_pwrseq>;
> + bus-width = <4>;
> + non-removable;
> + status = "okay";
> +
> + /*
> + * Explicitly define the sdio device, so that we can add an ethernet
> + * alias for it (which e.g. makes u-boot set a mac-address).
> + */
> + xr819: sdio_wifi at 1 {
> + reg = <1>;
> + };
> +};
> +
> +&mmc1_pins_a {
> + bias-pull-up;
This is already set in h3.dtsi
> +};
> +
> +&ohci1 {
> + status = "okay";
> +};
> +
> +&uart0 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&uart0_pins_a>;
> + status = "okay";
> +};
> +
> +&uart1 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&uart1_pins>;
> + status = "disabled";
> +};
> +
> +&uart2 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&uart2_pins>;
> + status = "disabled";
> +};
> +
> +&usbphy {
> + /* USB VBUS is always on */
I think this comment could use a little work.
AFAIK this board doesn't have an actual USB port.
It's just the D+/D- pins on the pin header, along
with the board-wide 5V, also on the pin header.
ChenYu
> + status = "okay";
> +};
> --
> 2.10.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* [stable:PATCH 0/3] PAN fixes backport for v4.4.35
From: James Morse @ 2016-12-02 16:42 UTC (permalink / raw)
To: linux-arm-kernel
Hi linux-stable,
This is the backport of the recent PAN fixes series for v4.4.35.
Original series:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-October/461806.html
Patch 1 changes the prototype of all the feature/errata enable calls, so
is fiddly to backport, hence doing it later as a separate series.
Patch 3 has had the UAO desription removed from its commit message as
v4.4 doesn't support this feature.
Thanks,
James Morse (3):
arm64: cpufeature: Schedule enable() calls instead of calling them via
IPI [v4.4]
arm64: mm: Set PSTATE.PAN from the cpu_enable_pan() call [v4.4]
arm64: suspend: Reconfigure PSTATE after resume from idle [v4.4]
arch/arm64/include/asm/cpufeature.h | 2 +-
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/kernel/cpufeature.c | 10 +++++++++-
arch/arm64/kernel/suspend.c | 9 +++++++++
arch/arm64/mm/fault.c | 12 +++++++++++-
5 files changed, 31 insertions(+), 4 deletions(-)
--
2.10.1
^ permalink raw reply
* [stable:PATCH 1/3] arm64: cpufeature: Schedule enable() calls instead of calling them via IPI [v4.4]
From: James Morse @ 2016-12-02 16:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202164247.19496-1-james.morse@arm.com>
commit 2a6dcb2b5f3e21592ca8dfa198dcce7bec09b020 upstream.
The enable() call for a cpufeature/errata is called using on_each_cpu().
This issues a cross-call IPI to get the work done. Implicitly, this
stashes the running PSTATE in SPSR when the CPU receives the IPI, and
restores it when we return. This means an enable() call can never modify
PSTATE.
To allow PAN to do this, change the on_each_cpu() call to use
stop_machine(). This schedules the work on each CPU which allows
us to modify PSTATE.
This involves changing the protype of all the enable() functions.
enable_cpu_capabilities() is called during boot and enables the feature
on all online CPUs. This path now uses stop_machine(). CPU features for
hotplug'd CPUs are enabled by verify_local_cpu_features() which only
acts on the local CPU, and can already modify the running PSTATE as it
is called from secondary_start_kernel().
Reported-by: Tony Thompson <anthony.thompson@arm.com>
Reported-by: Vladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
[Removed enable() hunks for features/errata v4.4. doesn't have. Changed
caps->enable arg in enable_cpu_capabilities()]
Signed-off-by: James Morse <james.morse@arm.com>
Cc: <stable@vger.kernel.org> # 4.4.35
---
arch/arm64/include/asm/cpufeature.h | 2 +-
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/kernel/cpufeature.c | 10 +++++++++-
arch/arm64/mm/fault.c | 3 ++-
4 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 8136afc9df0d..8884b5d5f48c 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -77,7 +77,7 @@ struct arm64_cpu_capabilities {
const char *desc;
u16 capability;
bool (*matches)(const struct arm64_cpu_capabilities *);
- void (*enable)(void *); /* Called on all active CPUs */
+ int (*enable)(void *); /* Called on all active CPUs */
union {
struct { /* To be used for erratum handling only */
u32 midr_model;
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 4acb7ca94fcd..d08559528927 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -186,6 +186,6 @@ static inline void spin_lock_prefetch(const void *x)
#endif
-void cpu_enable_pan(void *__unused);
+int cpu_enable_pan(void *__unused);
#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 0669c63281ea..2735bf814592 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -19,7 +19,9 @@
#define pr_fmt(fmt) "CPU features: " fmt
#include <linux/bsearch.h>
+#include <linux/cpumask.h>
#include <linux/sort.h>
+#include <linux/stop_machine.h>
#include <linux/types.h>
#include <asm/cpu.h>
#include <asm/cpufeature.h>
@@ -764,7 +766,13 @@ static void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
for (i = 0; caps[i].desc; i++)
if (caps[i].enable && cpus_have_cap(caps[i].capability))
- on_each_cpu(caps[i].enable, NULL, true);
+ /*
+ * Use stop_machine() as it schedules the work allowing
+ * us to modify PSTATE, instead of on_each_cpu() which
+ * uses an IPI, giving us a PSTATE that disappears when
+ * we return.
+ */
+ stop_machine(caps[i].enable, NULL, cpu_online_mask);
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 4c1a118c1d09..d4634e6942ca 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -606,8 +606,9 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
}
#ifdef CONFIG_ARM64_PAN
-void cpu_enable_pan(void *__unused)
+int cpu_enable_pan(void *__unused)
{
config_sctlr_el1(SCTLR_EL1_SPAN, 0);
+ return 0;
}
#endif /* CONFIG_ARM64_PAN */
--
2.10.1
^ permalink raw reply related
* [stable:PATCH 2/3] arm64: mm: Set PSTATE.PAN from the cpu_enable_pan() call [v4.4]
From: James Morse @ 2016-12-02 16:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202164247.19496-1-james.morse@arm.com>
commit 7209c868600bd8926e37c10b9aae83124ccc1dd8 upstream.
Commit 338d4f49d6f7 ("arm64: kernel: Add support for Privileged Access
Never") enabled PAN by enabling the 'SPAN' feature-bit in SCTLR_EL1.
This means the PSTATE.PAN bit won't be set until the next return to the
kernel from userspace. On a preemptible kernel we may schedule work that
accesses userspace on a CPU before it has done this.
Now that cpufeature enable() calls are scheduled via stop_machine(), we
can set PSTATE.PAN from the cpu_enable_pan() call.
Add WARN_ON_ONCE(in_interrupt()) to check the PSTATE value we updated
is not immediately discarded.
Reported-by: Tony Thompson <anthony.thompson@arm.com>
Reported-by: Vladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
[will: fixed typo in comment]
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Cc: <stable@vger.kernel.org> # 4.4.35
---
arch/arm64/mm/fault.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index d4634e6942ca..247bae758e1e 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -29,7 +29,9 @@
#include <linux/sched.h>
#include <linux/highmem.h>
#include <linux/perf_event.h>
+#include <linux/preempt.h>
+#include <asm/bug.h>
#include <asm/cpufeature.h>
#include <asm/exception.h>
#include <asm/debug-monitors.h>
@@ -608,7 +610,14 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
#ifdef CONFIG_ARM64_PAN
int cpu_enable_pan(void *__unused)
{
+ /*
+ * We modify PSTATE. This won't work from irq context as the PSTATE
+ * is discarded once we return from the exception.
+ */
+ WARN_ON_ONCE(in_interrupt());
+
config_sctlr_el1(SCTLR_EL1_SPAN, 0);
+ asm(SET_PSTATE_PAN(1));
return 0;
}
#endif /* CONFIG_ARM64_PAN */
--
2.10.1
^ permalink raw reply related
* [stable:PATCH 3/3] arm64: suspend: Reconfigure PSTATE after resume from idle [v4.4]
From: James Morse @ 2016-12-02 16:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202164247.19496-1-james.morse@arm.com>
commit d08544127d9fb4505635e3cb6871fd50a42947bd upstream.
The suspend/resume path in kernel/sleep.S, as used by cpu-idle, does not
save/restore PSTATE. As a result of this cpufeatures that were detected
and have bits in PSTATE get lost when we resume from idle.
PAN will be re-enabled next time we return from user-space, but on a
preemptible kernel we may run work accessing user space before this point.
Add code to re-enable this feature in __cpu_suspend_exit().
Signed-off-by: James Morse <james.morse@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
[Removed UAO hooks and commit-message references: this feature is not
present in v4.4]
Signed-off-by: James Morse <james.morse@arm.com>
Cc: <stable@vger.kernel.org> # 4.4.35
---
arch/arm64/kernel/suspend.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index 1095aa483a1c..00c1372bf57b 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -1,7 +1,9 @@
#include <linux/ftrace.h>
#include <linux/percpu.h>
#include <linux/slab.h>
+#include <asm/alternative.h>
#include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
#include <asm/debug-monitors.h>
#include <asm/pgtable.h>
#include <asm/memory.h>
@@ -111,6 +113,13 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
/*
+ * PSTATE was not saved over suspend/resume, re-enable any
+ * detected features that might not have been set correctly.
+ */
+ asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,
+ CONFIG_ARM64_PAN));
+
+ /*
* Restore HW breakpoint registers to sane values
* before debug exceptions are possibly reenabled
* through local_dbg_restore.
--
2.10.1
^ permalink raw reply related
* [PATCH 2/2] ARM: omap: timers: reduce rating of gp_timer clocksource
From: Tony Lindgren @ 2016-12-02 16:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d3a71d3d-3015-bb1f-80a4-4bb9adecaa4c@ti.com>
* Grygorii Strashko <grygorii.strashko@ti.com> [161129 08:43]:
>
>
> On 11/24/2016 12:19 AM, Keerthy wrote:
> > From: Grygorii Strashko <grygorii.strashko@ti.com>
> >
> > Now ARM Global timer (rating 300) will not be selected as clocksource,
> > because it's initialized after OMAP GP Timer (rating 300) and
> > Timekeeping core will not allow to replace clocksource with new one if
> > both of them have the same rating.
> >
> > Reduce rating of OMAP GP Timer (300->290) when it's used as
> > clocksource device - this will allow to select ARM Global timer (300)
> > as clocksource when enabled.
> >
> > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
> > Signed-off-by: Keerthy <j-keerthy@ti.com>
>
> Unfortunately, this patch has dependency [1] and can't be used alone as
> it will cause ARM Global timer to be selected as clocksource
> always on am437x and this will kill cpuidle, because ARM Global timer
> is not in always_on domain.
>
> The intention of enabling ARM Global timer is only for non-pm aware use
> cases for RT-kernel latency improvement - where deep cpuidle states are not
> enabled.
Yeah we need to fix up things to be able to change the clocksource
in addition to clockevent. However, currently only cpuidle_coupled
knows when the whole system is idle, so quite a bit of work is
needed to do that in a sane way.
What about the first patch in this series?
Regards,
Tony
> [1] https://patchwork.kernel.org/patch/8940051/
>
> > ---
> > arch/arm/mach-omap2/timer.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> > index b2f2448..a0dbb0b 100644
> > --- a/arch/arm/mach-omap2/timer.c
> > +++ b/arch/arm/mach-omap2/timer.c
> > @@ -376,7 +376,7 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs)
> > }
> >
> > static struct clocksource clocksource_gpt = {
> > - .rating = 300,
> > + .rating = 290,
> > .read = clocksource_read_cycles,
> > .mask = CLOCKSOURCE_MASK(32),
> > .flags = CLOCK_SOURCE_IS_CONTINUOUS,
> >
>
> --
> regards,
> -grygorii
^ permalink raw reply
* [RFC PATCH 00/29] arm64: Scalable Vector Extension core support
From: Joseph Myers @ 2016-12-02 16:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <faabab1d-fafb-2bd1-200f-b0e3ba17e1d5@redhat.com>
On Fri, 2 Dec 2016, Florian Weimer wrote:
> > However, it would be necessary to prevent GCC from moving any code
> > across these statements -- in particular, SVE code that access VL-
> > dependent data spilled on the stack is liable to go wrong if reordered
> > with the above. So the sequence would need to go in an external
> > function (or a single asm...)
>
> I would talk to GCC folks?we have similar issues with changing the FPU
> rounding mode, I assume.
In general, GCC doesn't track the implicit uses of thread-local state
involved in floating-point exceptions and rounding modes, and so doesn't
avoid moving code across manipulations of such state; there are various
open bugs in this area (though many of the open bugs are for local rather
than global issues with code generation or local optimizations not
respecting exceptions and rounding modes, which are easier to fix). Hence
glibc using various macros such as math_opt_barrier and math_force_eval
which use asms to prevent such motion.
I'm not familiar enough with the optimizers to judge the right way to
address such issues with implicit use of thread-local state. And I
haven't thought much yet about how to implement TS 18661-1 constant
rounding modes, which would involve the compiler implicitly inserting
rounding modes changes, though I think it would be fairly straightforward
given underlying support for avoiding inappropriate code motion.
--
Joseph S. Myers
joseph at codesourcery.com
^ permalink raw reply
* [PATCH v2 1/2] arm64: dts: zx: Fix gic GICR property
From: Marc Zyngier @ 2016-12-02 17:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476361881-19685-2-git-send-email-jun.nie@linaro.org>
Just noticed this.
On 13/10/16 13:31, Jun Nie wrote:
> GICR for multiple CPU can be described with start address and stride,
> or with multiple address. Current multiple address and stride are
> both used. Fix it.
>
> vmalloc patch 727a7f5a9 triggered this bug:
> [ 0.097146] Unable to handle kernel paging request at virtual address ffff000008060008
> [ 0.097150] pgd = ffff000008602000
> [ 0.097160] [ffff000008060008] *pgd=000000007fffe003, *pud=000000007fffd003, *pmd=000000007fffc003, *pte=0000000000000000
> [ 0.097165] Internal error: Oops: 96000007 [#1] PREEMPT SMP
> [ 0.097170] Modules linked in:
> [ 0.097177] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0+ #1474
> [ 0.097179] Hardware name: ZTE zx296718 evaluation board (DT)
> [ 0.097183] task: ffff80003e8c8b80 task.stack: ffff80003e8d0000
> [ 0.097197] PC is at gic_populate_rdist+0x74/0x15c
> [ 0.097202] LR is at gic_starting_cpu+0xc/0x20
> [ 0.097206] pc : [<ffff0000082b1b18>] lr : [<ffff0000082b26e0>] pstate: 600001c5
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> arch/arm64/boot/dts/zte/zx296718.dtsi | 11 +++--------
> 1 file changed, 3 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/zte/zx296718.dtsi b/arch/arm64/boot/dts/zte/zx296718.dtsi
> index a223066..6b239a3 100644
> --- a/arch/arm64/boot/dts/zte/zx296718.dtsi
> +++ b/arch/arm64/boot/dts/zte/zx296718.dtsi
> @@ -239,16 +239,11 @@
> compatible = "arm,gic-v3";
> #interrupt-cells = <3>;
> #address-cells = <0>;
> - #redistributor-regions = <6>;
> - redistributor-stride = <0x0 0x40000>;
> + #redistributor-regions = <1>;
> + redistributor-stride = <0x20000>;
Why is that stride specified? Is the GIC implementation so busted that
the GICR_TYPER do not report a GICv3 redistributor, which implies a
128kB stride?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [stable:PATCH 0/3] PAN fixes backport for v4.4.35
From: Greg KH @ 2016-12-02 17:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202164247.19496-1-james.morse@arm.com>
On Fri, Dec 02, 2016 at 04:42:44PM +0000, James Morse wrote:
> Hi linux-stable,
>
> This is the backport of the recent PAN fixes series for v4.4.35.
> Original series:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-October/461806.html
Why just 4.4-stable? What about 4.8-stable?
thanks,
greg k-h
^ permalink raw reply
* [RFC PATCH 0/2] arm64: memory-hotplug: Add Memory Hotplug support
From: Scott Branden @ 2016-12-02 17:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <99a1ce87-2dfc-f6f8-353b-70fcd0b3a977@virtualopensystems.com>
Hi Maciej,
On 16-12-02 02:55 AM, Maciej Bielski wrote:
>
>
> On 02/12/2016 11:49, Will Deacon wrote:
>> On Fri, Dec 02, 2016 at 10:13:43AM +0100, Maciej Bielski wrote:
>>> Recently we have announced our effort on that:
>>> https://lkml.org/lkml/2016/11/17/49
>>>
>>> For now we have a working solution for hotplug and we are performing
>>> code cleanup to push the patches soon.
>> Are these intended to replace or extend Scott's patches? If the former,
>> please work with Scott's stuff as a base rather than posting a competing
>> series.
> In the piece of code provided by Scott I have seen similar steps to what
> is done by us but our work went further since we have the mapping
> created and everything is working via the sysfs interface. I am now
> having closer look and comparing them.
I would love to see the missing section mapping step and any other
additions to test out. Please send additions as soon as you have a chance.
Regards,
Scott
>>
>> Will
>
^ permalink raw reply
* XHCI controller does not detect USB key insertion
From: Mason @ 2016-12-02 17:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <96d38b62-135e-9787-e8b5-1ac3e820c23b@baylibre.com>
On 02/12/2016 14:46, Neil Armstrong wrote:
> On 12/02/2016 11:24 AM, Mason wrote:
>
>> (Sad face) All the documentation I have is in front of me, and nothing
>> is ringing a bell. This is a Sigma Designs SoC, with a Pravega XHCI
>> controller + Synopsys PHY.
>>
>> The documentation I have:
>>
>> Pravega_Dual_Mode_Datasheet_v10c.pdf (documents IP signals)
>> Pravega_Dual_Mode_Controller_Programmers_Reference_manual_v1.pdf (documents IP registers)
>> PHY databook (very low-level stuff)
>> SoC register mapping (for how the SoC maps the IP signals to registers)
>
> You should have all the necessary bits to enable and configure the Embedded Synopsys PHY !
>
> You should have some register mapping of the PHY signals, or at least a way to write those registers.
>
> You should have a reset, clock gate and eventually a power regulator to enable in order to have the PHY running.
I'll dump all the non-0 non-standard registers. Maybe someone
more experienced than me will spot an obvious mistake.
host_usb30_0_config: 0x2e800
- host_usb30_0_fladj 0x20
- host_usb30_0_usb30_controller_cg_disable 0x0
- host_usb30_0_mode_select 0x1
- host_usb30_0_device_reset_mode 0x0
host_usb30_0_control: 0x2e804
- host_usb30_0_app_lfps_u3_wp 0x0
- host_usb30_0_link_up 0x1
- host_usb30_0_msi_msg_sent 0x0
- host_usb30_0_usb3_p0_over_current 0x0
- host_usb30_0_usb2_p0_over_current 0x0
host_usb30_0_test: 0x2e808
- host_usb30_0_test_powerdown_hsp 0x0
- host_usb30_0_test_powerdown_ssp 0x0
- host_usb30_0_test_burnin 0x0
- host_usb30_0_acjt_level 0x14
- host_usb30_0_lane0_tx2rx_loopbk 0x0
- host_usb30_0_rtune_req 0x0
host_usb30_0_status: 0x2e80c
- host_usb30_0_phystatus 0x0
- host_usb30_0_usb2_p0_pp 0x1
- host_usb30_0_usb3_p0_pp 0x1
- host_usb30_0_usb3_sleep 0x0
- host_usb30_0_rtune_ack 0x0
host_usb30_0_clk_rst_0: 0x2e810
- host_usb30_0_commononn 0x1
- host_usb30_0_portreset 0x0
- host_usb30_0_refclksel 0x2
- host_usb30_0_teneable 0x1
- host_usb30_0_fsel 0x27
- host_usb30_0_mpll_multiplier 0x19
- host_usb30_0_ref_clkdiv2 0x0
- host_usb30_0_ref_ssp_en 0x1
- host_usb30_0_ref_use_pad 0x0
- host_usb30_0_ssc_en 0x1
- host_usb30_0_ssc_range 0x0
host_usb30_0_clk_rst_1: 0x2e814
- host_usb30_0_ssc_ref_clk_sel 0x88
- host_usb30_0_sleepm 0x1
- host_usb30_0_vbusvldext 0x1
host_usb30_0_param_0: 0x2e818
- host_usb30_0_compdistune 0x4
- host_usb30_0_otgtune 0x4
- host_usb30_0_sqrxtune 0x3
- host_usb30_0_txfsltune 0x3
- host_usb30_0_txhsxvtune 0x3
- host_usb30_0_txpreempltune 0x0
- host_usb30_0_txpreemppulsetune 0x0
- host_usb30_0_txrestune 0x1
- host_usb30_0_txrisetune 0x2
- host_usb30_0_txvreftune 0x4
host_usb30_0_param_1: 0x2e81c
- host_usb30_0_los_bias 0x5
- host_usb30_0_los_level 0xc
- host_usb30_0_pcs_rx_los_mask_val 0xf0
- host_usb30_0_pcs_tx_deemph_3p5db 0x18
- host_usb30_0_pcs_tx_deemph_6db 0x21
host_usb30_0_param_2: 0x2e820
- host_usb30_0_pcs_tx_swing_full 0x73
- host_usb30_0_lane0_tx_term_offset 0x0
- host_usb30_0_tx_vboost_lvl 0x4
host_usb30_0_SNPS_CR_ADD: 0x2e880
- host_usb30_0_snps_cr_add 0xe03c
DEVICE_AND_PORT_000: 0x70050000
- sw_reset 0x0
- gen_resume 0x0
- ss_support 0x0
- revision_id 0x0
- vendor_id 0x3
DEVICE_AND_PORT_00C: 0x7005000c
- set_isoc_delay 0x0
- utmi_vstatus 0x0
- utmi_vcontrolloadm 0x1
- utmi_vcontrol 0x0
- config_dev_speed 0x1
ENDP_CONFIG_020: 0x70050020
- burst_size 0x1
- max_packet_size_7_0 0x0
- rst_seq_num 0x0
- iso_xact_type 0x0
- stall 0x0
- max_pkt_size_10_8 0x2
- setup_reenable 0x0
- endp_enable 0x1
- endp_type 0x0
- endp_no 0x0
LTSSM_STATE_REGISTER: 0x70050220
- ltssm_state_status 0x4
- u1_enable 0x0
- u2_enable 0x0
- disable_scramble_lb 0x1
- lfps_ux_exit 0x0
- disable_scramble_request 0x0
- self_powered_device 0x0
- host_device 0x1
- send_warm_reseti 0x0
- send_hot_reset 0x0
- reg_lgo_u3 0x0
PHY_TIMER_REGISTER: 0x70050410
- u2_inactivity_timeout 0x0
- pending_hp_time_out 0x2a
- recv_resume 0x0
- auto_resume 0x0
- credit_hp_timer 0x46
- usb3_clk_pulse_256us 0x100
PM_LC_TIMER_REGISTER: 0x70050418
- cntr_pulse_pm_lc_timer 0x2a
- cntr_pulse_pm_entry_timer 0x54
- lup_timeout_value 0xa
- no_link_commands_timeout_value 0xe
- pm_lc_timer_register_reserved 0x6e
LTSSM_TIMER_REGISTER1: 0x7005041c
- u1_exit_timeout 0x54
- u2_exit_timeout 0x54
- reg_12_ms_timeout 0xa8
LTSSM_TIMER_REGISTER2: 0x70050420
- reg_360_ms_timeout 0x34
- pipe_width 0x3
- reg_2_ms_timeout 0x3c
- rxeq_timeout 0xffff
LTSSM_TIMER_REGISTER3: 0x70050424
- reg_6_ms_timeout 0x54
- reg_300_ms_timeout 0x149
- reg_100_ms_timeout 0x8c
- ltssm_timer_reg3_undef 0x0
LOW_POWER_LFPS_SIGNALING_REGISTER: 0x70050434
- low_power_lfps_signaling_register_value 0x4e030303
- low_power_lfps_undef 0x0
PING_POLLING_LFPS_SIGNALING_REGISTER: 0x70050440
- ping_polling_lfps_signaling_register 0x9f5beebc
WARM_RESET_LFPS_SIGNALING_REGISTER: 0x70050444
- lfps_rx_trepeat_polling 0x5
- lfps_wr_undef 0x0
- lfps_wr_tresetdelay_min 0x12
- lfps_wr_tresetdelay_max 0x0
- lfps_wr_treset_total 0x76
LOW_POWER_LFPS_SIGNALING_REGISTER1: 0x70050448
- lfp_rx_undef 0x0
- lfps_rx_u2_t13_t11 0x12
- lfps_rx_u3_t13_t11 0x62
- lfps_rx_u1_t13_t11 0x7
- lfps_tx_u1_t11_t10 0xe
- lfps_tx_u1_t12_t11 0x8
- lfps_tx_u1_t11_t10_7_4 0x1
LOW_POWER_LFPS_SIGNALING_REGISTER2: 0x7005044c
- low_power_lfps_signaling_register2 0xc34f07d0
LOW_POWER_LFPS_SIGNALING_REGISTER3: 0x70050450
- low_power_lfps_signaling_register3 0xc34f07d0
TIMER_ENABLE_REGISTERS: 0x70050454
- pravega_counter_pulse_1us 0x9
- pravega_counter_pulse_10us 0x9
- pravega_counter_pulse_1ms 0x9
- pravega_counter_pulse_100us 0x9
- pravega_counter_pulse_10ms 0x9
- counter_pulse_100ns 0x14
I'll take a closer look on Monday.
Regards.
^ permalink raw reply
* [PATCH 3/8] rtc: add STM32 RTC driver
From: Mathieu Poirier @ 2016-12-02 17:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480687801-19525-5-git-send-email-amelie.delaunay@st.com>
On Fri, Dec 02, 2016 at 03:09:56PM +0100, Amelie Delaunay wrote:
> This patch adds support for the STM32 RTC.
Hello Amelie,
>
> Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
> ---
> drivers/rtc/Kconfig | 10 +
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-stm32.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 788 insertions(+)
> create mode 100644 drivers/rtc/rtc-stm32.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index e859d14..dd8b218 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1706,6 +1706,16 @@ config RTC_DRV_PIC32
> This driver can also be built as a module. If so, the module
> will be called rtc-pic32
>
> +config RTC_DRV_STM32
> + tristate "STM32 On-Chip RTC"
> + depends on ARCH_STM32
> + help
> + If you say yes here you get support for the STM32 On-Chip
> + Real Time Clock.
> +
> + This driver can also be built as a module, if so, the module
> + will be called "rtc-stm32".
> +
> comment "HID Sensor RTC drivers"
>
> config RTC_DRV_HID_SENSOR_TIME
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 1ac694a..87bd9cc 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
> obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
> obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
> obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
> +obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
> obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
> obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
> obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
> diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
> new file mode 100644
> index 0000000..9e710ff
> --- /dev/null
> +++ b/drivers/rtc/rtc-stm32.c
> @@ -0,0 +1,777 @@
> +/*
> + * Copyright (C) Amelie Delaunay 2015
> + * Author: Amelie Delaunay <adelaunay.stm32@gmail.com>
> + * License terms: GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/clk.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/rtc.h>
> +#include <linux/spinlock.h>
> +
> +#define DRIVER_NAME "stm32_rtc"
> +
> +/* STM32 RTC registers */
> +#define STM32_RTC_TR 0x00
> +#define STM32_RTC_DR 0x04
> +#define STM32_RTC_CR 0x08
> +#define STM32_RTC_ISR 0x0C
> +#define STM32_RTC_PRER 0x10
> +#define STM32_RTC_ALRMAR 0x1C
> +#define STM32_RTC_WPR 0x24
> +
> +/* STM32_RTC_TR bit fields */
> +#define STM32_RTC_TR_SEC_SHIFT 0
> +#define STM32_RTC_TR_SEC GENMASK(6, 0)
> +#define STM32_RTC_TR_MIN_SHIFT 8
> +#define STM32_RTC_TR_MIN GENMASK(14, 8)
> +#define STM32_RTC_TR_HOUR_SHIFT 16
> +#define STM32_RTC_TR_HOUR GENMASK(21, 16)
> +
> +/* STM32_RTC_DR bit fields */
> +#define STM32_RTC_DR_DATE_SHIFT 0
> +#define STM32_RTC_DR_DATE GENMASK(5, 0)
> +#define STM32_RTC_DR_MONTH_SHIFT 8
> +#define STM32_RTC_DR_MONTH GENMASK(11, 8)
> +#define STM32_RTC_DR_WDAY_SHIFT 13
> +#define STM32_RTC_DR_WDAY GENMASK(15, 13)
> +#define STM32_RTC_DR_YEAR_SHIFT 16
> +#define STM32_RTC_DR_YEAR GENMASK(23, 16)
> +
> +/* STM32_RTC_CR bit fields */
> +#define STM32_RTC_CR_FMT BIT(6)
> +#define STM32_RTC_CR_ALRAE BIT(8)
> +#define STM32_RTC_CR_ALRAIE BIT(12)
> +
> +/* STM32_RTC_ISR bit fields */
> +#define STM32_RTC_ISR_ALRAWF BIT(0)
> +#define STM32_RTC_ISR_INITS BIT(4)
> +#define STM32_RTC_ISR_RSF BIT(5)
> +#define STM32_RTC_ISR_INITF BIT(6)
> +#define STM32_RTC_ISR_INIT BIT(7)
> +#define STM32_RTC_ISR_ALRAF BIT(8)
> +
> +/* STM32_RTC_PRER bit fields */
> +#define STM32_RTC_PRER_PRED_S_SHIFT 0
> +#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
> +#define STM32_RTC_PRER_PRED_A_SHIFT 16
> +#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
> +
> +/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
> +#define STM32_RTC_ALRMXR_SEC_SHIFT 0
> +#define STM32_RTC_ALRMXR_SEC GENMASK(6, 0)
> +#define STM32_RTC_ALRMXR_SEC_MASK BIT(7)
> +#define STM32_RTC_ALRMXR_MIN_SHIFT 8
> +#define STM32_RTC_ALRMXR_MIN GENMASK(14, 8)
> +#define STM32_RTC_ALRMXR_MIN_MASK BIT(15)
> +#define STM32_RTC_ALRMXR_HOUR_SHIFT 16
> +#define STM32_RTC_ALRMXR_HOUR GENMASK(21, 16)
> +#define STM32_RTC_ALRMXR_PM BIT(22)
> +#define STM32_RTC_ALRMXR_HOUR_MASK BIT(23)
> +#define STM32_RTC_ALRMXR_DATE_SHIFT 24
> +#define STM32_RTC_ALRMXR_DATE GENMASK(29, 24)
> +#define STM32_RTC_ALRMXR_WDSEL BIT(30)
> +#define STM32_RTC_ALRMXR_WDAY_SHIFT 24
> +#define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24)
> +#define STM32_RTC_ALRMXR_DATE_MASK BIT(31)
> +
> +/* STM32_RTC_WPR key constants */
> +#define RTC_WPR_1ST_KEY 0xCA
> +#define RTC_WPR_2ND_KEY 0x53
> +#define RTC_WPR_WRONG_KEY 0xFF
> +
> +/*
> + * RTC registers are protected agains parasitic write access.
> + * PWR_CR_DBP bit must be set to enable write access to RTC registers.
> + */
> +/* STM32_PWR_CR */
> +#define PWR_CR 0x00
> +/* STM32_PWR_CR bit field */
> +#define PWR_CR_DBP BIT(8)
> +
> +static struct regmap *dbp;
> +
> +struct stm32_rtc {
> + struct rtc_device *rtc_dev;
> + void __iomem *base;
> + struct clk *pclk;
> + struct clk *ck_rtc;
> + unsigned int clksrc;
> + spinlock_t lock; /* Protects registers accesses */
> + int irq_alarm;
> + struct regmap *pwrcr;
> +};
> +
> +static inline unsigned int stm32_rtc_readl(struct stm32_rtc *rtc,
> + unsigned int offset)
> +{
> + return readl_relaxed(rtc->base + offset);
> +}
> +
> +static inline void stm32_rtc_writel(struct stm32_rtc *rtc,
> + unsigned int offset, unsigned int value)
> +{
> + writel_relaxed(value, rtc->base + offset);
> +}
I'm not sure wrapping the readl/writel_relaxed function does anything special
other than simply redirecting the reader to another section of the code.
> +
> +static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
> +{
> +// if (dbp)
> +// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
Did checkpatch let you get away with this? What did you intend to do here?
> +
> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_1ST_KEY);
> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_2ND_KEY);
> +}
> +
> +static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
> +{
> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_WRONG_KEY);
> +
> +// if (dbp)
> +// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +}
> +
> +static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
> +{
> + unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + if (!(isr & STM32_RTC_ISR_INITF)) {
> + isr |= STM32_RTC_ISR_INIT;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + return readl_relaxed_poll_timeout_atomic(
> + rtc->base + STM32_RTC_ISR,
> + isr, (isr & STM32_RTC_ISR_INITF),
> + 10, 100000);
When using hard coded numerics please add comments that explains the reason
behind the selected values.
> + }
> +
> + return 0;
> +}
> +
> +static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
> +{
> + unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + isr &= ~STM32_RTC_ISR_INIT;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +}
> +
> +static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
> +{
> + unsigned int isr;
> +
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + isr &= ~STM32_RTC_ISR_RSF;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + /* Wait the registers to be synchronised */
> + return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> + isr,
> + (isr & STM32_RTC_ISR_RSF),
> + 10, 100000);
Shouldn't the break condition be !((isr & STM32_RTC_ISR_RSF) ? If not this
probably deserve a better comment.
> +}
> +
> +static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
> +{
> + struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
> + unsigned long irqflags, events = 0;
> + unsigned int isr, cr;
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +
> + if ((isr & STM32_RTC_ISR_ALRAF) &&
> + (cr & STM32_RTC_CR_ALRAIE)) {
> + /* Alarm A flag - Alarm interrupt */
> + events |= RTC_IRQF | RTC_AF;
> + isr &= ~STM32_RTC_ISR_ALRAF;
> + }
> +
> + /* Clear event irqflags, otherwise new events won't be received */
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + if (events) {
> + dev_info(&rtc->rtc_dev->dev, "Alarm occurred\n");
> +
> + /* Pass event to the kernel */
> + rtc_update_irq(rtc->rtc_dev, 1, events);
> + return IRQ_HANDLED;
> + } else {
> + return IRQ_NONE;
> + }
> +}
> +
> +/* Convert rtc_time structure from bin to bcd format */
> +static void tm2bcd(struct rtc_time *tm)
> +{
> + tm->tm_sec = bin2bcd(tm->tm_sec);
> + tm->tm_min = bin2bcd(tm->tm_min);
> + tm->tm_hour = bin2bcd(tm->tm_hour);
> +
> + tm->tm_mday = bin2bcd(tm->tm_mday);
> + tm->tm_mon = bin2bcd(tm->tm_mon + 1);
> + tm->tm_year = bin2bcd(tm->tm_year - 100);
> + /*
> + * Number of days since Sunday
> + * - on kernel side, 0=Sunday...6=Saturday
> + * - on rtc side, 0=invalid,1=Monday...7=Sunday
> + */
> + tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
> +}
> +
> +/* Convert rtc_time structure from bcd to bin format */
> +static void bcd2tm(struct rtc_time *tm)
> +{
> + tm->tm_sec = bcd2bin(tm->tm_sec);
> + tm->tm_min = bcd2bin(tm->tm_min);
> + tm->tm_hour = bcd2bin(tm->tm_hour);
> +
> + tm->tm_mday = bcd2bin(tm->tm_mday);
> + tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
> + tm->tm_year = bcd2bin(tm->tm_year) + 100;
> + /*
> + * Number of days since Sunday
> + * - on kernel side, 0=Sunday...6=Saturday
> + * - on rtc side, 0=invalid,1=Monday...7=Sunday
> + */
> + tm->tm_wday %= 7;
> +}
> +
> +static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + unsigned int tr, dr;
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + /* Time and Date in BCD format */
> + tr = stm32_rtc_readl(rtc, STM32_RTC_TR);
> + dr = stm32_rtc_readl(rtc, STM32_RTC_DR);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
> + tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
> + tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
> +
> + tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
> + tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
> + tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
> + tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
> +
> + /* We don't report tm_yday and tm_isdst */
> +
> + bcd2tm(tm);
> +
> + if (rtc_valid_tm(tm) < 0) {
> + dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + unsigned int tr, dr;
> + unsigned long irqflags;
> + int ret = 0;
> +
> + if (rtc_valid_tm(tm) < 0) {
> + dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
> + return -EINVAL;
> + }
> +
> + tm2bcd(tm);
> +
> + /* Time in BCD format */
> + tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
> + ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
> + ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
> +
> + /* Date in BCD format */
> + dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
> + ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
> + ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
> + ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + ret = stm32_rtc_enter_init_mode(rtc);
> + if (ret) {
> + dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
> + goto end;
> + }
> +
> + stm32_rtc_writel(rtc, STM32_RTC_TR, tr);
> + stm32_rtc_writel(rtc, STM32_RTC_DR, dr);
> +
> + stm32_rtc_exit_init_mode(rtc);
> +
> + ret = stm32_rtc_wait_sync(rtc);
> +end:
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return ret;
> +}
> +
> +static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + struct rtc_time *tm = &alrm->time;
> + unsigned int alrmar, cr, isr;
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + alrmar = stm32_rtc_readl(rtc, STM32_RTC_ALRMAR);
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
> + /*
> + * Date/day don't care in Alarm comparison so alarm triggers
> + * every day
> + */
> + tm->tm_mday = -1;
> + tm->tm_wday = -1;
> + } else {
> + if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
> + /* Alarm is set to a day of week */
> + tm->tm_mday = -1;
> + tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
> + STM32_RTC_ALRMXR_WDAY_SHIFT;
> + tm->tm_wday %= 7;
> + } else {
> + /* Alarm is set to a day of month */
> + tm->tm_wday = -1;
> + tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
> + STM32_RTC_ALRMXR_DATE_SHIFT;
> + }
> + }
> +
> + if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
> + /* Hours don't care in Alarm comparison */
> + tm->tm_hour = -1;
> + } else {
> + tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
> + STM32_RTC_ALRMXR_HOUR_SHIFT;
> + if (alrmar & STM32_RTC_ALRMXR_PM)
> + tm->tm_hour += 12;
> + }
> +
> + if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
> + /* Minutes don't care in Alarm comparison */
> + tm->tm_min = -1;
> + } else {
> + tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
> + STM32_RTC_ALRMXR_MIN_SHIFT;
> + }
> +
> + if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
> + /* Seconds don't care in Alarm comparison */
> + tm->tm_sec = -1;
> + } else {
> + tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
> + STM32_RTC_ALRMXR_SEC_SHIFT;
> + }
> +
> + bcd2tm(tm);
> +
> + alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
> + alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + unsigned long irqflags;
> + unsigned int isr, cr;
> +
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
Is the STM32_RTC_CR garanteed to be valid, i.e updated atomically? If not this
should probably be below the spinlock.
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + /* We expose Alarm A to the kernel */
> + if (enabled)
> + cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
> + else
> + cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> + /* Clear event irqflags, otherwise new events won't be received */
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> + isr &= ~STM32_RTC_ISR_ALRAF;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + struct rtc_time *tm = &alrm->time;
> + unsigned long irqflags;
> + unsigned int cr, isr, alrmar;
> + int ret = 0;
> +
> + if (rtc_valid_tm(tm)) {
> + dev_err(dev, "Alarm time not valid.\n");
> + return -EINVAL;
> + }
> +
> + tm2bcd(tm);
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + /* Disable Alarm */
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + cr &= ~STM32_RTC_CR_ALRAE;
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> + /* Poll Alarm write flag to be sure that Alarm update is allowed */
> + ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> + isr,
> + (isr & STM32_RTC_ISR_ALRAWF),
> + 10, 100);
> +
> + if (ret) {
> + dev_err(dev, "Alarm update not allowed\n");
> + goto end;
> + }
> +
> + alrmar = 0;
> +
> + if (tm->tm_mday < 0 && tm->tm_wday < 0) {
> + /*
> + * Date/day don't care in Alarm comparison so alarm triggers
> + * every day
> + */
> + alrmar |= STM32_RTC_ALRMXR_DATE_MASK;
> + } else {
> + if (tm->tm_mday > 0) {
> + /* Date is selected (ignoring wday) */
> + alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
> + STM32_RTC_ALRMXR_DATE;
> + } else {
> + /* Day of week is selected */
> + int wday = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
> +
> + alrmar |= STM32_RTC_ALRMXR_WDSEL;
> + alrmar |= (wday << STM32_RTC_ALRMXR_WDAY_SHIFT) &
> + STM32_RTC_ALRMXR_WDAY;
> + }
> + }
> +
> + if (tm->tm_hour < 0) {
> + /* Hours don't care in Alarm comparison */
> + alrmar |= STM32_RTC_ALRMXR_HOUR_MASK;
> + } else {
> + /* 24-hour format */
> + alrmar &= ~STM32_RTC_ALRMXR_PM;
> + alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
> + STM32_RTC_ALRMXR_HOUR;
> + }
> +
> + if (tm->tm_min < 0) {
> + /* Minutes don't care in Alarm comparison */
> + alrmar |= STM32_RTC_ALRMXR_MIN_MASK;
> + } else {
> + alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
> + STM32_RTC_ALRMXR_MIN;
> + }
> +
> + if (tm->tm_sec < 0) {
> + /* Seconds don't care in Alarm comparison */
> + alrmar |= STM32_RTC_ALRMXR_SEC_MASK;
> + } else {
> + alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
> + STM32_RTC_ALRMXR_SEC;
> + }
> +
> + /* Write to Alarm register */
> + stm32_rtc_writel(rtc, STM32_RTC_ALRMAR, alrmar);
> +
> + if (alrm->enabled)
> + stm32_rtc_alarm_irq_enable(dev, 1);
> + else
> + stm32_rtc_alarm_irq_enable(dev, 0);
> +
> +end:
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return ret;
> +}
> +
> +static const struct rtc_class_ops stm32_rtc_ops = {
> + .read_time = stm32_rtc_read_time,
> + .set_time = stm32_rtc_set_time,
> + .read_alarm = stm32_rtc_read_alarm,
> + .set_alarm = stm32_rtc_set_alarm,
> + .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
> +};
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_rtc_of_match[] = {
> + { .compatible = "st,stm32-rtc" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
> +#endif
> +
> +static int stm32_rtc_init(struct platform_device *pdev,
> + struct stm32_rtc *rtc)
> +{
> + unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
> + unsigned int rate;
> + unsigned long irqflags;
> + int ret = 0;
> +
> + rate = clk_get_rate(rtc->ck_rtc);
> +
> + /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
> + pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
> + pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
> +
> + for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
> + pred_s = (rate / (pred_a + 1)) - 1;
> +
> + if (((pred_s + 1) * (pred_a + 1)) == rate)
> + break;
> + }
> +
> + /*
> + * Can't find a 1Hz, so give priority to RTC power consumption
> + * by choosing the higher possible value for prediv_a
> + */
> + if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
> + pred_a = pred_a_max;
> + pred_s = (rate / (pred_a + 1)) - 1;
> +
> + dev_warn(&pdev->dev, "ck_rtc is %s\n",
> + (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
> + "fast" : "slow");
> + }
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + ret = stm32_rtc_enter_init_mode(rtc);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "Can't enter in init mode. Prescaler config failed.\n");
> + goto end;
> + }
> +
> + prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
> + stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> + prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
> + stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> +
> + /* Force 24h time format */
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + cr &= ~STM32_RTC_CR_FMT;
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> + stm32_rtc_exit_init_mode(rtc);
> +
> + ret = stm32_rtc_wait_sync(rtc);
> +
> + if (stm32_rtc_readl(rtc, STM32_RTC_ISR) & STM32_RTC_ISR_INITS)
> + dev_warn(&pdev->dev, "Date/Time must be initialized\n");
> +end:
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return ret;
> +}
> +
> +static int stm32_rtc_probe(struct platform_device *pdev)
> +{
> + struct stm32_rtc *rtc;
> + struct resource *res;
> + int ret;
> +
> + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
> + if (!rtc)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
The value of 'res' should be checked before using it.
> + rtc->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(rtc->base))
> + return PTR_ERR(rtc->base);
> +
> + dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "st,syscfg");
> + if (IS_ERR(dbp)) {
> + dev_err(&pdev->dev, "no st,syscfg\n");
> + return PTR_ERR(dbp);
> + }
> +
> + spin_lock_init(&rtc->lock);
> +
> + rtc->ck_rtc = devm_clk_get(&pdev->dev, "ck_rtc");
> + if (IS_ERR(rtc->ck_rtc)) {
> + dev_err(&pdev->dev, "no ck_rtc clock");
> + return PTR_ERR(rtc->ck_rtc);
> + }
> +
> + ret = clk_prepare_enable(rtc->ck_rtc);
> + if (ret)
> + return ret;
> +
> + if (dbp)
> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
The code above exits if there is a problem with the dbp, there is no point in
checking again.
> +
> + ret = stm32_rtc_init(pdev, rtc);
> + if (ret)
> + goto err;
> +
> + rtc->irq_alarm = platform_get_irq_byname(pdev, "alarm");
> + if (rtc->irq_alarm <= 0) {
> + dev_err(&pdev->dev, "no alarm irq\n");
> + ret = -ENOENT;
> + goto err;
> + }
> +
> + platform_set_drvdata(pdev, rtc);
> +
> + device_init_wakeup(&pdev->dev, true);
What happens if device_init_wakeup() returns an error?
> +
> + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
> + &stm32_rtc_ops, THIS_MODULE);
> + if (IS_ERR(rtc->rtc_dev)) {
> + ret = PTR_ERR(rtc->rtc_dev);
> + dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
> + ret);
> + goto err;
> + }
> +
> + /* Handle RTC alarm interrupts */
> + ret = devm_request_irq(&pdev->dev, rtc->irq_alarm,
> + stm32_rtc_alarm_irq, IRQF_TRIGGER_RISING,
> + dev_name(&rtc->rtc_dev->dev), rtc);
> + if (ret) {
> + dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
> + rtc->irq_alarm);
> + goto err;
> + }
> +
> + return 0;
> +err:
> + clk_disable_unprepare(rtc->ck_rtc);
> +
> + if (dbp)
> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
Same comment as above.
> +
> + device_init_wakeup(&pdev->dev, false);
> +
> + return ret;
> +}
> +
> +static int __exit stm32_rtc_remove(struct platform_device *pdev)
> +{
> + struct stm32_rtc *rtc = platform_get_drvdata(pdev);
> + unsigned int cr;
> +
> + /* Disable interrupts */
> + stm32_rtc_wpr_unlock(rtc);
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + cr &= ~STM32_RTC_CR_ALRAIE;
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> + stm32_rtc_wpr_lock(rtc);
> +
> + clk_disable_unprepare(rtc->ck_rtc);
> +
> + /* Enable backup domain write protection */
> + if (dbp)
> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +
> + device_init_wakeup(&pdev->dev, false);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int stm32_rtc_suspend(struct device *dev)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev))
> + return enable_irq_wake(rtc->irq_alarm);
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_resume(struct device *dev)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + ret = stm32_rtc_wait_sync(rtc);
> + if (ret < 0)
> + return ret;
> +
> + if (device_may_wakeup(dev))
> + return disable_irq_wake(rtc->irq_alarm);
> +
> + return ret;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
> + stm32_rtc_suspend, stm32_rtc_resume);
> +
> +static struct platform_driver stm32_rtc_driver = {
> + .probe = stm32_rtc_probe,
> + .remove = stm32_rtc_remove,
> + .driver = {
> + .name = DRIVER_NAME,
> + .pm = &stm32_rtc_pm_ops,
> + .of_match_table = stm32_rtc_of_match,
> + },
> +};
> +
> +module_platform_driver(stm32_rtc_driver);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.9.1
>
^ permalink raw reply
* XHCI controller does not detect USB key insertion
From: Mason @ 2016-12-02 18:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <96d38b62-135e-9787-e8b5-1ac3e820c23b@baylibre.com>
[ Fix incorrect address for Felipe ]
On 02/12/2016 14:46, Neil Armstrong wrote:
> On 12/02/2016 11:24 AM, Mason wrote:
>
>> (Sad face) All the documentation I have is in front of me, and nothing
>> is ringing a bell. This is a Sigma Designs SoC, with a Pravega XHCI
>> controller + Synopsys PHY.
>>
>> The documentation I have:
>>
>> Pravega_Dual_Mode_Datasheet_v10c.pdf (documents IP signals)
>> Pravega_Dual_Mode_Controller_Programmers_Reference_manual_v1.pdf (documents IP registers)
>> PHY databook (very low-level stuff)
>> SoC register mapping (for how the SoC maps the IP signals to registers)
>
> You should have all the necessary bits to enable and configure the Embedded Synopsys PHY !
>
> You should have some register mapping of the PHY signals, or at least a way to write those registers.
>
> You should have a reset, clock gate and eventually a power regulator to enable in order to have the PHY running.
I'll dump all the non-0 non-standard registers. Maybe someone
more experienced than me will spot an obvious mistake.
host_usb30_0_config: 0x2e800
- host_usb30_0_fladj 0x20
- host_usb30_0_usb30_controller_cg_disable 0x0
- host_usb30_0_mode_select 0x1
- host_usb30_0_device_reset_mode 0x0
host_usb30_0_control: 0x2e804
- host_usb30_0_app_lfps_u3_wp 0x0
- host_usb30_0_link_up 0x1
- host_usb30_0_msi_msg_sent 0x0
- host_usb30_0_usb3_p0_over_current 0x0
- host_usb30_0_usb2_p0_over_current 0x0
host_usb30_0_test: 0x2e808
- host_usb30_0_test_powerdown_hsp 0x0
- host_usb30_0_test_powerdown_ssp 0x0
- host_usb30_0_test_burnin 0x0
- host_usb30_0_acjt_level 0x14
- host_usb30_0_lane0_tx2rx_loopbk 0x0
- host_usb30_0_rtune_req 0x0
host_usb30_0_status: 0x2e80c
- host_usb30_0_phystatus 0x0
- host_usb30_0_usb2_p0_pp 0x1
- host_usb30_0_usb3_p0_pp 0x1
- host_usb30_0_usb3_sleep 0x0
- host_usb30_0_rtune_ack 0x0
host_usb30_0_clk_rst_0: 0x2e810
- host_usb30_0_commononn 0x1
- host_usb30_0_portreset 0x0
- host_usb30_0_refclksel 0x2
- host_usb30_0_teneable 0x1
- host_usb30_0_fsel 0x27
- host_usb30_0_mpll_multiplier 0x19
- host_usb30_0_ref_clkdiv2 0x0
- host_usb30_0_ref_ssp_en 0x1
- host_usb30_0_ref_use_pad 0x0
- host_usb30_0_ssc_en 0x1
- host_usb30_0_ssc_range 0x0
host_usb30_0_clk_rst_1: 0x2e814
- host_usb30_0_ssc_ref_clk_sel 0x88
- host_usb30_0_sleepm 0x1
- host_usb30_0_vbusvldext 0x1
host_usb30_0_param_0: 0x2e818
- host_usb30_0_compdistune 0x4
- host_usb30_0_otgtune 0x4
- host_usb30_0_sqrxtune 0x3
- host_usb30_0_txfsltune 0x3
- host_usb30_0_txhsxvtune 0x3
- host_usb30_0_txpreempltune 0x0
- host_usb30_0_txpreemppulsetune 0x0
- host_usb30_0_txrestune 0x1
- host_usb30_0_txrisetune 0x2
- host_usb30_0_txvreftune 0x4
host_usb30_0_param_1: 0x2e81c
- host_usb30_0_los_bias 0x5
- host_usb30_0_los_level 0xc
- host_usb30_0_pcs_rx_los_mask_val 0xf0
- host_usb30_0_pcs_tx_deemph_3p5db 0x18
- host_usb30_0_pcs_tx_deemph_6db 0x21
host_usb30_0_param_2: 0x2e820
- host_usb30_0_pcs_tx_swing_full 0x73
- host_usb30_0_lane0_tx_term_offset 0x0
- host_usb30_0_tx_vboost_lvl 0x4
host_usb30_0_SNPS_CR_ADD: 0x2e880
- host_usb30_0_snps_cr_add 0xe03c
DEVICE_AND_PORT_000: 0x70050000
- sw_reset 0x0
- gen_resume 0x0
- ss_support 0x0
- revision_id 0x0
- vendor_id 0x3
DEVICE_AND_PORT_00C: 0x7005000c
- set_isoc_delay 0x0
- utmi_vstatus 0x0
- utmi_vcontrolloadm 0x1
- utmi_vcontrol 0x0
- config_dev_speed 0x1
ENDP_CONFIG_020: 0x70050020
- burst_size 0x1
- max_packet_size_7_0 0x0
- rst_seq_num 0x0
- iso_xact_type 0x0
- stall 0x0
- max_pkt_size_10_8 0x2
- setup_reenable 0x0
- endp_enable 0x1
- endp_type 0x0
- endp_no 0x0
LTSSM_STATE_REGISTER: 0x70050220
- ltssm_state_status 0x4
- u1_enable 0x0
- u2_enable 0x0
- disable_scramble_lb 0x1
- lfps_ux_exit 0x0
- disable_scramble_request 0x0
- self_powered_device 0x0
- host_device 0x1
- send_warm_reseti 0x0
- send_hot_reset 0x0
- reg_lgo_u3 0x0
PHY_TIMER_REGISTER: 0x70050410
- u2_inactivity_timeout 0x0
- pending_hp_time_out 0x2a
- recv_resume 0x0
- auto_resume 0x0
- credit_hp_timer 0x46
- usb3_clk_pulse_256us 0x100
PM_LC_TIMER_REGISTER: 0x70050418
- cntr_pulse_pm_lc_timer 0x2a
- cntr_pulse_pm_entry_timer 0x54
- lup_timeout_value 0xa
- no_link_commands_timeout_value 0xe
- pm_lc_timer_register_reserved 0x6e
LTSSM_TIMER_REGISTER1: 0x7005041c
- u1_exit_timeout 0x54
- u2_exit_timeout 0x54
- reg_12_ms_timeout 0xa8
LTSSM_TIMER_REGISTER2: 0x70050420
- reg_360_ms_timeout 0x34
- pipe_width 0x3
- reg_2_ms_timeout 0x3c
- rxeq_timeout 0xffff
LTSSM_TIMER_REGISTER3: 0x70050424
- reg_6_ms_timeout 0x54
- reg_300_ms_timeout 0x149
- reg_100_ms_timeout 0x8c
- ltssm_timer_reg3_undef 0x0
LOW_POWER_LFPS_SIGNALING_REGISTER: 0x70050434
- low_power_lfps_signaling_register_value 0x4e030303
- low_power_lfps_undef 0x0
PING_POLLING_LFPS_SIGNALING_REGISTER: 0x70050440
- ping_polling_lfps_signaling_register 0x9f5beebc
WARM_RESET_LFPS_SIGNALING_REGISTER: 0x70050444
- lfps_rx_trepeat_polling 0x5
- lfps_wr_undef 0x0
- lfps_wr_tresetdelay_min 0x12
- lfps_wr_tresetdelay_max 0x0
- lfps_wr_treset_total 0x76
LOW_POWER_LFPS_SIGNALING_REGISTER1: 0x70050448
- lfp_rx_undef 0x0
- lfps_rx_u2_t13_t11 0x12
- lfps_rx_u3_t13_t11 0x62
- lfps_rx_u1_t13_t11 0x7
- lfps_tx_u1_t11_t10 0xe
- lfps_tx_u1_t12_t11 0x8
- lfps_tx_u1_t11_t10_7_4 0x1
LOW_POWER_LFPS_SIGNALING_REGISTER2: 0x7005044c
- low_power_lfps_signaling_register2 0xc34f07d0
LOW_POWER_LFPS_SIGNALING_REGISTER3: 0x70050450
- low_power_lfps_signaling_register3 0xc34f07d0
TIMER_ENABLE_REGISTERS: 0x70050454
- pravega_counter_pulse_1us 0x9
- pravega_counter_pulse_10us 0x9
- pravega_counter_pulse_1ms 0x9
- pravega_counter_pulse_100us 0x9
- pravega_counter_pulse_10ms 0x9
- counter_pulse_100ns 0x14
I'll take a closer look on Monday.
Regards.
^ permalink raw reply
* [PATCH 2/2] ARM: omap: timers: reduce rating of gp_timer clocksource
From: Grygorii Strashko @ 2016-12-02 18:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202164714.GB4705@atomide.com>
On 12/02/2016 10:47 AM, Tony Lindgren wrote:
> * Grygorii Strashko <grygorii.strashko@ti.com> [161129 08:43]:
>>
>>
>> On 11/24/2016 12:19 AM, Keerthy wrote:
>>> From: Grygorii Strashko <grygorii.strashko@ti.com>
>>>
>>> Now ARM Global timer (rating 300) will not be selected as clocksource,
>>> because it's initialized after OMAP GP Timer (rating 300) and
>>> Timekeeping core will not allow to replace clocksource with new one if
>>> both of them have the same rating.
>>>
>>> Reduce rating of OMAP GP Timer (300->290) when it's used as
>>> clocksource device - this will allow to select ARM Global timer (300)
>>> as clocksource when enabled.
>>>
>>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>>> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
>>> Signed-off-by: Keerthy <j-keerthy@ti.com>
>>
>> Unfortunately, this patch has dependency [1] and can't be used alone as
>> it will cause ARM Global timer to be selected as clocksource
>> always on am437x and this will kill cpuidle, because ARM Global timer
>> is not in always_on domain.
>>
>> The intention of enabling ARM Global timer is only for non-pm aware use
>> cases for RT-kernel latency improvement - where deep cpuidle states are not
>> enabled.
>
> Yeah we need to fix up things to be able to change the clocksource
> in addition to clockevent. However, currently only cpuidle_coupled
> knows when the whole system is idle, so quite a bit of work is
> needed to do that in a sane way.
Also sched_clock and timer_delay ;)
>
> What about the first patch in this series?
>
Fist one is ok. It was originally posted long time ago.
--
regards,
-grygorii
^ permalink raw reply
* [PATCH 3/8] rtc: add STM32 RTC driver
From: Mathieu Poirier @ 2016-12-02 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480687801-19525-5-git-send-email-amelie.delaunay@st.com>
On Fri, Dec 02, 2016 at 03:09:56PM +0100, Amelie Delaunay wrote:
> This patch adds support for the STM32 RTC.
>
> Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
> ---
> drivers/rtc/Kconfig | 10 +
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-stm32.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 788 insertions(+)
> create mode 100644 drivers/rtc/rtc-stm32.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index e859d14..dd8b218 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1706,6 +1706,16 @@ config RTC_DRV_PIC32
> This driver can also be built as a module. If so, the module
> will be called rtc-pic32
>
> +config RTC_DRV_STM32
> + tristate "STM32 On-Chip RTC"
> + depends on ARCH_STM32
> + help
> + If you say yes here you get support for the STM32 On-Chip
> + Real Time Clock.
> +
> + This driver can also be built as a module, if so, the module
> + will be called "rtc-stm32".
> +
> comment "HID Sensor RTC drivers"
>
> config RTC_DRV_HID_SENSOR_TIME
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 1ac694a..87bd9cc 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
> obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
> obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
> obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
> +obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
> obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
> obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
> obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
> diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
> new file mode 100644
> index 0000000..9e710ff
> --- /dev/null
> +++ b/drivers/rtc/rtc-stm32.c
> @@ -0,0 +1,777 @@
> +/*
> + * Copyright (C) Amelie Delaunay 2015
> + * Author: Amelie Delaunay <adelaunay.stm32@gmail.com>
> + * License terms: GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/clk.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/rtc.h>
> +#include <linux/spinlock.h>
> +
> +#define DRIVER_NAME "stm32_rtc"
> +
> +/* STM32 RTC registers */
> +#define STM32_RTC_TR 0x00
> +#define STM32_RTC_DR 0x04
> +#define STM32_RTC_CR 0x08
> +#define STM32_RTC_ISR 0x0C
> +#define STM32_RTC_PRER 0x10
> +#define STM32_RTC_ALRMAR 0x1C
> +#define STM32_RTC_WPR 0x24
> +
> +/* STM32_RTC_TR bit fields */
> +#define STM32_RTC_TR_SEC_SHIFT 0
> +#define STM32_RTC_TR_SEC GENMASK(6, 0)
> +#define STM32_RTC_TR_MIN_SHIFT 8
> +#define STM32_RTC_TR_MIN GENMASK(14, 8)
> +#define STM32_RTC_TR_HOUR_SHIFT 16
> +#define STM32_RTC_TR_HOUR GENMASK(21, 16)
> +
> +/* STM32_RTC_DR bit fields */
> +#define STM32_RTC_DR_DATE_SHIFT 0
> +#define STM32_RTC_DR_DATE GENMASK(5, 0)
> +#define STM32_RTC_DR_MONTH_SHIFT 8
> +#define STM32_RTC_DR_MONTH GENMASK(11, 8)
> +#define STM32_RTC_DR_WDAY_SHIFT 13
> +#define STM32_RTC_DR_WDAY GENMASK(15, 13)
> +#define STM32_RTC_DR_YEAR_SHIFT 16
> +#define STM32_RTC_DR_YEAR GENMASK(23, 16)
> +
> +/* STM32_RTC_CR bit fields */
> +#define STM32_RTC_CR_FMT BIT(6)
> +#define STM32_RTC_CR_ALRAE BIT(8)
> +#define STM32_RTC_CR_ALRAIE BIT(12)
> +
> +/* STM32_RTC_ISR bit fields */
> +#define STM32_RTC_ISR_ALRAWF BIT(0)
> +#define STM32_RTC_ISR_INITS BIT(4)
> +#define STM32_RTC_ISR_RSF BIT(5)
> +#define STM32_RTC_ISR_INITF BIT(6)
> +#define STM32_RTC_ISR_INIT BIT(7)
> +#define STM32_RTC_ISR_ALRAF BIT(8)
> +
> +/* STM32_RTC_PRER bit fields */
> +#define STM32_RTC_PRER_PRED_S_SHIFT 0
> +#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
> +#define STM32_RTC_PRER_PRED_A_SHIFT 16
> +#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
> +
> +/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
> +#define STM32_RTC_ALRMXR_SEC_SHIFT 0
> +#define STM32_RTC_ALRMXR_SEC GENMASK(6, 0)
> +#define STM32_RTC_ALRMXR_SEC_MASK BIT(7)
> +#define STM32_RTC_ALRMXR_MIN_SHIFT 8
> +#define STM32_RTC_ALRMXR_MIN GENMASK(14, 8)
> +#define STM32_RTC_ALRMXR_MIN_MASK BIT(15)
> +#define STM32_RTC_ALRMXR_HOUR_SHIFT 16
> +#define STM32_RTC_ALRMXR_HOUR GENMASK(21, 16)
> +#define STM32_RTC_ALRMXR_PM BIT(22)
> +#define STM32_RTC_ALRMXR_HOUR_MASK BIT(23)
> +#define STM32_RTC_ALRMXR_DATE_SHIFT 24
> +#define STM32_RTC_ALRMXR_DATE GENMASK(29, 24)
> +#define STM32_RTC_ALRMXR_WDSEL BIT(30)
> +#define STM32_RTC_ALRMXR_WDAY_SHIFT 24
> +#define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24)
> +#define STM32_RTC_ALRMXR_DATE_MASK BIT(31)
> +
> +/* STM32_RTC_WPR key constants */
> +#define RTC_WPR_1ST_KEY 0xCA
> +#define RTC_WPR_2ND_KEY 0x53
> +#define RTC_WPR_WRONG_KEY 0xFF
> +
> +/*
> + * RTC registers are protected agains parasitic write access.
> + * PWR_CR_DBP bit must be set to enable write access to RTC registers.
> + */
> +/* STM32_PWR_CR */
> +#define PWR_CR 0x00
> +/* STM32_PWR_CR bit field */
> +#define PWR_CR_DBP BIT(8)
> +
> +static struct regmap *dbp;
> +
> +struct stm32_rtc {
> + struct rtc_device *rtc_dev;
> + void __iomem *base;
> + struct clk *pclk;
> + struct clk *ck_rtc;
> + unsigned int clksrc;
> + spinlock_t lock; /* Protects registers accesses */
> + int irq_alarm;
> + struct regmap *pwrcr;
> +};
One more thing... What did you want to do with pclk, clksrc and pwrcr? They
aren't used in the driver. If this is for future enhancement I suggest you
introduce those when you submit the patches.
> +
> +static inline unsigned int stm32_rtc_readl(struct stm32_rtc *rtc,
> + unsigned int offset)
> +{
> + return readl_relaxed(rtc->base + offset);
> +}
> +
> +static inline void stm32_rtc_writel(struct stm32_rtc *rtc,
> + unsigned int offset, unsigned int value)
> +{
> + writel_relaxed(value, rtc->base + offset);
> +}
> +
> +static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
> +{
> +// if (dbp)
> +// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
> +
> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_1ST_KEY);
> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_2ND_KEY);
> +}
> +
> +static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
> +{
> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_WRONG_KEY);
> +
> +// if (dbp)
> +// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +}
> +
> +static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
> +{
> + unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + if (!(isr & STM32_RTC_ISR_INITF)) {
> + isr |= STM32_RTC_ISR_INIT;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + return readl_relaxed_poll_timeout_atomic(
> + rtc->base + STM32_RTC_ISR,
> + isr, (isr & STM32_RTC_ISR_INITF),
> + 10, 100000);
> + }
> +
> + return 0;
> +}
> +
> +static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
> +{
> + unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + isr &= ~STM32_RTC_ISR_INIT;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +}
> +
> +static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
> +{
> + unsigned int isr;
> +
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + isr &= ~STM32_RTC_ISR_RSF;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + /* Wait the registers to be synchronised */
> + return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> + isr,
> + (isr & STM32_RTC_ISR_RSF),
> + 10, 100000);
> +}
> +
> +static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
> +{
> + struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
> + unsigned long irqflags, events = 0;
> + unsigned int isr, cr;
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +
> + if ((isr & STM32_RTC_ISR_ALRAF) &&
> + (cr & STM32_RTC_CR_ALRAIE)) {
> + /* Alarm A flag - Alarm interrupt */
> + events |= RTC_IRQF | RTC_AF;
> + isr &= ~STM32_RTC_ISR_ALRAF;
> + }
> +
> + /* Clear event irqflags, otherwise new events won't be received */
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + if (events) {
> + dev_info(&rtc->rtc_dev->dev, "Alarm occurred\n");
> +
> + /* Pass event to the kernel */
> + rtc_update_irq(rtc->rtc_dev, 1, events);
> + return IRQ_HANDLED;
> + } else {
> + return IRQ_NONE;
> + }
> +}
> +
> +/* Convert rtc_time structure from bin to bcd format */
> +static void tm2bcd(struct rtc_time *tm)
> +{
> + tm->tm_sec = bin2bcd(tm->tm_sec);
> + tm->tm_min = bin2bcd(tm->tm_min);
> + tm->tm_hour = bin2bcd(tm->tm_hour);
> +
> + tm->tm_mday = bin2bcd(tm->tm_mday);
> + tm->tm_mon = bin2bcd(tm->tm_mon + 1);
> + tm->tm_year = bin2bcd(tm->tm_year - 100);
> + /*
> + * Number of days since Sunday
> + * - on kernel side, 0=Sunday...6=Saturday
> + * - on rtc side, 0=invalid,1=Monday...7=Sunday
> + */
> + tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
> +}
> +
> +/* Convert rtc_time structure from bcd to bin format */
> +static void bcd2tm(struct rtc_time *tm)
> +{
> + tm->tm_sec = bcd2bin(tm->tm_sec);
> + tm->tm_min = bcd2bin(tm->tm_min);
> + tm->tm_hour = bcd2bin(tm->tm_hour);
> +
> + tm->tm_mday = bcd2bin(tm->tm_mday);
> + tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
> + tm->tm_year = bcd2bin(tm->tm_year) + 100;
> + /*
> + * Number of days since Sunday
> + * - on kernel side, 0=Sunday...6=Saturday
> + * - on rtc side, 0=invalid,1=Monday...7=Sunday
> + */
> + tm->tm_wday %= 7;
> +}
> +
> +static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + unsigned int tr, dr;
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + /* Time and Date in BCD format */
> + tr = stm32_rtc_readl(rtc, STM32_RTC_TR);
> + dr = stm32_rtc_readl(rtc, STM32_RTC_DR);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
> + tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
> + tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
> +
> + tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
> + tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
> + tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
> + tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
> +
> + /* We don't report tm_yday and tm_isdst */
> +
> + bcd2tm(tm);
> +
> + if (rtc_valid_tm(tm) < 0) {
> + dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + unsigned int tr, dr;
> + unsigned long irqflags;
> + int ret = 0;
> +
> + if (rtc_valid_tm(tm) < 0) {
> + dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
> + return -EINVAL;
> + }
> +
> + tm2bcd(tm);
> +
> + /* Time in BCD format */
> + tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
> + ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
> + ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
> +
> + /* Date in BCD format */
> + dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
> + ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
> + ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
> + ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + ret = stm32_rtc_enter_init_mode(rtc);
> + if (ret) {
> + dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
> + goto end;
> + }
> +
> + stm32_rtc_writel(rtc, STM32_RTC_TR, tr);
> + stm32_rtc_writel(rtc, STM32_RTC_DR, dr);
> +
> + stm32_rtc_exit_init_mode(rtc);
> +
> + ret = stm32_rtc_wait_sync(rtc);
> +end:
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return ret;
> +}
> +
> +static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + struct rtc_time *tm = &alrm->time;
> + unsigned int alrmar, cr, isr;
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + alrmar = stm32_rtc_readl(rtc, STM32_RTC_ALRMAR);
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
> + /*
> + * Date/day don't care in Alarm comparison so alarm triggers
> + * every day
> + */
> + tm->tm_mday = -1;
> + tm->tm_wday = -1;
> + } else {
> + if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
> + /* Alarm is set to a day of week */
> + tm->tm_mday = -1;
> + tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
> + STM32_RTC_ALRMXR_WDAY_SHIFT;
> + tm->tm_wday %= 7;
> + } else {
> + /* Alarm is set to a day of month */
> + tm->tm_wday = -1;
> + tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
> + STM32_RTC_ALRMXR_DATE_SHIFT;
> + }
> + }
> +
> + if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
> + /* Hours don't care in Alarm comparison */
> + tm->tm_hour = -1;
> + } else {
> + tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
> + STM32_RTC_ALRMXR_HOUR_SHIFT;
> + if (alrmar & STM32_RTC_ALRMXR_PM)
> + tm->tm_hour += 12;
> + }
> +
> + if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
> + /* Minutes don't care in Alarm comparison */
> + tm->tm_min = -1;
> + } else {
> + tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
> + STM32_RTC_ALRMXR_MIN_SHIFT;
> + }
> +
> + if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
> + /* Seconds don't care in Alarm comparison */
> + tm->tm_sec = -1;
> + } else {
> + tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
> + STM32_RTC_ALRMXR_SEC_SHIFT;
> + }
> +
> + bcd2tm(tm);
> +
> + alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
> + alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + unsigned long irqflags;
> + unsigned int isr, cr;
> +
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + /* We expose Alarm A to the kernel */
> + if (enabled)
> + cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
> + else
> + cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> + /* Clear event irqflags, otherwise new events won't be received */
> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> + isr &= ~STM32_RTC_ISR_ALRAF;
> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + struct rtc_time *tm = &alrm->time;
> + unsigned long irqflags;
> + unsigned int cr, isr, alrmar;
> + int ret = 0;
> +
> + if (rtc_valid_tm(tm)) {
> + dev_err(dev, "Alarm time not valid.\n");
> + return -EINVAL;
> + }
> +
> + tm2bcd(tm);
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + /* Disable Alarm */
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + cr &= ~STM32_RTC_CR_ALRAE;
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> + /* Poll Alarm write flag to be sure that Alarm update is allowed */
> + ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> + isr,
> + (isr & STM32_RTC_ISR_ALRAWF),
> + 10, 100);
> +
> + if (ret) {
> + dev_err(dev, "Alarm update not allowed\n");
> + goto end;
> + }
> +
> + alrmar = 0;
> +
> + if (tm->tm_mday < 0 && tm->tm_wday < 0) {
> + /*
> + * Date/day don't care in Alarm comparison so alarm triggers
> + * every day
> + */
> + alrmar |= STM32_RTC_ALRMXR_DATE_MASK;
> + } else {
> + if (tm->tm_mday > 0) {
> + /* Date is selected (ignoring wday) */
> + alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
> + STM32_RTC_ALRMXR_DATE;
> + } else {
> + /* Day of week is selected */
> + int wday = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
> +
> + alrmar |= STM32_RTC_ALRMXR_WDSEL;
> + alrmar |= (wday << STM32_RTC_ALRMXR_WDAY_SHIFT) &
> + STM32_RTC_ALRMXR_WDAY;
> + }
> + }
> +
> + if (tm->tm_hour < 0) {
> + /* Hours don't care in Alarm comparison */
> + alrmar |= STM32_RTC_ALRMXR_HOUR_MASK;
> + } else {
> + /* 24-hour format */
> + alrmar &= ~STM32_RTC_ALRMXR_PM;
> + alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
> + STM32_RTC_ALRMXR_HOUR;
> + }
> +
> + if (tm->tm_min < 0) {
> + /* Minutes don't care in Alarm comparison */
> + alrmar |= STM32_RTC_ALRMXR_MIN_MASK;
> + } else {
> + alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
> + STM32_RTC_ALRMXR_MIN;
> + }
> +
> + if (tm->tm_sec < 0) {
> + /* Seconds don't care in Alarm comparison */
> + alrmar |= STM32_RTC_ALRMXR_SEC_MASK;
> + } else {
> + alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
> + STM32_RTC_ALRMXR_SEC;
> + }
> +
> + /* Write to Alarm register */
> + stm32_rtc_writel(rtc, STM32_RTC_ALRMAR, alrmar);
> +
> + if (alrm->enabled)
> + stm32_rtc_alarm_irq_enable(dev, 1);
> + else
> + stm32_rtc_alarm_irq_enable(dev, 0);
> +
> +end:
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return ret;
> +}
> +
> +static const struct rtc_class_ops stm32_rtc_ops = {
> + .read_time = stm32_rtc_read_time,
> + .set_time = stm32_rtc_set_time,
> + .read_alarm = stm32_rtc_read_alarm,
> + .set_alarm = stm32_rtc_set_alarm,
> + .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
> +};
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_rtc_of_match[] = {
> + { .compatible = "st,stm32-rtc" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
> +#endif
> +
> +static int stm32_rtc_init(struct platform_device *pdev,
> + struct stm32_rtc *rtc)
> +{
> + unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
> + unsigned int rate;
> + unsigned long irqflags;
> + int ret = 0;
> +
> + rate = clk_get_rate(rtc->ck_rtc);
> +
> + /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
> + pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
> + pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
> +
> + for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
> + pred_s = (rate / (pred_a + 1)) - 1;
> +
> + if (((pred_s + 1) * (pred_a + 1)) == rate)
> + break;
> + }
> +
> + /*
> + * Can't find a 1Hz, so give priority to RTC power consumption
> + * by choosing the higher possible value for prediv_a
> + */
> + if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
> + pred_a = pred_a_max;
> + pred_s = (rate / (pred_a + 1)) - 1;
> +
> + dev_warn(&pdev->dev, "ck_rtc is %s\n",
> + (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
> + "fast" : "slow");
> + }
> +
> + spin_lock_irqsave(&rtc->lock, irqflags);
> +
> + stm32_rtc_wpr_unlock(rtc);
> +
> + ret = stm32_rtc_enter_init_mode(rtc);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "Can't enter in init mode. Prescaler config failed.\n");
> + goto end;
> + }
> +
> + prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
> + stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> + prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
> + stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> +
> + /* Force 24h time format */
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + cr &= ~STM32_RTC_CR_FMT;
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> + stm32_rtc_exit_init_mode(rtc);
> +
> + ret = stm32_rtc_wait_sync(rtc);
> +
> + if (stm32_rtc_readl(rtc, STM32_RTC_ISR) & STM32_RTC_ISR_INITS)
> + dev_warn(&pdev->dev, "Date/Time must be initialized\n");
> +end:
> + stm32_rtc_wpr_lock(rtc);
> +
> + spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> + return ret;
> +}
> +
> +static int stm32_rtc_probe(struct platform_device *pdev)
> +{
> + struct stm32_rtc *rtc;
> + struct resource *res;
> + int ret;
> +
> + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
> + if (!rtc)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + rtc->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(rtc->base))
> + return PTR_ERR(rtc->base);
> +
> + dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "st,syscfg");
> + if (IS_ERR(dbp)) {
> + dev_err(&pdev->dev, "no st,syscfg\n");
> + return PTR_ERR(dbp);
> + }
> +
> + spin_lock_init(&rtc->lock);
> +
> + rtc->ck_rtc = devm_clk_get(&pdev->dev, "ck_rtc");
> + if (IS_ERR(rtc->ck_rtc)) {
> + dev_err(&pdev->dev, "no ck_rtc clock");
> + return PTR_ERR(rtc->ck_rtc);
> + }
> +
> + ret = clk_prepare_enable(rtc->ck_rtc);
> + if (ret)
> + return ret;
> +
> + if (dbp)
> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
> +
> + ret = stm32_rtc_init(pdev, rtc);
> + if (ret)
> + goto err;
> +
> + rtc->irq_alarm = platform_get_irq_byname(pdev, "alarm");
> + if (rtc->irq_alarm <= 0) {
> + dev_err(&pdev->dev, "no alarm irq\n");
> + ret = -ENOENT;
> + goto err;
> + }
> +
> + platform_set_drvdata(pdev, rtc);
> +
> + device_init_wakeup(&pdev->dev, true);
> +
> + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
> + &stm32_rtc_ops, THIS_MODULE);
> + if (IS_ERR(rtc->rtc_dev)) {
> + ret = PTR_ERR(rtc->rtc_dev);
> + dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
> + ret);
> + goto err;
> + }
> +
> + /* Handle RTC alarm interrupts */
> + ret = devm_request_irq(&pdev->dev, rtc->irq_alarm,
> + stm32_rtc_alarm_irq, IRQF_TRIGGER_RISING,
> + dev_name(&rtc->rtc_dev->dev), rtc);
> + if (ret) {
> + dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
> + rtc->irq_alarm);
> + goto err;
> + }
> +
> + return 0;
> +err:
> + clk_disable_unprepare(rtc->ck_rtc);
> +
> + if (dbp)
> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +
> + device_init_wakeup(&pdev->dev, false);
> +
> + return ret;
> +}
> +
> +static int __exit stm32_rtc_remove(struct platform_device *pdev)
> +{
> + struct stm32_rtc *rtc = platform_get_drvdata(pdev);
> + unsigned int cr;
> +
> + /* Disable interrupts */
> + stm32_rtc_wpr_unlock(rtc);
> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> + cr &= ~STM32_RTC_CR_ALRAIE;
> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> + stm32_rtc_wpr_lock(rtc);
> +
> + clk_disable_unprepare(rtc->ck_rtc);
> +
> + /* Enable backup domain write protection */
> + if (dbp)
> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +
> + device_init_wakeup(&pdev->dev, false);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int stm32_rtc_suspend(struct device *dev)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev))
> + return enable_irq_wake(rtc->irq_alarm);
> +
> + return 0;
> +}
> +
> +static int stm32_rtc_resume(struct device *dev)
> +{
> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + ret = stm32_rtc_wait_sync(rtc);
> + if (ret < 0)
> + return ret;
> +
> + if (device_may_wakeup(dev))
> + return disable_irq_wake(rtc->irq_alarm);
> +
> + return ret;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
> + stm32_rtc_suspend, stm32_rtc_resume);
> +
> +static struct platform_driver stm32_rtc_driver = {
> + .probe = stm32_rtc_probe,
> + .remove = stm32_rtc_remove,
> + .driver = {
> + .name = DRIVER_NAME,
> + .pm = &stm32_rtc_pm_ops,
> + .of_match_table = stm32_rtc_of_match,
> + },
> +};
> +
> +module_platform_driver(stm32_rtc_driver);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.9.1
>
^ permalink raw reply
* [RFC PATCH 00/29] arm64: Scalable Vector Extension core support
From: Dave Martin @ 2016-12-02 18:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.20.1612021648580.16956@digraph.polyomino.org.uk>
On Fri, Dec 02, 2016 at 04:59:27PM +0000, Joseph Myers wrote:
> On Fri, 2 Dec 2016, Florian Weimer wrote:
>
> > > However, it would be necessary to prevent GCC from moving any code
> > > across these statements -- in particular, SVE code that access VL-
> > > dependent data spilled on the stack is liable to go wrong if reordered
> > > with the above. So the sequence would need to go in an external
> > > function (or a single asm...)
> >
> > I would talk to GCC folks?we have similar issues with changing the FPU
> > rounding mode, I assume.
>
> In general, GCC doesn't track the implicit uses of thread-local state
> involved in floating-point exceptions and rounding modes, and so doesn't
> avoid moving code across manipulations of such state; there are various
> open bugs in this area (though many of the open bugs are for local rather
> than global issues with code generation or local optimizations not
> respecting exceptions and rounding modes, which are easier to fix). Hence
> glibc using various macros such as math_opt_barrier and math_force_eval
> which use asms to prevent such motion.
Presumably the C language specs specify that fenv manipulations cannot
be reordered with respect to evaluation or floating-point expressions?
Sanity would seem to require this, though I've not dug into the specs
myself yet.
This doesn't get us off the hook for prctl() -- the C specs can only
define constraints on reordering for things that appear in the C spec.
prctl() is just an external function call in this context, and doesn't
enjoy the same guarantees.
> I'm not familiar enough with the optimizers to judge the right way to
> address such issues with implicit use of thread-local state. And I
> haven't thought much yet about how to implement TS 18661-1 constant
> rounding modes, which would involve the compiler implicitly inserting
> rounding modes changes, though I think it would be fairly straightforward
> given underlying support for avoiding inappropriate code motion.
My concern is that the compiler has no clue about what code motions are
appropriate or not with respect to a system call, beyond what applies
to a system call in general (i.e., asm volatile ( ::: "memory" ) for
GCC).
?
Cheers
---Dave
^ permalink raw reply
* [PATCH 2/2] ARM: omap: timers: reduce rating of gp_timer clocksource
From: Tony Lindgren @ 2016-12-02 18:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <14878d85-1b08-5df1-4e67-6f982ba72019@ti.com>
* Grygorii Strashko <grygorii.strashko@ti.com> [161202 10:02]:
>
>
> On 12/02/2016 10:47 AM, Tony Lindgren wrote:
> > * Grygorii Strashko <grygorii.strashko@ti.com> [161129 08:43]:
> > >
> > >
> > > On 11/24/2016 12:19 AM, Keerthy wrote:
> > > > From: Grygorii Strashko <grygorii.strashko@ti.com>
> > > >
> > > > Now ARM Global timer (rating 300) will not be selected as clocksource,
> > > > because it's initialized after OMAP GP Timer (rating 300) and
> > > > Timekeeping core will not allow to replace clocksource with new one if
> > > > both of them have the same rating.
> > > >
> > > > Reduce rating of OMAP GP Timer (300->290) when it's used as
> > > > clocksource device - this will allow to select ARM Global timer (300)
> > > > as clocksource when enabled.
> > > >
> > > > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > > > Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
> > > > Signed-off-by: Keerthy <j-keerthy@ti.com>
> > >
> > > Unfortunately, this patch has dependency [1] and can't be used alone as
> > > it will cause ARM Global timer to be selected as clocksource
> > > always on am437x and this will kill cpuidle, because ARM Global timer
> > > is not in always_on domain.
> > >
> > > The intention of enabling ARM Global timer is only for non-pm aware use
> > > cases for RT-kernel latency improvement - where deep cpuidle states are not
> > > enabled.
> >
> > Yeah we need to fix up things to be able to change the clocksource
> > in addition to clockevent. However, currently only cpuidle_coupled
> > knows when the whole system is idle, so quite a bit of work is
> > needed to do that in a sane way.
>
> Also sched_clock and timer_delay ;)
Yeah sched_clock would need something to save and restore it..
Not nice :)
> > What about the first patch in this series?
> >
>
> Fist one is ok. It was originally posted long time ago.
OK so can you please resend that one more time with proper
Fixes tag on it?
Regards,
Tony
^ permalink raw reply
* [PATCH net-next v2] net: thunderx: Fix transmit queue timeout issue
From: David Miller @ 2016-12-02 18:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480596868-17693-1-git-send-email-sunil.kovvuri@gmail.com>
From: sunil.kovvuri@gmail.com
Date: Thu, 1 Dec 2016 18:24:28 +0530
> From: Sunil Goutham <sgoutham@cavium.com>
>
> Transmit queue timeout issue is seen in two cases
> - Due to a race condition btw setting stop_queue at xmit()
> and checking for stopped_queue in NAPI poll routine, at times
> transmission from a SQ comes to a halt. This is fixed
> by using barriers and also added a check for SQ free descriptors,
> incase SQ is stopped and there are only CQE_RX i.e no CQE_TX.
> - Contrary to an assumption, a HW errata where HW doesn't stop transmission
> even though there are not enough CQEs available for a CQE_TX is
> not fixed in T88 pass 2.x. This results in a Qset error with
> 'CQ_WR_FULL' stalling transmission. This is fixed by adjusting
> RXQ's RED levels for CQ level such that there is always enough
> space left for CQE_TXs.
>
> Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
> ---
> v2: As suggested by David, replaced netif_tx_start_queue with
> netif_tx_wake_queue.
Applied, thanks.
^ permalink raw reply
* [PATCH 1/3] Documentation: dt: Add TI SCI clock driver
From: Rob Herring @ 2016-12-02 18:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8579b123-f214-22f1-0236-e5b98ab51597@ti.com>
On Fri, Dec 2, 2016 at 2:19 AM, Tero Kristo <t-kristo@ti.com> wrote:
> On 21/11/16 10:14, Tero Kristo wrote:
>>
>> On 18/11/16 19:20, Rob Herring wrote:
>>>
>>> On Mon, Oct 31, 2016 at 7:50 AM, Tero Kristo <t-kristo@ti.com> wrote:
>>>>
>>>> On 30/10/16 22:41, Rob Herring wrote:
>>>>>
>>>>>
>>>>> On Fri, Oct 21, 2016 at 03:45:59PM +0300, Tero Kristo wrote:
>>>>>>
>>>>>>
>>>>>> Add a clock implementation, TI SCI clock, that will hook to the common
>>>>>> clock framework, and allow each clock to be controlled via TI SCI
>>>>>> protocol.
>>>>>>
>>>>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>>>>> ---
>>>>>> .../devicetree/bindings/clock/ti,sci-clk.txt | 37
>>>>>> ++++++++++++++++++++++
>>>>>> MAINTAINERS | 1 +
>>>>>> 2 files changed, 38 insertions(+)
>>>>>> create mode 100644
>>>>>> Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>> b/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>> new file mode 100644
>>>>>> index 0000000..bfc3ca4
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>> @@ -0,0 +1,37 @@
>>>>>> +Texas Instruments TI-SCI Clocks
>>>>>> +===============================
>>>>>> +
>>>>>> +All clocks on Texas Instruments' SoCs that contain a System
>>>>>> Controller,
>>>>>> +are only controlled by this entity. Communication between a host
>>>>>> processor
>>>>>> +running an OS and the System Controller happens through a protocol
>>>>>> known
>>>>>> +as TI-SCI[1]. This clock implementation plugs into the common clock
>>>>>> +framework and makes use of the TI-SCI protocol on clock API requests.
>>>>>> +
>>>>>> +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
>>>>>> +
>>>>>> +Required properties:
>>>>>> +-------------------
>>>>>> +- compatible: Must be "ti,k2g-sci-clk"
>>>>>> +- #clock-cells: Shall be 2.
>>>>>> + In clock consumers, this cell represents the device ID and clock ID
>>>>>> + exposed by the PM firmware. The assignments can be found in the
>>>>>> header
>>>>>> + files <dt-bindings/genpd/<soc>.h> (which covers the device IDs) and
>>>>>> + <dt-bindings/clock/<soc>.h> (which covers the clock IDs), where
>>>>>> <soc>
>>>>>> + is the SoC involved, for example 'k2g'.
>>>>>> +
>>>>>> +Examples:
>>>>>> +--------
>>>>>> +
>>>>>> +pmmc: pmmc {
>>>>>> + compatible = "ti,k2g-sci";
>>>>>> +
>>>>>> + k2g_clks: k2g_clks {
>>>>>
>>>>>
>>>>>
>>>>> Use "clocks" for node name instead.
>>>>>
>>>>>> + compatible = "ti,k2g-sci-clk";
>>>>>
>>>>>
>>>>>
>>>>> I'm starting to think all these child nodes for SCI are pointless. Is
>>>>> there any reason why the parent node can't be the clock provider (along
>>>>> with all the other providers it acks as)?
>>>>
>>>>
>>>>
>>>> I believe the only reason to keep them separate is to have kernel
>>>> side of
>>>> things modular. If we have separate nodes, the drivers can be probed
>>>> separately.
>>>>
>>>> If not, we need to build one huge blob with all the features in it,
>>>> so the
>>>> main driver can probe everything in one go, with annoying back-and-forth
>>>> callbacks in place (assuming we still want to keep stuff somehow
>>>> modular.)
>>>
>>>
>>> Since when is DT the only way to create a device? The main driver can
>>> create devices for all the sub-functions like clocks. This is the same
>>> as MFDs which have been done both ways.
>>
>>
>> Yes obviously this can be done, my main point was that it will require
>> building some sort of infra within the driver to handle this. With
>> separate nodes, none of this is going to be needed. Also, we will lose
>> any kind of configurability via DT if we don't have separate nodes; now
>> we can select the available clocks / genpds via the compatible string of
>> the clocks/genpd nodes themselves (this isn't clearly evident as of now
>> as we only support a grand total of one device, which is k2g-evm.)
>> Otherwise we need to probe against the main node and add a separate
>> compatible string for every device, and carry this information to the
>> sibling devices also somehow. It is just so much simpler if we can just
>> keep separate nodes for them.
>>
>> Also, plenty of things are doing this kind of stuff already in
>> DT/kernel, having a parent node in place and sub-functions added
>> separately for ease of use, with apparently no visible point for having
>> the nodes within the DT.
>
>
> Rob, any response on this one? I see you have acked the reset part of the
> bindings which is doing pretty much the same thing as the clock part is
> doing here, namely adding child node under the main SCI node. Is it okay to
> do this same for other parts of the TI SCI?
Yes. It would be silly to allow for one and not others...
Rob
^ permalink raw reply
* [PATCH v6 net-next 0/7] Support Armada 37xx SoC (ARMv8 64-bits) in mvneta driver
From: David Miller @ 2016-12-02 18:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.dd374b7aaa358be0211d7ead81129a399fa692f4.1480611779.git-series.gregory.clement@free-electrons.com>
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
Date: Thu, 1 Dec 2016 18:03:03 +0100
> The Armada 37xx is a new ARMv8 SoC from Marvell using same network
> controller as the older Armada 370/38x/XP SoCs. This series adapts the
> driver in order to be able to use it on this new SoC. The main changes
> are:
>
> - 64-bits support: the first patches allow using the driver on a 64-bit
> architecture.
>
> - MBUS support: the mbus configuration is different on Armada 37xx
> from the older SoCs.
>
> - per cpu interrupt: Armada 37xx do not support per cpu interrupt for
> the NETA IP, the non-per-CPU behavior was added back.
>
> The first patch is an optimization in the rx path in swbm mode.
> The second patch remove unnecessary allocation for HWBM.
> The first item is solved by patches 4 and 5.
> The 2 last items are solved by patch 6.
> In patch 7 the dt support is added.
>
> Beside Armada 37xx, this series have been again tested on Armada XP
> and Armada 38x (with Hardware Buffer Management and with Software
> Buffer Management).
...
Series applied, thanks.
^ permalink raw reply
* [PATCH v11 0/7] Enable PMUs in ACPI systems
From: Jeremy Linton @ 2016-12-02 18:55 UTC (permalink / raw)
To: linux-arm-kernel
This patch expands and reworks the patches published by Mark Salter
in order to clean up a few of the previous review comments, as well as
add support for newer CPUs and big/little configurations.
v11:
- Add is_smp() check to read_specific_cpuid() for arch/arm. Update
c_show() and various routines in arm_pmu_acpi() to use the macro.
- Moved the duplicate "generic" pmu detection code into its own
patch and hoist it into arm_pmu_device_probe() so it works
for DT based systems as well.
v10:
- Rebase to 4.9
- Rework the arm_perf_start_cpu changes to support the 4.9 hotplug
changes.
- Remove the call to acpi_register_gsi() from the cpu online code path.
Instead the GSI's are registered during the initcall. This changes
the error handling a bit because we now try to clean up the
previously registered GSIs in a couple important places. This
was also a result of the rebase.
- Dropped the MIDR partnumber usage, its no longer necessary to
differentiate by only the partnum, so this helps to clarify the code
a bit.
- Shuffle some code around and rename a few variables.
- Added a few comments to hopefully clarify some questions people have
previously had about unused MADT entries, skipping processing cores
with MIDR=0, etc.
v9:
- Add/cleanup an additional hotplug patch I've had sitting around. This
patch brings the ACPI PMU mostly on par with the DT functionality with
respect to having CPUs offline during boot. This should help clarify
some of the code structuring.
- Cleanup the list of PMU types early if we fail to allocate memory for an
additional pmu type.
v8:
- Rebase to 4.8rc4
- Assorted minor comment/hunk placement/etc tweaks per Punit Agrawal
v7:
- Rebase to 4.8rc3
- Remove cpu affinity sysfs entry. While providing a CPU mask for
ARMv8 PMU's is really helpful in big/little environments, reworking
the PMU code to support the cpumask attribute for !arm64 PMUs is out
of the scope of this patch set.
- Fix CPU miscount problem where an alloc failure followed by successfully
allocating the structure can result in under counting the CPUs associated
with the PMU. This bug was created in v6 with the conversion to a linked
list.
- Remove initial platform device creation code by Mark Salter, and re-squash
multiple platform device creation code together with helper routines.
Other minor tweakage.
v6:
- Added cpu affinity sysfs entry
- Converted pmu_types array, to linked list
- Restrict use of the armv8_pmu_probe_table to ACPI systems
- Rename MADT parsing routines in smp.c
- Convert sysfs PMU name to use index rather than partnum
- Remove pr_devel statements
- Other Minor cleanups
- Add Partial Ack-by Will Deacon
v5:
- Remove list of CPU types for ACPI systems. We now match a generic
event list, and use the PMCIED[01] to select events which exist on
the given PMU. This avoids the need to update the kernel every time
a new CPU is released.
- Update the maintainers list to include the new file.
v4:
- Correct build issues with ARM (!ARM64) kernels.
- Add ThunderX to list of PMU types.
v3:
- Enable ARM performance monitoring units on ACPI/arm64 machines.
Jeremy Linton (6):
arm64: Rename the common MADT parse routine
arm: arm64: Add routine to determine cpuid of other cpus
arm: arm64: pmu: Assign platform PMU CPU affinity
arm64: pmu: Detect multiple generic PMUs and append counter
arm64: pmu: Detect and enable multiple PMUs in an ACPI system
arm: pmu: Add PMU definitions for cores not initially online
Mark Salter (1):
arm64: pmu: Cache PMU interrupt numbers from MADT parse
arch/arm/include/asm/cputype.h | 4 +
arch/arm/kernel/setup.c | 2 +-
arch/arm64/include/asm/cputype.h | 3 +
arch/arm64/kernel/perf_event.c | 2 +-
arch/arm64/kernel/smp.c | 18 ++-
drivers/perf/Kconfig | 4 +
drivers/perf/Makefile | 1 +
drivers/perf/arm_pmu.c | 107 ++++++++++++++--
drivers/perf/arm_pmu_acpi.c | 271 +++++++++++++++++++++++++++++++++++++++
include/linux/perf/arm_pmu.h | 12 ++
10 files changed, 404 insertions(+), 20 deletions(-)
create mode 100644 drivers/perf/arm_pmu_acpi.c
--
2.5.5
^ 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