* [RFC PATCH] PCI: designware: add host_init() error handling
From: Joao Pinto @ 2016-12-05 10:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d416f9b3-20d9-0339-a4d2-9a4ba0669633@linaro.org>
?s 11:51 AM de 12/2/2016, Srinivas Kandagatla escreveu:
>
>
> On 02/12/16 10:32, Joao Pinto wrote:
>>
>> Hi Srinivas,
>>
>> ?s 11:51 AM de 12/1/2016, Srinivas Kandagatla escreveu:
>>> drivers/pci/host/pci-dra7xx.c | 4 +++-
>>> drivers/pci/host/pci-exynos.c | 4 +++-
>>> drivers/pci/host/pci-imx6.c | 4 +++-
>>> drivers/pci/host/pci-keystone.c | 4 +++-
>>> drivers/pci/host/pci-layerscape.c | 12 ++++++++----
>>> drivers/pci/host/pcie-armada8k.c | 4 +++-
>>> drivers/pci/host/pcie-designware-plat.c | 4 +++-
>>> drivers/pci/host/pcie-designware.c | 4 +++-
>>> drivers/pci/host/pcie-designware.h | 2 +-
>>> drivers/pci/host/pcie-qcom.c | 6 ++++--
>>> drivers/pci/host/pcie-spear13xx.c | 4 +++-
>>> 11 files changed, 37 insertions(+), 15 deletions(-)
>>>
>>
>> Thanks for the patch!
>>
>> In my opinion your idea is good but only qcom driver is able to detect failure
>> in the specific host init routine, all others have a 'return 0' even if
>> something not well init. I would recomend that we take this issue a bit further
>> and add the error checking to all specific pci drivers in order to make them as
>> robust as qcom'.
> I totally agree with you, I can give this a go in next version.
Sure, but I think it would be better to finish now since we are on top of the
task. I can help you if you need.
Thanks Joao
>
> Thanks,
> srini
>
>>
>> Thanks,
>> Joao
>>
^ permalink raw reply
* ILP32 for ARM64: testing with glibc testsuite
From: Zhangjian (Bamvor) @ 2016-12-05 10:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <mvmeg1mn0yp.fsf@hawking.suse.de>
On 2016/12/5 18:07, Andreas Schwab wrote:
> On Dez 05 2016, "Zhangjian (Bamvor)" <bamvor.zhangjian@huawei.com> wrote:
>
>> Is there some progresses on it? We could collabrate to fix those issues.
>
> All the elf/nptl/rt fails should be fixed by the recent binutils fixes.
Cool. How about the conform and other failures?
Regards
Bamvor
>
> Andreas.
>
^ permalink raw reply
* [PATCH v1 2/2] crypto: mediatek - add DT bindings documentation
From: Matthias Brugger @ 2016-12-05 10:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480921284-45827-3-git-send-email-ryder.lee@mediatek.com>
On 05/12/16 08:01, Ryder Lee wrote:
> Add DT bindings documentation for the crypto driver
>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> ---
> .../devicetree/bindings/crypto/mediatek-crypto.txt | 32 ++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
>
> diff --git a/Documentation/devicetree/bindings/crypto/mediatek-crypto.txt b/Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
> new file mode 100644
> index 0000000..8b1db08
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
> @@ -0,0 +1,32 @@
> +MediaTek cryptographic accelerators
> +
> +Required properties:
> +- compatible: Should be "mediatek,mt7623-crypto"
Do you know how big the difference is between the crypto engine for
mt7623/mt2701/mt8521p in comparison, let's say mt8173 or mt6797?
Do this SoCs have a crypot engine? If so and they are quite similar, we
might think of adding a mtk-crypto binding and add soc specific bindings.
Regards,
Matthias
> +- reg: Address and length of the register set for the device
> +- interrupts: Should contain the five crypto engines interrupts in numeric
> + order. These are global system and four descriptor rings.
> +- clocks: the clock used by the core
> +- clock-names: the names of the clock listed in the clocks property. These are
> + "ethif", "cryp"
> +- power-domains: Must contain a reference to the PM domain.
> +
> +
> +Optional properties:
> +- interrupt-parent: Should be the phandle for the interrupt controller
> + that services interrupts for this device
> +
> +
> +Example:
> + crypto: crypto at 1b240000 {
> + compatible = "mediatek,mt7623-crypto";
> + reg = <0 0x1b240000 0 0x20000>;
> + interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
> + clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
> + <ðsys CLK_ETHSYS_CRYPTO>;
> + clock-names = "ethif","cryp";
> + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
> + };
>
^ permalink raw reply
* ILP32 for ARM64 - testing with lmbench
From: Zhangjian (Bamvor) @ 2016-12-05 10:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <120041af-f4e9-5b6f-36dc-7d3535a1f01c@huawei.com>
Hi, Catalin, Guys
Do you have suggestion of next move of upstreaming ILP32?
There are already the test results of lmbench and specint. Do you they are ok or need more data to prove no regression?
I have also noticed that there are ILP32 failures in glibc testsuite. Is it the only blocker for merge ILP32(in technology part)?
We appreciate any feedback/suggestion and hope could collaborate to improve the upstream progress.
(cc libc-alpha to get more input).
Thanks
Bamvor
On 2016/11/17 15:48, Zhangjian (Bamvor) wrote:
> Hi, Maxim
>
> On 2016/11/17 13:02, Maxim Kuvyrkov wrote:
>> Hi Bamvor,
>>
>> I'm surprised that you see this much difference from ILP32 patches on SPEC CPU2006int at all. The SPEC CPU2006 benchmarks spend almost no time in the kernel syscalls. I can imagine memory, TLB,
>> and cache handling in the kernel could affect CPU2006 benchmarks. Do ILP32 patches touch code in those areas?
>>
>> Other than that, it would be interesting to check what the variance is between the 3 iterations of benchmark runs. Could you check what relative standard deviation is between the 3 iterations --
>> (STDEV(RUN1, RUN2, RUN3) / RUNselected)?
>>
>> For reference, in my [non-ILP32] benchmarking I see 1.1% for 401.bzip2, 0.8% for 429.mcf, 0.2% for 456.hmmer, and 0.1% for 462.libquantum.
> Here is my result:
> ILP32_merged ILP32_unmerged
> 401.bzip2 0.31% 0.26%
> 429.mcf 1.61% 1.36%
> 456.hmmer 1.37% 1.57%
> 462.libquantum 0.29% 0.28%
>
> Regards
>
> Bamvor
>
>>
>> --
>> Maxim Kuvyrkov
>> www.linaro.org
>>
>>
>>
>>> On Nov 17, 2016, at 7:28 AM, Zhangjian (Bamvor) <bamvor.zhangjian@huawei.com> wrote:
>>>
>>> Hi, all
>>>
>>> I test specint of aarch64 LP64 when aarch32 el0 disable/enabled respectively
>>> and compare with ILP32 unmerged kernel(4.8-rc6) in our arm64 board. I found
>>> that difference(ILP32 disabled/ILP32 unmerged) is bigger when aarch32 el0 is
>>> enabled, compare with aarch32 el0 disabled kernel. And bzip2, mcg, hmmer,
>>> libquantum are the top four differences[1]. Note that bigger is better in
>>> specint test.
>>>
>>> In order to make sure the above results, I retest these four testcases in
>>> reportable way(reference the command in the end). The result[2] show that
>>> libquantum decrease -2.09% after ILP32 enabled and aarch32 on. I think it is in
>>> significant.
>>>
>>> The result of lmbench is not stable in my board. I plan to dig it later.
>>>
>>> [1] The following test result is tested through --size=ref --iterations=3.
>>> 1.1 Test when aarch32_el0 is enabled.
>>> ILP32 disabled base line
>>> 400.perlbench 100.00% 100%
>>> 401.bzip2 99.35% 100%
>>> 403.gcc 100.26% 100%
>>> 429.mcf 102.75% 100%
>>> 445.gobmk 100.00% 100%
>>> 456.hmmer 95.66% 100%
>>> 458.sjeng 100.00% 100%
>>> 462.libquantum 100.00% 100%
>>> 471.omnetpp 100.59% 100%
>>> 473.astar 99.66% 100%
>>> 483.xalancbmk 99.10% 100%
>>>
>>> 1.2 Test when aarch32_el0 is disabled
>>> ILP32 disabled base line
>>> 400.perlbench 100.22% 100%
>>> 401.bzip2 100.95% 100%
>>> 403.gcc 100.20% 100%
>>> 429.mcf 100.76% 100%
>>> 445.gobmk 100.36% 100%
>>> 456.hmmer 97.94% 100%
>>> 458.sjeng 99.73% 100%
>>> 462.libquantum 98.72% 100%
>>> 471.omnetpp 100.86% 100%
>>> 473.astar 99.15% 100%
>>> 483.xalancbmk 100.08% 100%
>>>
>>> [2] The following test result is tested through: runspec --config=my.cfg --size=test,train,ref --noreportable --tune=base,peak --iterations=3 bzip2 mcf hmmer libquantum
>>> 2.1 Test when aarch32_el0 is enabled.
>>> ILP32_enabled base line
>>> 401.bzip2 100.82% 100%
>>> 429.mcf 100.18% 100%
>>> 456.hmmer 99.64% 100%
>>> 462.libquantum 97.91% 100%
>>>
>>> Regards
>>>
>>> Bamvor
>>>
>>> On 2016/10/28 20:46, Yury Norov wrote:
>>>> [Add Steve Ellcey, thanks for testing on ThunderX]
>>>>
>>>> Lmbench-3.0-a9 testing is performed on ThunderX machine to check that
>>>> ILP32 series does not add performance regressions for LP64. Test
>>>> summary is in the table below. Our measurements doesn't show
>>>> significant performance regression of LP64 if ILP32 code is merged,
>>>> both enabled or disabled.
>>>>
>>>> ILP32 enabled ILP32 disabled Standard Kernel
>>>> null syscall 0.1066 0.1121 0.1121
>>>> 95.09% 100.00%
>>>>
>>>> stat 1.3947 1.3814 1.3864
>>>> 100.60% 99.64%
>>>>
>>>> fstat 0.4459 0.4344 0.4524
>>>> 98.56% 96.02%
>>>>
>>>> open/close 4.0606 4.0411 4.0453
>>>> 100.38% 99.90%
>>>>
>>>> read 0.4819 0.5014 0.5014
>>>> 96.11% 100.00%
>>>>
>>>> Tested with linux 4.8 because 4.9-rc1 is not fixed yet for ThunderX.
>>>> Other system details below.
>>>>
>>>> Yury.
>>>>
>>>> ubuntu at crb6:~$ uname -a
>>>> Linux crb6 4.8.0+ #3 SMP Thu Oct 27 11:01:32 PDT 2016 aarch64 aarch64 aarch64 GNU/Linux
>>>>
>>>> ubuntu at crb6:~$ cat /proc/meminfo
>>>> MemTotal: 132011948 kB
>>>> MemFree: 131442672 kB
>>>> MemAvailable: 130695764 kB
>>>> Buffers: 15696 kB
>>>> Cached: 88088 kB
>>>> SwapCached: 0 kB
>>>> Active: 82760 kB
>>>> Inactive: 41336 kB
>>>> Active(anon): 20880 kB
>>>> Inactive(anon): 8576 kB
>>>> Active(file): 61880 kB
>>>> Inactive(file): 32760 kB
>>>> Unevictable: 0 kB
>>>> Mlocked: 0 kB
>>>> SwapTotal: 128920572 kB
>>>> SwapFree: 128920572 kB
>>>> Dirty: 0 kB
>>>> Writeback: 0 kB
>>>> AnonPages: 20544 kB
>>>> Mapped: 19780 kB
>>>> Shmem: 9060 kB
>>>> Slab: 78804 kB
>>>> SReclaimable: 27372 kB
>>>> SUnreclaim: 51432 kB
>>>> KernelStack: 8336 kB
>>>> PageTables: 820 kB
>>>> NFS_Unstable: 0 kB
>>>> Bounce: 0 kB
>>>> WritebackTmp: 0 kB
>>>> CommitLimit: 194926544 kB
>>>> Committed_AS: 256324 kB
>>>> VmallocTotal: 135290290112 kB
>>>> VmallocUsed: 0 kB
>>>> VmallocChunk: 0 kB
>>>> AnonHugePages: 0 kB
>>>> ShmemHugePages: 0 kB
>>>> ShmemPmdMapped: 0 kB
>>>> CmaTotal: 0 kB
>>>> CmaFree: 0 kB
>>>> HugePages_Total: 0
>>>> HugePages_Free: 0
>>>> HugePages_Rsvd: 0
>>>> HugePages_Surp: 0
>>>> Hugepagesize: 2048 kB
>>>>
>>>> ubuntu at crb6:~$ cat /proc/cpuinfo
>>>> processor : 0
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 1
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 2
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 3
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 4
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 5
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 6
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 7
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 8
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 9
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 10
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 11
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 12
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 13
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 14
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 15
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 16
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 17
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 18
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 19
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 20
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 21
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 22
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 23
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 24
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 25
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 26
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 27
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 28
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 29
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 30
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 31
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 32
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 33
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 34
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 35
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 36
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 37
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 38
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 39
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 40
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 41
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 42
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 43
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 44
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 45
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 46
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>> processor : 47
>>>> BogoMIPS : 200.00
>>>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>>>> CPU implementer : 0x43
>>>> CPU architecture: 8
>>>> CPU variant : 0x1
>>>> CPU part : 0x0a1
>>>> CPU revision : 0
>>>>
>>>
>>
>
^ permalink raw reply
* [PATCH v3 1/3] ARM: da850: fix infinite loop in clk_set_rate()
From: Sekhar Nori @ 2016-12-05 10:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480932549-30811-2-git-send-email-bgolaszewski@baylibre.com>
On Monday 05 December 2016 03:39 PM, Bartosz Golaszewski wrote:
> The aemif clock is added twice to the lookup table in da850.c. This
> breaks the children list of pll0_sysclk3 as we're using the same list
> links in struct clk. When calling clk_set_rate(), we get stuck in
> propagate_rate().
>
> Create a separate clock for nand, inheriting the rate of the aemif
> clock and retrieve it in the davinci_nand module.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> arch/arm/mach-davinci/da850.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> index e770c97..c008e5e 100644
> --- a/arch/arm/mach-davinci/da850.c
> +++ b/arch/arm/mach-davinci/da850.c
> @@ -367,6 +367,11 @@ static struct clk aemif_clk = {
> .flags = ALWAYS_ENABLED,
> };
>
> +static struct clk aemif_nand_clk = {
> + .name = "nand",
> + .parent = &aemif_clk,
> +};
> +
> static struct clk usb11_clk = {
> .name = "usb11",
> .parent = &pll0_sysclk4,
> @@ -537,7 +542,7 @@ static struct clk_lookup da850_clks[] = {
> CLK("da830-mmc.0", NULL, &mmcsd0_clk),
> CLK("da830-mmc.1", NULL, &mmcsd1_clk),
> CLK("ti-aemif", NULL, &aemif_clk),
> - CLK(NULL, "aemif", &aemif_clk),
> + CLK(NULL, "aemif", &aemif_nand_clk),
Why use a NULL device name here? Same question was asked on v2
submission. Also, can you please make sure you are testing this in both
DT mode (da850-lcdk) and non-DT boot (da850-evm).
Thanks,
Sekhar
^ permalink raw reply
* [PATCH 2/8] dt-bindings: document the STM32 RTC bindings
From: Amelie DELAUNAY @ 2016-12-05 10:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205100630.n3gldznf524pucjm@piout.net>
Hi Alexandre,
Thanks for reviewing
On 12/05/2016 11:06 AM, Alexandre Belloni wrote:
> Hi,
>
> On 02/12/2016 at 15:09:55 +0100, Amelie Delaunay wrote :
>> This patch adds documentation of device tree bindings for the STM32 RTC.
>>
>> Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
>> ---
>> .../devicetree/bindings/rtc/st,stm32-rtc.txt | 31 ++++++++++++++++++++++
>> 1 file changed, 31 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
>> new file mode 100644
>> index 0000000..4578838
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
>> @@ -0,0 +1,31 @@
>> +STM32 Real Time Clock
>> +
>> +Required properties:
>> +- compatible: "st,stm32-rtc".
>> +- reg: address range of rtc register set.
>> +- clocks: reference to the clock entry ck_rtc.
>> +- clock-names: name of the clock used. Should be "ck_rtc".
>
> Is this name really useful?
You're right, not useful.
>
>> +- interrupt-parent: phandle for the interrupt controller.
>> +- interrupts: rtc alarm interrupt.
>> +- interrupt-names: rtc alarm interrupt name, should be "alarm".
>
> Same comment, is this name really useful?
Ditto.
>
>
Best regards,
Amelie
^ permalink raw reply
* [PATCH v3 3/3] ARM: da850: fix da850_set_pll0rate()
From: Bartosz Golaszewski @ 2016-12-05 10:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480932549-30811-1-git-send-email-bgolaszewski@baylibre.com>
This function is confusing - its second argument is an index to the
freq table, not the requested clock rate in Hz, but it's used as the
set_rate callback for the pll0 clock. It leads to an oops when the
caller doesn't know the internals and passes the rate in Hz as
argument instead of the cpufreq index since this argument isn't bounds
checked either.
Fix it by iterating over the array of supported frequencies and
selecting a one that matches or returning -EINVAL for unsupported
rates.
Also: update the davinci cpufreq driver. It's the only user of this
clock and currently it passes the cpufreq table index to
clk_set_rate(), which is confusing. Make it pass the requested clock
rate in Hz.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
arch/arm/mach-davinci/da850.c | 20 ++++++++++++++++----
drivers/cpufreq/davinci-cpufreq.c | 2 +-
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 006ec56..9837541 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -1179,14 +1179,26 @@ static int da850_set_armrate(struct clk *clk, unsigned long index)
return clk_set_rate(pllclk, index);
}
-static int da850_set_pll0rate(struct clk *clk, unsigned long index)
+static int da850_set_pll0rate(struct clk *clk, unsigned long rate)
{
- unsigned int prediv, mult, postdiv;
- struct da850_opp *opp;
struct pll_data *pll = clk->pll_data;
+ struct cpufreq_frequency_table *freq;
+ unsigned int prediv, mult, postdiv;
+ struct da850_opp *opp = NULL;
int ret;
- opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
+ for (freq = da850_freq_table;
+ freq->frequency != CPUFREQ_TABLE_END; freq++) {
+ /* rate is in Hz, freq->frequency is in KHz */
+ if (freq->frequency == rate / 1000) {
+ opp = (struct da850_opp *)freq->driver_data;
+ break;
+ }
+ }
+
+ if (opp == NULL)
+ return -EINVAL;
+
prediv = opp->prediv;
mult = opp->mult;
postdiv = opp->postdiv;
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index b95a872..d54a27c 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -55,7 +55,7 @@ static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
return ret;
}
- ret = clk_set_rate(armclk, idx);
+ ret = clk_set_rate(armclk, new_freq * 1000);
if (ret)
return ret;
--
2.9.3
^ permalink raw reply related
* [PATCH v3 2/3] ARM: da850: coding style fix
From: Bartosz Golaszewski @ 2016-12-05 10:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480932549-30811-1-git-send-email-bgolaszewski@baylibre.com>
Fix alignment of the clock lookup table entries.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/arm/mach-davinci/da850.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index c008e5e..006ec56 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -548,7 +548,7 @@ static struct clk_lookup da850_clks[] = {
CLK("spi_davinci.0", NULL, &spi0_clk),
CLK("spi_davinci.1", NULL, &spi1_clk),
CLK("vpif", NULL, &vpif_clk),
- CLK("ahci_da850", NULL, &sata_clk),
+ CLK("ahci_da850", NULL, &sata_clk),
CLK("davinci-rproc.0", NULL, &dsp_clk),
CLK(NULL, NULL, &ehrpwm_clk),
CLK("ehrpwm.0", "fck", &ehrpwm0_clk),
--
2.9.3
^ permalink raw reply related
* [PATCH v3 1/3] ARM: da850: fix infinite loop in clk_set_rate()
From: Bartosz Golaszewski @ 2016-12-05 10:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480932549-30811-1-git-send-email-bgolaszewski@baylibre.com>
The aemif clock is added twice to the lookup table in da850.c. This
breaks the children list of pll0_sysclk3 as we're using the same list
links in struct clk. When calling clk_set_rate(), we get stuck in
propagate_rate().
Create a separate clock for nand, inheriting the rate of the aemif
clock and retrieve it in the davinci_nand module.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/arm/mach-davinci/da850.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index e770c97..c008e5e 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -367,6 +367,11 @@ static struct clk aemif_clk = {
.flags = ALWAYS_ENABLED,
};
+static struct clk aemif_nand_clk = {
+ .name = "nand",
+ .parent = &aemif_clk,
+};
+
static struct clk usb11_clk = {
.name = "usb11",
.parent = &pll0_sysclk4,
@@ -537,7 +542,7 @@ static struct clk_lookup da850_clks[] = {
CLK("da830-mmc.0", NULL, &mmcsd0_clk),
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
CLK("ti-aemif", NULL, &aemif_clk),
- CLK(NULL, "aemif", &aemif_clk),
+ CLK(NULL, "aemif", &aemif_nand_clk),
CLK("ohci-da8xx", "usb11", &usb11_clk),
CLK("musb-da8xx", "usb20", &usb20_clk),
CLK("spi_davinci.0", NULL, &spi0_clk),
--
2.9.3
^ permalink raw reply related
* [PATCH v3 0/3] ARM: da850: fix pll0 rate setting
From: Bartosz Golaszewski @ 2016-12-05 10:09 UTC (permalink / raw)
To: linux-arm-kernel
While trying to set the pll0 rate from the kernel I noticed there are
two issues with da850 clocks. The first patch fixes an infinite loop
in propagate_rate(). The third fixes an oops in da850_set_pll0rate().
The second patch is just a coding style fix, while we're at it.
v1 -> v2:
- change the approach in 1/3: create a new clock for nand inheriting
the rate from the aemif clock (verified that nand still works on
da850-lcdk)
- patch 3/3: also update the davinci_cpufreq driver - the only
(indirect) user of da850_set_pll0rate()
- s/requested_rate/rate in 3/3
v2 -> v3:
- 1/3: keep the "aemif" connector id for the nand clock
- 3/3: instead of multiplying freq->frequency, divide rate by 1000
- retested both davinci_nand and clk_set_rate() for pll0
Bartosz Golaszewski (3):
ARM: da850: fix infinite loop in clk_set_rate()
ARM: da850: coding style fix
ARM: da850: fix da850_set_pll0rate()
arch/arm/mach-davinci/da850.c | 29 +++++++++++++++++++++++------
drivers/cpufreq/davinci-cpufreq.c | 2 +-
2 files changed, 24 insertions(+), 7 deletions(-)
--
2.9.3
^ permalink raw reply
* [PATCHv4 11/15] clk: ti: clockdomain: add clock provider support to clockdomains
From: Tero Kristo @ 2016-12-05 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161203001852.GI4705@atomide.com>
On 03/12/16 02:18, Tony Lindgren wrote:
> * Michael Turquette <mturquette@baylibre.com> [161202 15:52]:
>> Quoting Tony Lindgren (2016-12-02 15:12:40)
>>> * Michael Turquette <mturquette@baylibre.com> [161202 14:34]:
>>>> Quoting Tony Lindgren (2016-10-28 16:54:48)
>>>>> * Stephen Boyd <sboyd@codeaurora.org> [161028 16:37]:
>>>>>> On 10/28, Tony Lindgren wrote:
>>>>>>> * Tero Kristo <t-kristo@ti.com> [161028 00:43]:
>>>>>>>> On 28/10/16 03:50, Stephen Boyd wrote:
>>>>>>>>> I suppose a PRCM is
>>>>>>>>> like an MFD that has clocks and resets under it? On other
>>>>>>>>> platforms we've combined that all into one node and just had
>>>>>>>>> #clock-cells and #reset-cells in that node. Is there any reason
>>>>>>>>> we can't do that here?
>>>>>>>>
>>>>>>>> For OMAPs, there are typically multiple instances of the PRCM around; OMAP4
>>>>>>>> for example has:
>>>>>>>>
>>>>>>>> cm1 @ 0x4a004000 (clocks + clockdomains)
>>>>>>>> cm2 @ 0x4a008000 (clocks + clockdomains)
>>>>>>>> prm @ 0x4a306000 (few clocks + resets + power state handling)
>>>>>>>> scrm @ 0x4a30a000 (few external clocks + plenty of misc stuff)
>>>>>>>>
>>>>>>>> These instances are also under different power/voltage domains which means
>>>>>>>> their PM behavior is different.
>>>>>>>>
>>>>>>>> The idea behind having a clockdomain as a provider was mostly to have the
>>>>>>>> topology visible : prcm-instance -> clockdomain -> clocks
>>>>>>>
>>>>>>> Yeah that's needed to get the interconnect hierarchy right for
>>>>>>> genpd :)
>>>>>>>
>>>>>>>> ... but basically I think it would be possible to drop the clockdomain
>>>>>>>> representation and just mark the prcm-instance as a clock provider. Tony,
>>>>>>>> any thoughts on that?
>>>>>>>
>>>>>>> No let's not drop the clockdomains as those will be needed when we
>>>>>>> move things into proper hierarchy within the interconnect instances.
>>>>>>> This will then help with getting things right with genpd.
>>>>>>>
>>>>>>> In the long run we just want to specify clockdomain and the offset of
>>>>>>> the clock instance within the clockdomain in the dts files.
>>>>>>>
>>>>>>
>>>>>> Sorry, I have very little idea how OMAP hardware works. Do you
>>>>>> mean that you will have different nodes for each clockdomain so
>>>>>> that genpd can map 1:1 to the node in dts? But in hardware
>>>>>> there's a prcm that allows us to control many clock domains
>>>>>> through register read/writes? How is the interconnect involved?
>>>>>
>>>>> There are multiple clockdomains, at least one for each interconnect
>>>>> instance. Once a clockdomain is idle, the related interconnect can
>>>>> idle too. So yeah genpd pretty much maps 1:1 with the clockdomains.
>>>>>
>>>>> There's more info in for example omap4 TRM section "3.4.1 Device
>>>>> Power-Management Layout" that shows the voltage/power/clock domains.
>>>>> The interconnect instances are mostly named there too looking at
>>>>> the L4/L3 naming.
>>>>
>>>> I'm confused on two points:
>>>>
>>>> 1) why are the clkdm's acting as clock providers? I've always hated the
>>>> name "clock domain" since those bits are for managing module state, not
>>>> clock state. The PRM, CM1 and CM2 provide the clocks, not the
>>>> clockdomains.
>>>
>>> The clock domains have multiple clock inputs that are routed to multiple
>>> child clocks. So it is a clock :)
>>>
>>> See for example omap4430 TRM "3.6.4 CD_WKUP Clock Domain" on page
>>> 393 in my revision here.
>>>
>>> On that page "Figure 3-48" shows CD_WKUP with the four input clocks.
>>> And then "Table 3-84. CD_WKUP Control and Status Parameters" shows
>>> the CD_WKUP clock domain specific registers. These registers show
>>> the status, I think they are all read-only registers. Then CD_WKUP
>>> has multiple child clocks with configurable registers.
>>>
>>> From hardware register point of view, each clock domain has:
>>>
>>> - Read-only clockdomain status registers in the beginning of
>>> the address space
>>>
>>> - Multiple similar clock instances register instances each
>>> mapping to a specific interconnect target module
>>>
>>> These are documented in "3.11.16.1 WKUP_CM Register Summary".
>>
>> Oh, this is because you are treating the MODULEMODE bits like gate
>> clocks. I never really figured out if this was the best way to model
>> those bits since they do more than control a line toggling at a rate.
>> For instance this bit will affect the master/slave IDLE protocol between
>> the module and the PRCM.
>
> Yes seems like there is some negotiation going on there with the
> target module. But from practical point of view the CLKCTRL
> register is the gate for a module functional clock.
There's some confusion on this, clockdomain is effectively a collection
of clocks, and can be used to force control that collection if needed.
Chapter "3.1.1.1.3 Clock Domain" in some OMAP4 TRM shows the
relationship neatly.
>
>>> From hardware point of view, we ideally want to map interconnect
>>> target modules to the clock instance offset from the clock domain
>>> for that interconnect segment. For example gptimer1 clocks would
>>> be just:
>>>
>>> clocks = <&cd_wkup 0x40>;
>>>
>>>> 2) why aren't the clock domains modeled as genpds with their associated
>>>> devices attached to them? Note that it is possible to "nest" genpd
>>>> objects. This would also allow for the "Clockdomain Dependency"
>>>> relationships to be properly modeled (see section 3.1.1.1.7 Clock Domain
>>>> Dependency in the OMAP4 TRM).
>>>
>>> Clock domains only route clocks to child clocks. Power domains
>>> are different registers. The power domains map roughly to
>>> interconnect instances, there we have registers to disable the
>>> whole interconnect when idle.
>>
>> I'm not talking about power islands at all, but the genpd object in
>> Linux. For instance, if we treat each clock domain like a clock
>> provider, how could the functional dependency between clkdm_A and
>> clkdm_B be asserted?
>
> To me it seems that some output of a clockdomain is just a input
> of another clockdomain? So it's just the usual parent child
> relationship once we treat a clockdomain just as a clock. Tero
> probably has some input here.
A clockdomain should be modelled as a genpd, that I agree. However, it
doesn't prevent it from being a clock provider also, or does it?
>> There is certainly no API for that in the clock framework, but for genpd
>> your runtime_pm_get() callback for clkdm_A could call runtime_pm_get
>> against clkdm_B, which would satisfy the requirement. See section
>> 3.1.1.1.7 Clock Domain Dependency in the OMAP4 TRM, version AB.
For static dependencies the apis genpd_add/remove_subdomain could
probably be used.
> To me it seems the API is just clk_get() :) Do you have some
> specific example we can use to check? My guess is that the
> TRM "Clock Domain Dependency" is just the usual parent child
> relationship between clocks that are the clockdomains..
>
> If there is something more magical there certainly that should
> be considered though.
The hwmods could be transformed to individual genpds also I guess. On DT
level though, we would still need a clock pointer to the main clock and
a genpd pointer in addition to that.
Tony, any thoughts on that? Would this break up the plans for the
interconnect completely?
-Tero
^ permalink raw reply
* ILP32 for ARM64: testing with glibc testsuite
From: Andreas Schwab @ 2016-12-05 10:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ff3b973b-3887-7ae8-5a27-4d1ad115055f@huawei.com>
On Dez 05 2016, "Zhangjian (Bamvor)" <bamvor.zhangjian@huawei.com> wrote:
> Is there some progresses on it? We could collabrate to fix those issues.
All the elf/nptl/rt fails should be fixed by the recent binutils fixes.
Andreas.
--
Andreas Schwab, SUSE Labs, schwab at suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
^ permalink raw reply
* [PATCH 2/8] dt-bindings: document the STM32 RTC bindings
From: Alexandre Belloni @ 2016-12-05 10:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480687801-19525-4-git-send-email-amelie.delaunay@st.com>
Hi,
On 02/12/2016 at 15:09:55 +0100, Amelie Delaunay wrote :
> This patch adds documentation of device tree bindings for the STM32 RTC.
>
> Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
> ---
> .../devicetree/bindings/rtc/st,stm32-rtc.txt | 31 ++++++++++++++++++++++
> 1 file changed, 31 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
>
> diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
> new file mode 100644
> index 0000000..4578838
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
> @@ -0,0 +1,31 @@
> +STM32 Real Time Clock
> +
> +Required properties:
> +- compatible: "st,stm32-rtc".
> +- reg: address range of rtc register set.
> +- clocks: reference to the clock entry ck_rtc.
> +- clock-names: name of the clock used. Should be "ck_rtc".
Is this name really useful?
> +- interrupt-parent: phandle for the interrupt controller.
> +- interrupts: rtc alarm interrupt.
> +- interrupt-names: rtc alarm interrupt name, should be "alarm".
Same comment, is this name really useful?
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH 2/2] arm64: alternatives: Work around NOP generation with broken assembler
From: Will Deacon @ 2016-12-05 10:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161203140538.23525-3-marc.zyngier@arm.com>
On Sat, Dec 03, 2016 at 02:05:38PM +0000, Marc Zyngier wrote:
> When compiling a .inst directive in an alternative clause with
> a rather old version of gas (circa 2.24), and when used with
> the alternative_else_nop_endif feature, the compilation fails
> with a rather cryptic message such as:
>
> arch/arm64/lib/clear_user.S:33: Error: bad or irreducible absolute expression
>
> which is caused by the bug described in eb7c11ee3c5c ("arm64:
> alternative: Work around .inst assembler bugs").
>
> This effectively prevents the use of the "nops" macro, which
> requires the number of instruction as a parameter (the assembler
> is confused and unable to compute the difference between two labels).
>
> As an alternative(!), use the .fill directive to output the number
> of required NOPs (.fill has the good idea to output the fill pattern
> in the endianness of the instruction stream).
Are you sure about that? The gas docs say:
`The contents of each repeat bytes is taken from an 8-byte number. The
highest order 4 bytes are zero. The lowest order 4 bytes are value rendered
in the byte-order of an integer on the computer as is assembling for.'
and I'd expect "integer" to refer to data values, rather than instructions.
>
> Fixes: 792d47379f4d ("arm64: alternative: add auto-nop infrastructure")
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> arch/arm64/include/asm/alternative.h | 12 +++++++++++-
> 1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
> index 39feb85..39f8c98 100644
> --- a/arch/arm64/include/asm/alternative.h
> +++ b/arch/arm64/include/asm/alternative.h
> @@ -159,9 +159,19 @@ void apply_alternatives(void *start, size_t length);
> * of NOPs. The number of NOPs is chosen automatically to match the
> * previous case.
> */
> +
> +#define NOP_INST 0xd503201f
If we define this, let's put it in insn.h or something. It could even be
used in the vdso linker script, which open codes this constant.
> +
> .macro alternative_else_nop_endif
> alternative_else
> - nops (662b-661b) / AARCH64_INSN_SIZE
> + /*
> + * The same assembler bug strikes again here if the first half
> + * of the alternative sequence contains a .inst, leading to a
> + * bizarre error message. Fortulately, .fill replaces the
Fortunately
> + * "nops" macro by inserting padding with the target machine
> + * endianness.
> + */
> + .fill (662b-661b) / AARCH64_INSN_SIZE, AARCH64_INSN_SIZE, NOP_INST
Assuming we can get .fill to do the right thing, we should probably use
it in __nops rather than open-coding it here. Or is the issue that we're
unable to pass (662b-661b) / AARCH64_INSN_SIZE to any macro?
Will
^ permalink raw reply
* [PATCH v4] ARM: davinci: da8xx: Fix sleeping function called from invalid context
From: Alexandre Bailon @ 2016-12-05 10:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <907a3c22-534f-80ce-daff-be84dd5e5cf8@lechnology.com>
On 12/05/2016 04:44 AM, David Lechner wrote:
> On 12/02/2016 08:53 AM, Alexandre Bailon wrote:
>> Everytime the usb20 phy is enabled, there is a
>> "sleeping function called from invalid context" BUG.
>>
>> clk_enable() from arch/arm/mach-davinci/clock.c uses spin_lock_irqsave()
>> before to invoke the callback usb20_phy_clk_enable().
>> usb20_phy_clk_enable() uses clk_get() and clk_enable_prepapre()
>> which may sleep.
>> Move clk_get() to da8xx_register_usb20_phy_clk() and
>> replace clk_prepare_enable() by clk_enable().
>>
>> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
>> ---
>> arch/arm/mach-davinci/usb-da8xx.c | 28 +++++++++++++++-------------
>> 1 file changed, 15 insertions(+), 13 deletions(-)
>>
>> diff --git a/arch/arm/mach-davinci/usb-da8xx.c
>> b/arch/arm/mach-davinci/usb-da8xx.c
>> index b010e5f..704f506 100644
>> --- a/arch/arm/mach-davinci/usb-da8xx.c
>> +++ b/arch/arm/mach-davinci/usb-da8xx.c
>> @@ -22,6 +22,8 @@
>> #define DA8XX_USB0_BASE 0x01e00000
>> #define DA8XX_USB1_BASE 0x01e25000
>>
>> +static struct clk *usb20_clk;
>> +
>> static struct platform_device da8xx_usb_phy = {
>> .name = "da8xx-usb-phy",
>> .id = -1,
>> @@ -158,21 +160,14 @@ int __init da8xx_register_usb_refclkin(int rate)
>>
>> static void usb20_phy_clk_enable(struct clk *clk)
>> {
>> - struct clk *usb20_clk;
>> int err;
>> u32 val;
>> u32 timeout = 500000; /* 500 msec */
>>
>> val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
>>
>> - usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
>> - if (IS_ERR(usb20_clk)) {
>> - pr_err("could not get usb20 clk: %ld\n", PTR_ERR(usb20_clk));
>> - return;
>> - }
>> -
>> /* The USB 2.O PLL requires that the USB 2.O PSC is enabled as
>> well. */
>> - err = clk_prepare_enable(usb20_clk);
>> + err = clk_enable(usb20_clk);
>> if (err) {
>> pr_err("failed to enable usb20 clk: %d\n", err);
>> clk_put(usb20_clk);
>
> Need to remove clk_put() here.
I will do.
>
>> @@ -197,8 +192,7 @@ static void usb20_phy_clk_enable(struct clk *clk)
>>
>> pr_err("Timeout waiting for USB 2.0 PHY clock good\n");
>> done:
>> - clk_disable_unprepare(usb20_clk);
>> - clk_put(usb20_clk);
>> + clk_disable(usb20_clk);
>> }
>>
>> static void usb20_phy_clk_disable(struct clk *clk)
>> @@ -285,11 +279,19 @@ static struct clk_lookup usb20_phy_clk_lookup =
>> int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
>> {
>> struct clk *parent;
>> - int ret = 0;
>> + int ret;
>> +
>> + usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
>> + ret = PTR_ERR_OR_ZERO(usb20_clk);
>> + if (ret)
>> + return ret;
>>
>> parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" :
>> "pll0_aux");
>> - if (IS_ERR(parent))
>> - return PTR_ERR(parent);
>> + ret = PTR_ERR_OR_ZERO(parent);
>> + if (ret) {
>> + clk_put(usb20_clk);
>> + return ret;
>> + }
>>
>> usb20_phy_clk.parent = parent;
>> ret = clk_register(&usb20_phy_clk);
>>
>
>
> I have just tried this patch with a bunch of kernel hacking options
> enabled. I am getting the message show at the end of this email. We
> still have the problem of nested spin locks due to nested calls to
> clk_enable(). So, really, we need to use __clk_enable() and
> __clk_disable() from arch/arm/mach-davinci/clock.c in
> usb20_phy_clk_enable() above.
>
> Applying the following patch on top of your patch fixed the recursive
> lock message.
Good catch.
Thanks,
Alexandre
>
> ---
>
> diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
> index df42c93..4fba579 100644
> --- a/arch/arm/mach-davinci/clock.c
> +++ b/arch/arm/mach-davinci/clock.c
> @@ -31,7 +31,7 @@ static LIST_HEAD(clocks);
> static DEFINE_MUTEX(clocks_mutex);
> static DEFINE_SPINLOCK(clockfw_lock);
>
> -static void __clk_enable(struct clk *clk)
> +void __clk_enable(struct clk *clk)
> {
> if (clk->parent)
> __clk_enable(clk->parent);
> @@ -44,7 +44,7 @@ static void __clk_enable(struct clk *clk)
> }
> }
>
> -static void __clk_disable(struct clk *clk)
> +void __clk_disable(struct clk *clk)
> {
> if (WARN_ON(clk->usecount == 0))
> return;
> diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
> index e2a5437..8493242 100644
> --- a/arch/arm/mach-davinci/clock.h
> +++ b/arch/arm/mach-davinci/clock.h
> @@ -136,6 +136,9 @@ int davinci_clk_reset(struct clk *clk, bool reset);
> extern struct platform_device davinci_wdt_device;
> extern void davinci_watchdog_reset(struct platform_device *);
>
> +void __clk_enable(struct clk *clk);
> +void __clk_disable(struct clk *clk);
> +
> #endif
>
> #endif
> diff --git a/arch/arm/mach-davinci/usb-da8xx.c
> b/arch/arm/mach-davinci/usb-da8xx
> .c
> index 896d014..80ba0df 100644
> --- a/arch/arm/mach-davinci/usb-da8xx.c
> +++ b/arch/arm/mach-davinci/usb-da8xx.c
> @@ -160,19 +160,13 @@ int __init da8xx_register_usb_refclkin(int rate)
>
> static void usb20_phy_clk_enable(struct clk *clk)
> {
> - int err;
> u32 val;
> u32 timeout = 500000; /* 500 msec */
>
> val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
>
> /* The USB 2.O PLL requires that the USB 2.O PSC is enabled as
> well. */
> - err = clk_enable(usb20_clk);
> - if (err) {
> - pr_err("failed to enable usb20 clk: %d\n", err);
> - clk_put(usb20_clk);
> - return;
> - }
> + __clk_enable(usb20_clk);
>
> /*
> * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The
> USB 1.1
> @@ -192,7 +186,7 @@ static void usb20_phy_clk_enable(struct clk *clk)
>
> pr_err("Timeout waiting for USB 2.0 PHY clock good\n");
> done:
> - clk_disable(usb20_clk);
> + __clk_disable(usb20_clk);
> }
>
> static void usb20_phy_clk_disable(struct clk *clk)
>
>
>
> ---
>
>
> =============================================
> [ INFO: possible recursive locking detected ]
> 4.9.0-rc8-dlech-ev3-lms2012+ #22 Not tainted
> ---------------------------------------------
> swapper/1 is trying to acquire lock:
> (
> clockfw_lock
> ){......}
> , at:
> [<c0014884>] clk_enable+0x24/0x50
> k:
> (
> clockfw_lock
> ){......}
> , at:
> [<c0014884>] clk_enable+0x24/0x50
> ebug this:
> Possible unsafe locking scenario:
> CPU0
> ----
> lock(
> clockfw_lock
> );
> lock(
> clockfw_lock
> );
> May be due to missing lock nesting notation
> 4 locks held by swapper/1:
> #0:
> (
> &dev->mutex
> ){......}
> , at:
> [<c02bd60c>] __driver_attach+0x68/0xb4
> #1:
> (
> &dev->mutex
> ){......}
> , at:
> [<c02bd61c>] __driver_attach+0x78/0xb4
> #2:
> (
> &phy->mutex
> ){+.+...}
> , at:
> [<c025ee18>] phy_power_on+0x5c/0xe4
> #3:
> (
> clockfw_lock
> ){......}
> , at:
> [<c0014884>] clk_enable+0x24/0x50
> CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.0-rc8-dlech-ev3-lms2012+ #22
> Hardware name: Generic DA850/OMAP-L138/AM18x
> Backtrace:
> [<c000d824>] (dump_backtrace) from [<c000dac4>] (show_stack+0x18/0x1c)
> r7:c0e998a4 r6:c0820750 r5:c0820750 r4:c3838000
> [<c000daac>] (show_stack) from [<c02393dc>] (dump_stack+0x20/0x28)
> [<c02393bc>] (dump_stack) from [<c004bd7c>] (__lock_acquire+0x10f4/0x167c)
> [<c004ac88>] (__lock_acquire) from [<c004c6ac>] (lock_acquire+0x78/0x98)
> r10:00000000 r9:c06a5ed4 r8:00000000 r7:00000001 r6:60000093 r5:00000000
> r4:ffffe000
> [<c004c634>] (lock_acquire) from [<c04d8fac>]
> (_raw_spin_lock_irqsave+0x60/0x74)
> r7:0000003b r6:c0014884 r5:80000093 r4:c06b09a0
> [<c04d8f4c>] (_raw_spin_lock_irqsave) from [<c0014884>]
> (clk_enable+0x24/0x50)
> r6:c06f69f4 r5:0001ef02 r4:c06b3398
> [<c0014860>] (clk_enable) from [<c0015c74>]
> (usb20_phy_clk_enable+0x24/0xb8)
> r5:0001ef02 r4:c06f69f0
> [<c0015c50>] (usb20_phy_clk_enable) from [<c0014858>]
> (__clk_enable+0x74/0x7c)
> r9:c06a5ed4 r8:00000000 r7:0000003b r6:c3a6ca00 r5:80000013 r4:c06b7ee8
> [<c00147e4>] (__clk_enable) from [<c0014808>] (__clk_enable+0x24/0x7c)
> r4:c06b8648
> [<c00147e4>] (__clk_enable) from [<c0014890>] (clk_enable+0x30/0x50)
> r4:c06b8648
> [<c0014860>] (clk_enable) from [<c025f43c>]
> (da8xx_usb11_phy_power_on+0x30/0x80)
> r5:c3a54050 r4:c06b8648
> [<c025f40c>] (da8xx_usb11_phy_power_on) from [<c025ee3c>]
> (phy_power_on+0x80/0xe4)
> r5:c3a6c800 r4:fffffdf4
> [<c025edbc>] (phy_power_on) from [<c032243c>] (ohci_da8xx_enable+0x4c/0x80)
> r7:0000003b r6:c3af6000 r5:c3af6000 r4:00000000
> [<c03223f0>] (ohci_da8xx_enable) from [<c03224f0>]
> (ohci_da8xx_reset+0x1c/0xd8)
> r5:00000000 r4:c3af6000
> [<c03224d4>] (ohci_da8xx_reset) from [<c0309118>] (usb_add_hcd+0x314/0x834)
> r7:0000003b r6:ffffffed r5:00000000 r4:c3af6000
> [<c0308e04>] (usb_add_hcd) from [<c032200c>] (ohci_da8xx_probe+0x14c/0x21c)
> r9:c06a5ed4 r8:00000000 r7:c38bd010 r6:c38bd000 r5:c3af6000 r4:c38af900
> [<c0321ec0>] (ohci_da8xx_probe) from [<c02bec44>]
> (platform_drv_probe+0x40/0x8c)
> r7:c06e610c r6:c06e610c r5:c38bd010 r4:c0321ec0
> [<c02bec04>] (platform_drv_probe) from [<c02bd438>]
> (driver_probe_device+0x138/0x2a4)
> r7:c06e610c r6:c0e9db10 r5:00000000 r4:c38bd010
> [<c02bd300>] (driver_probe_device) from [<c02bd634>]
> (__driver_attach+0x90/0xb4)
> r9:c06a5ed4 r8:c06f66e0 r7:c06e1250 r6:c06e610c r5:c38bd044 r4:c38bd010
> [<c02bd5a4>] (__driver_attach) from [<c02bba5c>]
> (bus_for_each_dev+0x74/0x98)
> r7:c06e1250 r6:c02bd5a4 r5:c06e610c r4:00000000
> [<c02bb9e8>] (bus_for_each_dev) from [<c02bcf2c>] (driver_attach+0x20/0x28)
> r6:c39a2300 r5:00000000 r4:c06e610c
> [<c02bcf0c>] (driver_attach) from [<c02bca80>] (bus_add_driver+0xd4/0x1f0)
> [<c02bc9ac>] (bus_add_driver) from [<c02bdcec>] (driver_register+0xa4/0xe8)
> r7:c0698850 r6:00000000 r5:00000000 r4:c06e610c
> [<c02bdc48>] (driver_register) from [<c02bebac>]
> (__platform_driver_register+0x38/0x4c)
> r5:00000000 r4:c06acce4
> [<c02beb74>] (__platform_driver_register) from [<c068da20>]
> (ohci_da8xx_init+0x64/0x90)
> [<c068d9bc>] (ohci_da8xx_init) from [<c00096c0>]
> (do_one_initcall+0xb0/0x168)
> r5:c068d9bc r4:ffffe000
> [<c0009610>] (do_one_initcall) from [<c0676e14>]
> (kernel_init_freeable+0x110/0x1cc)
> r9:c06a5ed4 r8:c06f66e0 r7:c0698850 r6:000000c1 r5:c06f66e0 r4:00000007
> [<c0676d04>] (kernel_init_freeable) from [<c04d37e4>]
> (kernel_init+0x10/0xf8)
> r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c04d37d4 r4:00000000
> [<c04d37d4>] (kernel_init) from [<c000a2ac>] (ret_from_fork+0x14/0x28)
> r5:c04d37d4 r4:00000000
> BUG: spinlock lockup suspected on CPU#0, swapper/1
> lock: clockfw_lock+0x0/0x20, .magic: dead4ead, .owner: swapper/1,
> .owner_cpu: 0
> CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.0-rc8-dlech-ev3-lms2012+ #22
> Hardware name: Generic DA850/OMAP-L138/AM18x
> Backtrace:
> [<c000d824>] (dump_backtrace) from [<c000dac4>] (show_stack+0x18/0x1c)
> r7:00000000 r6:04605000 r5:c06b09a0 r4:c3838000
> [<c000daac>] (show_stack) from [<c02393dc>] (dump_stack+0x20/0x28)
> [<c02393bc>] (dump_stack) from [<c004f140>] (spin_dump+0x80/0x94)
> [<c004f0c0>] (spin_dump) from [<c004f2c4>] (do_raw_spin_lock+0xdc/0x11c)
> r5:00000000 r4:c06b09a0
> [<c004f1e8>] (do_raw_spin_lock) from [<c04d8fb4>]
> (_raw_spin_lock_irqsave+0x68/0x74)
> r10:00000000 r9:c06a5ed4 r8:00000000 r7:0000003b r6:c0014884 r5:80000093
> r4:c06b09a0 r3:c3838000
> [<c04d8f4c>] (_raw_spin_lock_irqsave) from [<c0014884>]
> (clk_enable+0x24/0x50)
> r6:c06f69f4 r5:0001ef02 r4:c06b3398
> [<c0014860>] (clk_enable) from [<c0015c74>]
> (usb20_phy_clk_enable+0x24/0xb8)
> r5:0001ef02 r4:c06f69f0
> [<c0015c50>] (usb20_phy_clk_enable) from [<c0014858>]
> (__clk_enable+0x74/0x7c)
> r9:c06a5ed4 r8:00000000 r7:0000003b r6:c3a6ca00 r5:80000013 r4:c06b7ee8
> [<c00147e4>] (__clk_enable) from [<c0014808>] (__clk_enable+0x24/0x7c)
> r4:c06b8648
> [<c00147e4>] (__clk_enable) from [<c0014890>] (clk_enable+0x30/0x50)
> r4:c06b8648
> [<c0014860>] (clk_enable) from [<c025f43c>]
> (da8xx_usb11_phy_power_on+0x30/0x80)
> r5:c3a54050 r4:c06b8648
> [<c025f40c>] (da8xx_usb11_phy_power_on) from [<c025ee3c>]
> (phy_power_on+0x80/0xe4)
> r5:c3a6c800 r4:fffffdf4
> [<c025edbc>] (phy_power_on) from [<c032243c>] (ohci_da8xx_enable+0x4c/0x80)
> r7:0000003b r6:c3af6000 r5:c3af6000 r4:00000000
> [<c03223f0>] (ohci_da8xx_enable) from [<c03224f0>]
> (ohci_da8xx_reset+0x1c/0xd8)
> r5:00000000 r4:c3af6000
> [<c03224d4>] (ohci_da8xx_reset) from [<c0309118>] (usb_add_hcd+0x314/0x834)
> r7:0000003b r6:ffffffed r5:00000000 r4:c3af6000
> [<c0308e04>] (usb_add_hcd) from [<c032200c>] (ohci_da8xx_probe+0x14c/0x21c)
> r9:c06a5ed4 r8:00000000 r7:c38bd010 r6:c38bd000 r5:c3af6000 r4:c38af900
> [<c0321ec0>] (ohci_da8xx_probe) from [<c02bec44>]
> (platform_drv_probe+0x40/0x8c)
> r7:c06e610c r6:c06e610c r5:c38bd010 r4:c0321ec0
> [<c02bec04>] (platform_drv_probe) from [<c02bd438>]
> (driver_probe_device+0x138/0x2a4)
> r7:c06e610c r6:c0e9db10 r5:00000000 r4:c38bd010
> [<c02bd300>] (driver_probe_device) from [<c02bd634>]
> (__driver_attach+0x90/0xb4)
> r9:c06a5ed4 r8:c06f66e0 r7:c06e1250 r6:c06e610c r5:c38bd044 r4:c38bd010
> [<c02bd5a4>] (__driver_attach) from [<c02bba5c>]
> (bus_for_each_dev+0x74/0x98)
> r7:c06e1250 r6:c02bd5a4 r5:c06e610c r4:00000000
> [<c02bb9e8>] (bus_for_each_dev) from [<c02bcf2c>] (driver_attach+0x20/0x28)
> r6:c39a2300 r5:00000000 r4:c06e610c
> [<c02bcf0c>] (driver_attach) from [<c02bca80>] (bus_add_driver+0xd4/0x1f0)
> [<c02bc9ac>] (bus_add_driver) from [<c02bdcec>] (driver_register+0xa4/0xe8)
> r7:c0698850 r6:00000000 r5:00000000 r4:c06e610c
> [<c02bdc48>] (driver_register) from [<c02bebac>]
> (__platform_driver_register+0x38/0x4c)
> r5:00000000 r4:c06acce4
> [<c02beb74>] (__platform_driver_register) from [<c068da20>]
> (ohci_da8xx_init+0x64/0x90)
> [<c068d9bc>] (ohci_da8xx_init) from [<c00096c0>]
> (do_one_initcall+0xb0/0x168)
> r5:c068d9bc r4:ffffe000
> [<c0009610>] (do_one_initcall) from [<c0676e14>]
> (kernel_init_freeable+0x110/0x1cc)
> r9:c06a5ed4 r8:c06f66e0 r7:c0698850 r6:000000c1 r5:c06f66e0 r4:00000007
> [<c0676d04>] (kernel_init_freeable) from [<c04d37e4>]
> (kernel_init+0x10/0xf8)
> r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c04d37d4 r4:00000000
> [<c04d37d4>] (kernel_init) from [<c000a2ac>] (ret_from_fork+0x14/0x28)
> r5:c04d37d4 r4:00000000
^ permalink raw reply
* ILP32 for ARM64: testing with glibc testsuite
From: Zhangjian (Bamvor) @ 2016-12-05 9:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479419136.908.90.camel@caviumnetworks.com>
Hi, Steve
On 2016/11/18 5:45, Steve Ellcey wrote:
> On Wed, 2016-11-16 at 15:22 +0400, Maxim Kuvyrkov wrote:
>>>
>>> On Nov 9, 2016, at 1:56 PM, Yury Norov <ynorov@caviumnetworks.com>
>>> wrote:
>>>
>>>>
>>>> Below is the results of glibc testsuite run for aarch64/lp64
>
> I have been running the glibc testsuite as well. I have only run it on
> an ILP32 enabled kernel. Using that kernel, top-of-tree glibc, and the
> ILP32 glibc patches I have no LP64 regressions. There are 5 failures
> in LP64 mode but I get them with vanilla top-of-tree glibc sources too.
> They are:
> nptl/eintr1 (I actually don't run this because it kills the 'make check')
> debug/tst-backtrace5
> debug/tst-backtrace6
> nptl/tst-stack4
> nptl/tst-thread_local1
>
> In ILP32 mode I get 33 failures, they include the above failures (minus
> nptl/tst-thread_local1) plus:
>
> c++-types-check
> conform/ISO11/inttypes.h/conform
> conform/ISO11/stdint.h/conform
> conform/ISO99/inttypes.h/conform
> conform/ISO99/stdint.h/conform
> conform/POSIX2008/inttypes.h/conform
> conform/POSIX2008/stdint.h/conform
> conform/XOPEN2K/inttypes.h/conform
> conform/XOPEN2K/stdint.h/conform
> conform/XOPEN2K8/inttypes.h/conform
> conform/XOPEN2K8/stdint.h/conform
> elf/tst-tls1
> elf/tst-tls1-static
> elf/tst-tls2
> elf/tst-tls2-static
> elf/tst-tls3
> math/check-abi-libm
> math/test-double
> math/test-double-finite
> math/test-float
> math/test-float-finite
> misc/tst-sync_file_range
> nptl/tst-cancel26
> nptl/tst-cancel27
> nptl/tst-sem3
> rt/tst-mqueue1
> rt/tst-mqueue2
> rt/tst-mqueue4
> rt/tst-mqueue7
> stdlib/tst-makecontext3
>
> I am currently looking at these ILP32 regressions (starting with the
> tls failures) to see if I can figure out what is happening with them.
Is there some progresses on it? We could collabrate to fix those issues.
Regards
Bamvor
>
> Steve Ellcey
> sellcey at caviumnetworks.com
>
^ permalink raw reply
* [stable:PATCH 0/3] PAN fixes backport for v4.4.35
From: James Morse @ 2016-12-05 9:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202172321.GA25426@kroah.com>
Hi Greg,
On 02/12/16 17:23, Greg KH wrote:
> 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?
Patch 1 doesn't backport easily. I was going to do v4.8 next, but thought one at
a time would be the least confusing...
(I don't seem to be very good at predicting what is confusing!)
Thanks,
James
^ permalink raw reply
* [PATCH v9 07/16] drivers: acpi: implement acpi_dma_configure
From: Sricharan @ 2016-12-05 9:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJZ5v0j5aMMyNsYpnbGXbJdDrbHFN5u03mQi+W6WK97iCdB2HA@mail.gmail.com>
Hi Lorenzo,
>
>On Sat, Dec 3, 2016 at 11:39 AM, Lorenzo Pieralisi
><lorenzo.pieralisi@arm.com> wrote:
>> On Sat, Dec 03, 2016 at 03:11:09AM +0100, Rafael J. Wysocki wrote:
>>> On Fri, Dec 2, 2016 at 4:38 PM, Lorenzo Pieralisi
>>> <lorenzo.pieralisi@arm.com> wrote:
>>> > Rafael, Mark, Suravee,
>>> >
>>> > On Mon, Nov 21, 2016 at 10:01:39AM +0000, Lorenzo Pieralisi wrote:
>>> >> On DT based systems, the of_dma_configure() API implements DMA
>>> >> configuration for a given device. On ACPI systems an API equivalent to
>>> >> of_dma_configure() is missing which implies that it is currently not
>>> >> possible to set-up DMA operations for devices through the ACPI generic
>>> >> kernel layer.
>>> >>
>>> >> This patch fills the gap by introducing acpi_dma_configure/deconfigure()
>>> >> calls that for now are just wrappers around arch_setup_dma_ops() and
>>> >> arch_teardown_dma_ops() and also updates ACPI and PCI core code to use
>>> >> the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions.
>>> >>
>>> >> Since acpi_dma_configure() is used to configure DMA operations, the
>>> >> function initializes the dma/coherent_dma masks to sane default values
>>> >> if the current masks are uninitialized (also to keep the default values
>>> >> consistent with DT systems) to make sure the device has a complete
>>> >> default DMA set-up.
>>> >
>>> > I spotted a niggle that unfortunately was hard to spot (and should not
>>> > be a problem per se but better safe than sorry) and I am not comfortable
>>> > with it.
>>> >
>>> > Following commit d0562674838c ("ACPI / scan: Parse _CCA and setup
>>> > device coherency") in acpi_bind_one() we check if the acpi_device
>>> > associated with a device just added supports DMA, first it was
>>> > done with acpi_check_dma() and then commit 1831eff876bd ("device
>>> > property: ACPI: Make use of the new DMA Attribute APIs") changed
>>> > it to acpi_get_dma_attr().
>>> >
>>> > The subsequent check (attr != DEV_DMA_NOT_SUPPORTED) is always true
>>> > on _any_ acpi device we pass to acpi_bind_one() on x86, which was
>>> > fine because we used it to call arch_setup_dma_ops(), which is a nop
>>> > on x86. On ARM64 a _CCA method is required to define if a device
>>> > supports DMA so (attr != DEV_DMA_NOT_SUPPORTED) may well be false.
>>> >
>>> > Now, acpi_bind_one() is used to bind an acpi_device to its physical
>>> > node also for pseudo-devices like cpus and memory nodes. For those
>>> > objects, on x86, attr will always be != DEV_DMA_NOT_SUPPORTED.
>>> >
>>> > So far so good, because on x86 arch_setup_dma_ops() is empty code.
>>> >
>>> > With this patch, I use the (attr != DEV_DMA_NOT_SUPPORTED) check
>>> > to call acpi_dma_configure() which is basically a nop on x86 except
>>> > that it sets up the dma_mask/coherent_dma_mask to a sane default value
>>> > (after all we are setting up DMA for the device so it makes sense to
>>> > initialize the masks there if they were unset since we are configuring
>>> > DMA for the device in question) for the given device.
>>> >
>>> > Problem is, as per the explanation above, we are also setting the
>>> > default dma masks for pseudo-devices (eg CPUs) that were previously
>>> > untouched, it should not be a problem per-se but I am not comfortable
>>> > with that, honestly it does not make much sense.
>>> >
>>> > An easy "fix" would be to move the default dma masks initialization out
>>> > of acpi_dma_configure() (as it was in previous patch versions of this
>>> > series - I moved it to acpi_dma_configure() just a consolidation point
>>> > for initializing the masks instead of scattering them in every
>>> > acpi_dma_configure caller) I can send this as a fix-up patch to Joerg if
>>> > we think that's the right thing to do (or I can send it to Rafael later
>>> > when the code is in the merged depending on the timing) just let me
>>> > know please.
>>>
>>> Why can't arch_setup_dma_ops() set those masks too?
>>
>> Because the dma masks set-up is done by the caller (see
>> of_dma_configure()) according to firmware configuration or
>> platform data knowledge. I wanted to replicate the of_dma_configure()
>> interface on ACPI for obvious reasons (on ARM systems), I stopped
>> short of adding ACPI code to mirror of_dma_get_range() equivalent
>> (through the _DMA object) but I am really really nervous about changing
>> the code path on x86 because in theory all is fine, in practice even
>> just setting the masks to sane values can have unexpected consequences,
>> I just can't know (that's why I wasn't doing it in the first iterations
>> of this series).
>>
>> Side note: DT with of_dma_configure() and ACPI with
>> acpi_create_platform_device() set the default dma mask for all
>> platform devices already _regardless_ of what they really are, though
>> arguably acpi_bind_one() touches ways more devices.
>>
>> I really think that removing the default dma masks settings from
>> acpi_dma_configure() is the safer thing to do for the time being (or
>> moving acpi_dma_configure() to acpi_create_platform_device(), where the
>> DMA masks are set-up by default by core ACPI. Mark, Suravee, what was
>> the rationale behind calling arch_setup_dma_ops() in acpi_bind_one() ?)
>
>Alternatively, you can add one more arch wrapper that will be a no-op
>on x86 and that will set up the default masks and call
>arch_setup_dma_ops() on ARM. Then, you can invoke that from
>acpi_dma_configure().
>
>Or make the definition of acpi_dma_configure() itself depend on the
>architecture.
>
So is it better that either removing the masks from acpi_dma_configure (or)
creating the wrapper as Rafael mentioned, than moving
acpi_dma_configure itself , because with something like iommu probe
deferral that is tried, acpi_dma_configure is getting invoked from a device's
really_probe, a different path again ?
Regards,
Sricharan
^ permalink raw reply
* [PATCH 3/8] rtc: add STM32 RTC driver
From: Amelie DELAUNAY @ 2016-12-05 9:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202180527.GB3284@linaro.org>
On 12/02/2016 07:05 PM, Mathieu Poirier wrote:
> 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.
You're right.
>
>> +
>> +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
>>
Best regards,
Amelie
^ permalink raw reply
* [PATCH 3/8] rtc: add STM32 RTC driver
From: Amelie DELAUNAY @ 2016-12-05 9:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202175646.GA3284@linaro.org>
Hi Mathieu,
Thanks for reviewing
On 12/02/2016 06:56 PM, Mathieu Poirier wrote:
> 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.
During development phase, it is useful to add debug traces but you're
right, this can be remove.
>
>> +
>> +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?
Hum, as surprising as it may seem, checkpatch didn't complained about
these comments! But anyway, this has to be removed, it was a tentative
to enable/disable backup domain write protection any time we have to
write in a protected RTC register, but it is not functionnal. I have
commented this just to keep it in mind and forget to remove it before
sending.
>
>> +
>> + 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.
Sure. It takes around 2 RTCCLK clock cycles to enter in initialization
phase mode. So it depends on the frequency of the ck_rtc parent clock.
Either I keep parent clock frequency and compute the exact timeout, or I
use the "best and worst cases": slowest RTCCLK frequency is 32kHz, so it
can take up to 62us, highest RTCCLK frequency should be 1MHz, so it can
take only 2us. Polling every 10us with a timeout of 100ms seemed
reasonable and be a good compromise.
>
>> + }
>> +
>> + 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.
RSF bit is set by hardware each time the calendar registers are
synchronized (it takes up to 2 RTCCLK). So the break condition is
correct: we poll until RSF flag is set or timeout is reached.
>
>> +}
>> +
>> +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.
You're right.
>
>> +
>> + 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.
res is checked in devm_ioremap_resource just below :
if (!res || resource_type(res) != IORESOURCE_MEM) {
dev_err(dev, "invalid resource\n");
return IOMEM_ERR_PTR(-EINVAL);
}
That's why it is not checked here.
>
>> + 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.
You're right.
>
>> +
>> + 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?
It means that RTC won't be able to wake up the board with RTC alarm. I
can add a warning for the user in this case ?
>
>> +
>> + 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.
OK.
>
>> +
>> + 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
>>
Best regards,
Amelie
^ permalink raw reply
* [PATCH v2 2/3] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Maxime Ripard @ 2016-12-05 9:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205120021.0GBGtAl4@smtp3m.mail.yandex.net>
On Mon, Dec 05, 2016 at 04:59:44PM +0800, Icenowy Zheng wrote:
>
> 2016?12?5? 16:52? Maxime Ripard <maxime.ripard@free-electrons.com>???
> >
> > On Fri, Dec 02, 2016 at 10:22:30PM +0800, 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" ' .
> >
> > You can't ask that from the majority of users. These users will take
> > debian or fedora, install it, and expect everything to work
> > properly. I would make the opposite argument actually. If someone is
> > knowledgeable enough to solder the USB pins a connector, then (s)he'll
> > be able to make that u-boot call.
>
> Now (s)he do not need soldering.
>
> (S)he needs only paying $1.99 more to Xunlong to get the expansion
> board, and insert it on the OPi Zero.
Which is going to require an overlay anyway, so we could have the USB
bits in there too.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/194dd5d6/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: dts: sunxi: Add num-cs for A20 spi nodes
From: Emmanuel Vadot @ 2016-12-05 9:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205092821.m2fmqxnzalcignly@lukather>
On Mon, 5 Dec 2016 10:28:21 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> On Thu, Dec 01, 2016 at 11:24:14AM +0100, Emmanuel Vadot wrote:
> > > > > > If num-cs isn't present nothing prevent to start a transfer
> > > > > > with a non-valid CS pin, resulting in an error. num-cs are
> > > > > > default property especially made for this and a SPI driver
> > > > > > should try to get the property at probe/attach time.
> > > > >
> > > > > Yes, but as far as I know, our driver doesn't. I'm all in for
> > > > > having support for that in our driver, but without it, that
> > > > > patch is kind of useless.
> > > >
> > > > Yes the Linux driver doesn't use it but my upcoming one for FreeBSD
> > > > uses it. So it is not useless for downstream user of DTS.
> > >
> > > Ah, I didn't know this was for FreeBSD. So you started to use our DTs,
> > > or do you have some modifications to it? How does that work?
> >
> > Yes we use the DTS from linux from quite some times now. We're
> > currently synced with 4.7-ish. We either use them directly or
> > modify them according to our needs and driver support.
>
> Do you have a link to those modifications?
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
Sure,
https://svnweb.freebsd.org/base/head/sys/boot/fdt/dts/arm/
--
Emmanuel Vadot <manu@bidouilliste.com> <manu@freebsd.org>
^ permalink raw reply
* [PATCH] arm/arm64: KVM: Check for properly initialized timer on init
From: Christoffer Dall @ 2016-12-05 9:32 UTC (permalink / raw)
To: linux-arm-kernel
When the arch timer code fails to initialize (for example because the
memory mapped timer doesn't work, which is currently seen with the AEM
model), then KVM just continues happily with a final result that KVM
eventually does a NULL pointer dereference of the uninitialized cycle
counter.
Check directly for this in the init path and give the user a reasonable
error in this case.
Cc: Shih-Wei Li <shihwei@cs.columbia.edu>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
virt/kvm/arm/arch_timer.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 27a1f63..5c12f53 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -425,6 +425,11 @@ int kvm_timer_hyp_init(void)
info = arch_timer_get_kvm_info();
timecounter = &info->timecounter;
+ if (!timecounter->cc) {
+ kvm_err("arch_timer: uninitialized timecounter\n");
+ return -ENODEV;
+ }
+
if (info->virtual_irq <= 0) {
kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
info->virtual_irq);
--
2.9.0
^ permalink raw reply related
* [PATCH v3 0/4] mm: fix the "counter.sh" failure for libhugetlbfs
From: Michal Hocko @ 2016-12-05 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480929431-22348-1-git-send-email-shijie.huang@arm.com>
On Mon 05-12-16 17:17:07, Huang Shijie wrote:
[...]
> The failure is caused by:
> 1) kernel fails to allocate a gigantic page for the surplus case.
> And the gather_surplus_pages() will return NULL in the end.
>
> 2) The condition checks for some functions are wrong:
> return_unused_surplus_pages()
> nr_overcommit_hugepages_store()
> hugetlb_overcommit_handler()
OK, so how is this any different from gigantic (1G) hugetlb pages on
x86_64? Do we need the same functionality or is it just 32MB not being
handled in the same way as 1G?
Thanks!
--
Michal Hocko
SUSE Labs
^ permalink raw reply
* [PATCH] ARM: dts: sunxi: Add num-cs for A20 spi nodes
From: Maxime Ripard @ 2016-12-05 9:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201112414.62f9b351186115f62c8998a9@bidouilliste.com>
On Thu, Dec 01, 2016 at 11:24:14AM +0100, Emmanuel Vadot wrote:
> > > > > If num-cs isn't present nothing prevent to start a transfer
> > > > > with a non-valid CS pin, resulting in an error. num-cs are
> > > > > default property especially made for this and a SPI driver
> > > > > should try to get the property at probe/attach time.
> > > >
> > > > Yes, but as far as I know, our driver doesn't. I'm all in for
> > > > having support for that in our driver, but without it, that
> > > > patch is kind of useless.
> > >
> > > Yes the Linux driver doesn't use it but my upcoming one for FreeBSD
> > > uses it. So it is not useless for downstream user of DTS.
> >
> > Ah, I didn't know this was for FreeBSD. So you started to use our DTs,
> > or do you have some modifications to it? How does that work?
>
> Yes we use the DTS from linux from quite some times now. We're
> currently synced with 4.7-ish. We either use them directly or
> modify them according to our needs and driver support.
Do you have a link to those modifications?
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/7f666e1b/attachment-0001.sig>
^ 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