Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv2 1/5] clk: mvebu: support for 98DX3236 SoC
From: Mark Rutland @ 2017-01-05 13:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-2-chris.packham@alliedtelesis.co.nz>

On Thu, Jan 05, 2017 at 04:36:37PM +1300, Chris Packham wrote:
> The 98DX3236, 98DX3336, 98DX4521 and variants have a different TCLK from
> the Armada XP (200MHz vs 250MHz). The CPU core clock is fixed at 800MHz.
> 
> The clock gating options are a subset of those on the Armada XP.
> 
> The core clock divider is different to the Armada XP also.
> 
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> Changes in v2:
> - Update devicetree binding documentation for new compatible string
> 
>  .../devicetree/bindings/clock/mvebu-cpu-clock.txt  |   1 +
>  drivers/clk/mvebu/Makefile                         |   2 +-
>  drivers/clk/mvebu/armada-xp.c                      |  42 +++++
>  drivers/clk/mvebu/clk-cpu.c                        |  33 +++-
>  drivers/clk/mvebu/mv98dx3236-corediv.c             | 207 +++++++++++++++++++++
>  5 files changed, 281 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/clk/mvebu/mv98dx3236-corediv.c


It looks like you also need to update
Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt for the
addition of "marvell,mv98dx3236-corediv-clock".

> 
> diff --git a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
> index 99c214660bdc..7f28506eaee7 100644
> --- a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
> +++ b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
> @@ -3,6 +3,7 @@ Device Tree Clock bindings for cpu clock of Marvell EBU platforms
>  Required properties:
>  - compatible : shall be one of the following:
>  	"marvell,armada-xp-cpu-clock" - cpu clocks for Armada XP
> +	"marvell,mv98dx3236-cpu-clock" - cpu clocks for 98DX3236 SoC
>  - reg : Address and length of the clock complex register set, followed
>          by address and length of the PMU DFS registers
>  - #clock-cells : should be set to 1.

[...]

> +static void __init mv98dx3236_corediv_clk_init(struct device_node *node)
> +{
> +	struct clk_init_data init;
> +	struct clk_corediv *corediv;
> +	struct clk **clks;
> +	void __iomem *base;
> +	const __be32 *off;
> +	const char *parent_name;
> +	const char *clk_name;
> +	int len;
> +	struct device_node *dfx_node;
> +
> +	dfx_node = of_parse_phandle(node, "base", 0);
> +	if (WARN_ON(!dfx_node))

What's going on here? The existing bingings don't mention a "base"
phandle, and nothing was added to describe it.

> +		return;
> +
> +	off = of_get_property(node, "reg", &len);
> +	if (WARN_ON(!off))
> +		return;

Please don't use of_get_property directly; generally you should use the
existing higher-level helpers like of_proeprty_read_u32().

> +
> +	base = of_iomap(dfx_node, 0);
> +	if (WARN_ON(!base))
> +		return;
> +
> +	of_node_put(dfx_node);
> +
> +	parent_name = of_clk_get_parent_name(node, 0);
> +
> +	clk_data.clk_num = 1;
> +
> +	/* clks holds the clock array */
> +	clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
> +				GFP_KERNEL);
> +	if (WARN_ON(!clks))
> +		goto err_unmap;
> +	/* corediv holds the clock specific array */
> +	corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
> +				GFP_KERNEL);
> +	if (WARN_ON(!corediv))
> +		goto err_free_clks;
> +
> +	spin_lock_init(&corediv->lock);
> +
> +	of_property_read_string_index(node, "clock-output-names",
> +					  0, &clk_name);
> +
> +	init.num_parents = 1;
> +	init.parent_names = &parent_name;
> +	init.name = clk_name;
> +	init.ops = &ops;
> +	init.flags = 0;
> +
> +	corediv[0].reg = (void *)((int)base + be32_to_cpu(*off));

I don't understand this, but I guess this has something to do with that
base phandle. Is the corediv clock a sub-component of some "base" clock?
I don't think this binding is the best way of describing that.

Thanks,
Mark.

^ permalink raw reply

* [PATCH 02/10] iommu/of: Prepare for deferred IOMMU configuration
From: Robin Murphy @ 2017-01-05 13:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105122714.GA30449@red-moon>

On 05/01/17 12:27, Lorenzo Pieralisi wrote:
> On Thu, Jan 05, 2017 at 02:04:37PM +0530, Sricharan wrote:
>> Hi Robin/Lorenzo,
>>
>>> Hi Robin,Lorenzo,
>>>
>>>> On Wed, Nov 30, 2016 at 04:42:27PM +0000, Robin Murphy wrote:
>>>>> On 30/11/16 16:17, Lorenzo Pieralisi wrote:
>>>>>> Sricharan, Robin,
>>>>>>
>>>>>> I gave this series a go on ACPI and apart from an SMMU v3 fix-up
>>>>>> it seems to work, more thorough testing required though.
>>>>>>
>>>>>> A key question below.
>>>>>>
>>>>>> On Wed, Nov 30, 2016 at 05:52:16AM +0530, Sricharan R wrote:
>>>>>>> From: Robin Murphy <robin.murphy@arm.com>
>>>>>>>
>>>>>>> IOMMU configuration represents unchanging properties of the hardware,
>>>>>>> and as such should only need happen once in a device's lifetime, but
>>>>>>> the necessary interaction with the IOMMU device and driver complicates
>>>>>>> exactly when that point should be.
>>>>>>>
>>>>>>> Since the only reasonable tool available for handling the inter-device
>>>>>>> dependency is probe deferral, we need to prepare of_iommu_configure()
>>>>>>> to run later than it is currently called (i.e. at driver probe rather
>>>>>>> than device creation), to handle being retried, and to tell whether a
>>>>>>> not-yet present IOMMU should be waited for or skipped (by virtue of
>>>>>>> having declared a built-in driver or not).
>>>>>>>
>>>>>>> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
>>>>>>> ---
>>>>>>>  drivers/iommu/of_iommu.c | 30 +++++++++++++++++++++++++++++-
>>>>>>>  1 file changed, 29 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
>>>>>>> index ee49081..349bd1d 100644
>>>>>>> --- a/drivers/iommu/of_iommu.c
>>>>>>> +++ b/drivers/iommu/of_iommu.c
>>>>>>> @@ -104,12 +104,20 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
>>>>>>>  	int err;
>>>>>>>
>>>>>>>  	ops = iommu_get_instance(fwnode);
>>>>>>> -	if (!ops || !ops->of_xlate)
>>>>>>> +	if ((ops && !ops->of_xlate) ||
>>>>>>> +	    (!ops && !of_match_node(&__iommu_of_table, iommu_spec->np)))
>>>>>>
>>>>>> IIUC of_match_node() here is there to check there is a driver compiled
>>>>>> in for this device_node (aka compatible string in OF world), correct ?
>>>>>
>>>>> Yes - specifically, it's checking the magic table for a matching
>>>>> IOMMU_OF_DECLARE entry.
>>>>>
>>>>>> If that's the case (and I think that's what Sricharan was referring to
>>>>>> in his ACPI query) I need to cook-up something on the ACPI side to
>>>>>> emulate the OF linker table behaviour (or anyway to detect a driver is
>>>>>> actually in the kernel), it is not that difficult but it is key to know,
>>>>>> I will give it some thought to make it as clean as possible.
>>>>>
>>>>> I didn't think this would be a concern for ACPI, since IORT works much
>>>>> the same way the current of_iommu_init_fn/of_platform_device_create()
>>>>> bodges in drivers so for DT. If you can only discover SMMUs from IORT,
>>>>> then iort_init_platform_devices() will have already created every SMMU
>>>>> that's going to exist before discovering other devices from wherever
>>>>> they come from, thus you could never get into the situation of probing a
>>>>> device without its SMMU being ready (if it's ever going to be). Is that
>>>>> not right?
>>>>
>>>> It is right, my point and question is: we are probing a device and we
>>>> have to know whether it is worth deferring its IOMMU DMA setup. On DT,
>>>> through of_match_node(&__iommu_of_table, iommu_device_node) we check at
>>>> once that:
>>>>
>>>> 1 - A device for the IOMMU exists
>>>>
>>>> AND
>>>>
>>>> 2 - A driver for the IOMMU is compiled in the kernel
>>>>
>>>> Is this correct ? As you said (1) is not a concern on ACPI IORT (because
>>>> we create the IOMMU device before _any_ other device so either the IOMMU
>>>> device is there or it will never be by the time master devices are
>>>> probed), but for (2) I need to slightly change how the IORT linker entry
>>>> work to make sure we can detect a driver is actually compiled in the
>>>> kernel, it is easy, I was just asking if my understanding was correct
>>>> and I think that was what Sricharan was referring to in his query.
>>>>
>>>
>>> Yes right, this was what i was looking for in the ACPI case and putting this
>>> in the iort_iommu_xlate was needed to return EPROBE_DEFER when the
>>> driver is not yet been probed.
>>
>> With the thinking of taking this series through, would it be fine if i
>> cleanup the pci configure hanging outside and push it in to
>> of/acpi_iommu configure respectively ? This time with all neeeded for
>> ACPI added as well.  Also on the last post of V4, Lorenzo commented
>> that it worked for him, although still the of_match_node equivalent in
>> ACPI has to be added. If i can get that, then i will add that as well
>> to make this complete.
> 
> Question: I had a look into this and instead of fiddling about with the
> linker script entries in ACPI (ie IORT_ACPI_DECLARE - which I hope this
> patchset would help remove entirely), I think that the only check we
> need in IORT is, depending on what type of SMMU a given device is
> connected to, to check if the respective SMMU driver is compiled in the
> kernel and it will be probed, _eventually_.
> 
> As Robin said, by the time a device is probed the respective SMMU
> devices are already created and registered with IORT kernel code or
> they will never be, so to understand if we should defer probing
> SMMU device creation is _not_ really a problem in ACPI.
> 
> To check if a SMMU driver is enabled, do we really need a linker
> table ?
> 
> Would not a check based on eg:
> 
> /**
>  * @type: IOMMU IORT node type of the IOMMU a device is connected to
>  */
> static bool iort_iommu_driver_enabled(u8 type)
> {
> 	switch (type) {
> 	case ACPI_IORT_SMMU_V3:
> 		return IS_ENABLED(CONFIG_ARM_SMMU_V3);

IS_BUILTIN(...)

> 	case ACPI_IORT_SMMU:
> 		return IS_ENABLED(CONFIG_ARM_SMMU);
> 	default:
> 		pr_warn("Unknown IORT SMMU type\n");

Might displaying the actual value be helfpul for debugging a broken IORT
table?

> 		return false;
> 	}
> }
> 
> be sufficient (it is a bit gross, agreed, but it is to understand if
> that's all we need) ? Is there anything I am missing ?
> 
> Let me know, I will put together a patch for you I really do not
> want to block your series for this trivial niggle.

Other than that, though, I like it :) IORT has a small, strictly
bounded, set of supported devices, so I really don't see the need to go
overboard putting it on parity with DT when something this neat and
simple will suffice.

Robin.

> 
> Thanks,
> Lorenzo
> 

^ permalink raw reply

* [GIT PULL] arm-soc fixes for 4.10-rc
From: Arnd Bergmann @ 2017-01-05 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

The following changes since commit 0c744ea4f77d72b3dcebb7a8f2684633ec79be88:

  Linux 4.10-rc2 (2017-01-01 14:31:53 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git tags/armsoc-fixes

for you to fetch changes up to 1b9ec81258827001c869f003e0b8dd2ddc104717:

  Merge tag 'davinci-fixes-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci into fixes (2017-01-04 16:43:00 +0100)

----------------------------------------------------------------
This is a rather large set of bugfixes, as we just returned from the
Christmas break. Most of these are relatively unimportant fixes for
regressions introduced during the merge window, and about half of
the changes are for mach-omap2.

A couple of patches are just cleanups and dead code removal that I would
not normally have considered for merging after -rc2, but I decided to
take them along with the fixes this time.

Notable fixes include:

- removing the skeleton.dtsi include broke a number of machines, and we
  have to put empty /chosen nodes back to be able to pass kernel command
  lines as before

- enabling Samsung platforms no longer hardwires CONFIG_HZ to 200,
  as it had been for no good reason for a long time.

----------------------------------------------------------------
Adam Ford (1):
      ARM: dts: omap3: Add DTS for Logic PD SOM-LV 37xx Dev Kit

Alexandre Bailon (2):
      ARM: davinci: Make __clk_{enable,disable} functions public
      ARM: davinci: da8xx: Fix sleeping function called from invalid context

Andreas F?rber (1):
      ARM: dts: vf610-zii-dev-rev-b: Add missing newline

Arnd Bergmann (12):
      Merge tag 'renesas-fixes-for-v4.10' of https://git.kernel.org/.../horms/renesas into fixes
      Merge tag 'qcom-fixes-for-4.10-rc1' of git://git.kernel.org/.../agross/linux into fixes
      Merge tag 'samsung-soc-4.10-2' of git://git.kernel.org/.../krzk/linux into fixes
      Merge tag 'omap-for-v4.10/fixes-rc1' of git://git.kernel.org/.../tmlind/linux-omap into fixes
      Merge tag 'qcom-arm-fixes-for-4.10-rc2' of git://git.kernel.org/.../agross/linux into fixes
      Merge tag 'imx-fixes-4.10' of git://git.kernel.org/.../shawnguo/linux into fixes
      Merge tag 'scpi-fixes-4.10' of git://git.kernel.org/.../sudeep.holla/linux into fixes
      Merge tag 'vexpress-fixes-4.10' of git://git.kernel.org/.../sudeep.holla/linux into fixes
      Merge tag 'juno-fixes-4.10' of git://git.kernel.org/.../sudeep.holla/linux into fixes
      Merge tag 'psci-fixes-4.10' of git://git.kernel.org/.../lpieralisi/linux into fixes
      Merge tag 'amlogic-fixes' of git://git.kernel.org/.../khilman/linux-amlogic into fixes
      Merge tag 'davinci-fixes-for-v4.10' of git://git.kernel.org/.../nsekhar/linux-davinci into fixes

Bartosz Golaszewski (2):
      ARM: davinci: da850: fix infinite loop in clk_set_rate()
      ARM: davinci: da850: don't add emac clock to lookup table twice

Bjorn Andersson (1):
      ARM: dts: qcom: apq8064: Add missing scm clock

Christoffer Dall (1):
      ARM: dts: vexpress: Support GICC_DIR operations

Fabio Estevam (1):
      ARM: dts: imx6: Disable "weim" node in the dtsi files

Gary Bisson (1):
      ARM: dts: imx6qdl-nitrogen6x: remove duplicate iomux entry

Grygorii Strashko (2):
      ARM: OMAP2+: Remove legacy gpio code
      ARM: omap2+: am437x: rollback to use omap3_gptimer_timer_init()

Javier Martinez Canillas (9):
      ARM: dts: omap2: Add an empty chosen node to top level DTSI
      ARM: dts: omap3: Add an empty chosen node to top level DTSI
      ARM: dts: omap4: Add an empty chosen node to top level DTSI
      ARM: dts: omap5: Add an empty chosen node to top level DTSI
      ARM: dts: am33xx: Add an empty chosen node to top level DTSI
      ARM: dts: am4372: Add an empty chosen node to top level DTSI
      ARM: dts: dm814x: Add an empty chosen node to top level DTSI
      ARM: dts: dm816x: Add an empty chosen node to top level DTSI
      ARM: dts: dra7: Add an empty chosen node to top level DTSI

Kevin Hilman (2):
      ARM64: dts: meson-gxl: fix GPIO include
      ARM64: defconfig: enable DRM_MESON as module

Kishon Vijay Abraham I (1):
      ARM: dts: am572x-idk: Add gpios property to control PCIE_RESETn

Krzysztof Kozlowski (1):
      ARM: Drop fixed 200 Hz timer requirement from Samsung platforms

Lokesh Vutla (1):
      ARM: dts: dra72-evm-tps65917: Add voltage supplies to usb_phy, mmc, dss

Maninder Singh (1):
      ARM: omap2+: fixing wrong strcat for Non-NULL terminated string

Markus Elfring (1):
      ARM: OMAP2+: PRM: Delete an error message for a failed memory allocation

Martin Blumenstingl (1):
      firmware: arm_scpi: fix reading sensor values on pre-1.0 SCPI firmwares

Milo Kim (4):
      ARM: dts: am335x: Fix the interrupt name of TPS65217
      dt-bindings: mfd: Remove TPS65217 interrupts
      dt-bindings: power/supply: Update TPS65217 properties
      dt-bindings: input: Specify the interrupt number of TPS65217 power button

Neil Armstrong (1):
      ARM64: dts: meson-gx: Add Graphic Controller nodes

Pali Roh?r (1):
      ARM: dts: n900: Mark eMMC slot with no-sdio and no-sd flags

Pankaj Dubey (1):
      ARM: EXYNOS: Remove smp_init_cpus hook from platsmp.c

Roger Quadros (2):
      ARM: dts: am57xx-idk: Support VBUS detection on USB2 port
      ARM: dts: am57xx-idk: Put USB2 port in peripheral mode

Simon Horman (1):
      arm64: dts: h3ulcb: Provide sd0_uhs node

Stephen Boyd (1):
      arm64: dts: msm8996: Add required memory carveouts

Sudeep Holla (3):
      arm64: dts: vexpress: Support GICC_DIR operations
      drivers: psci: annotate timer on stack to silence odebug messages
      MAINTAINERS: extend PSCI entry to cover the newly add PSCI checker code

Sylwester Nawrocki (1):
      ARM: S3C24XX: Add DMA slave maps for remaining s3c24xx SoCs

Tony Lindgren (1):
      Merge branch 'omap-for-v4.10/legacy' into omap-for-v4.10/fixes

Vladimir Murzin (1):
      ARM: i.MX: remove map_io callback

Vladimir Zapolskiy (1):
      ARM: dts: imx31: fix AVIC base address

 .../bindings/input/tps65218-pwrbutton.txt          |   4 +-
 .../bindings/power/supply/tps65217_charger.txt     |   7 +-
 MAINTAINERS                                        |   2 +-
 arch/arm/Kconfig                                   |   3 +-
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/am335x-bone-common.dtsi          |   8 +-
 arch/arm/boot/dts/am33xx.dtsi                      |   1 +
 arch/arm/boot/dts/am4372.dtsi                      |   1 +
 arch/arm/boot/dts/am571x-idk.dts                   |  10 +-
 arch/arm/boot/dts/am572x-idk.dts                   |  14 +-
 arch/arm/boot/dts/am57xx-idk-common.dtsi           |   9 +-
 arch/arm/boot/dts/dm814x.dtsi                      |   1 +
 arch/arm/boot/dts/dm816x.dtsi                      |   1 +
 arch/arm/boot/dts/dra7.dtsi                        |   1 +
 arch/arm/boot/dts/dra72-evm-tps65917.dtsi          |  16 +++
 arch/arm/boot/dts/imx31.dtsi                       |   4 +-
 arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi          |   1 -
 arch/arm/boot/dts/imx6qdl.dtsi                     |   1 +
 arch/arm/boot/dts/imx6sl.dtsi                      |   1 +
 arch/arm/boot/dts/imx6sx.dtsi                      |   1 +
 arch/arm/boot/dts/omap2.dtsi                       |   1 +
 arch/arm/boot/dts/omap3-n900.dts                   |   2 +
 arch/arm/boot/dts/omap3.dtsi                       |   1 +
 arch/arm/boot/dts/omap4.dtsi                       |   1 +
 arch/arm/boot/dts/omap5.dtsi                       |   1 +
 arch/arm/boot/dts/qcom-apq8064.dtsi                |   4 +
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts        |   2 +-
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts         |   2 +-
 arch/arm/boot/dts/vf610-zii-dev-rev-b.dts          |   3 +-
 arch/arm/mach-davinci/clock.c                      |  12 +-
 arch/arm/mach-davinci/clock.h                      |   2 +
 arch/arm/mach-davinci/da850.c                      |  32 ++++-
 arch/arm/mach-davinci/usb-da8xx.c                  |  34 ++---
 arch/arm/mach-exynos/platsmp.c                     |  31 ----
 arch/arm/mach-imx/mach-imx1.c                      |   1 -
 arch/arm/mach-omap2/Makefile                       |   2 +-
 arch/arm/mach-omap2/board-generic.c                |   2 +-
 arch/arm/mach-omap2/gpio.c                         | 160 ---------------------
 arch/arm/mach-omap2/omap_hwmod.c                   |   8 +-
 arch/arm/mach-omap2/omap_hwmod_common_data.h       |   4 -
 arch/arm/mach-omap2/prm_common.c                   |   4 +-
 arch/arm/mach-omap2/timer.c                        |   9 +-
 arch/arm/mach-s3c24xx/common.c                     |  76 ++++++++++
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |  16 +++
 .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    |  16 +++
 arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   |  16 +++
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |   4 +
 .../boot/dts/amlogic/meson-gxl-nexbox-a95x.dts     |  16 +++
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   6 +-
 .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts |  16 +++
 arch/arm64/boot/dts/amlogic/meson-gxm.dtsi         |   4 +
 arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts         |   2 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              |  10 ++
 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts     |   2 +-
 arch/arm64/configs/defconfig                       |   1 +
 drivers/firmware/arm_scpi.c                        |  10 +-
 drivers/firmware/psci_checker.c                    |   4 +-
 include/dt-bindings/mfd/tps65217.h                 |  26 ----
 58 files changed, 334 insertions(+), 296 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpio.c
 delete mode 100644 include/dt-bindings/mfd/tps65217.h

^ permalink raw reply

* [PATCHv3 8/8] ARM: configs: stm32: Add RTC support in STM32 defconfig
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch adds STM32 RTC support in stm32_defconfig file.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/configs/stm32_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
index be19e09..0acff9e 100644
--- a/arch/arm/configs/stm32_defconfig
+++ b/arch/arm/configs/stm32_defconfig
@@ -57,6 +57,8 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_STM32=y
 CONFIG_DMADEVICES=y
 CONFIG_STM32_DMA=y
 # CONFIG_FILE_LOCKING is not set
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 7/8] ARM: dts: stm32: enable RTC on stm32429i-eval
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch enables RTC on stm32429i-eval with default LSE clock source.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32429i-eval.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts
index 8b158f9..5007da9 100644
--- a/arch/arm/boot/dts/stm32429i-eval.dts
+++ b/arch/arm/boot/dts/stm32429i-eval.dts
@@ -134,6 +134,10 @@
 	};
 };
 
+&rtc {
+	status = "okay";
+};
+
 &usart1 {
 	pinctrl-0 = <&usart1_pins_a>;
 	pinctrl-names = "default";
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 6/8] ARM: dts: stm32: enable RTC on stm32f469-disco
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch enables RTC on stm32f469-disco with default LSE clock source.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f469-disco.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
index 8a163d7..af57dd5 100644
--- a/arch/arm/boot/dts/stm32f469-disco.dts
+++ b/arch/arm/boot/dts/stm32f469-disco.dts
@@ -78,6 +78,10 @@
 	clock-frequency = <8000000>;
 };
 
+&rtc {
+	status = "okay";
+};
+
 &usart3 {
 	status = "okay";
 };
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 5/8] ARM: dts: stm32: enable RTC on stm32f429-disco
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch enables RTC on stm32f429-disco with LSI as clock source because
X2 crystal for LSE is not fitted by default.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429-disco.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
index b6e63d8..49eddf6 100644
--- a/arch/arm/boot/dts/stm32f429-disco.dts
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -94,6 +94,12 @@
 	clock-frequency = <8000000>;
 };
 
+&rtc {
+	assigned-clocks = <&rcc 1 CLK_RTC>;
+	assigned-clock-parents = <&rcc 1 CLK_LSI>;
+	status = "okay";
+};
+
 &usart1 {
 	pinctrl-0 = <&usart1_pins_a>;
 	pinctrl-names = "default";
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 4/8] ARM: dts: stm32: Add RTC support for STM32F429 MCU
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch adds STM32 RTC bindings for STM32F429.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index d195ccf..d181025 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -125,6 +125,20 @@
 			status = "disabled";
 		};
 
+		rtc: rtc at 40002800 {
+			compatible = "st,stm32-rtc";
+			reg = <0x40002800 0x400>;
+			clocks = <&rcc 1 CLK_RTC>;
+			clock-names = "ck_rtc";
+			assigned-clocks = <&rcc 1 CLK_RTC>;
+			assigned-clock-parents = <&rcc 1 CLK_LSE>;
+			interrupt-parent = <&exti>;
+			interrupts = <17 1>;
+			interrupt-names = "alarm";
+			st,syscfg = <&pwrcfg>;
+			status = "disabled";
+		};
+
 		usart2: serial at 40004400 {
 			compatible = "st,stm32-usart", "st,stm32-uart";
 			reg = <0x40004400 0x400>;
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 3/8] rtc: add STM32 RTC driver
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch adds support for the STM32 RTC.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 drivers/rtc/Kconfig     |  11 +
 drivers/rtc/Makefile    |   1 +
 drivers/rtc/rtc-stm32.c | 776 ++++++++++++++++++++++++++++++++++++++++++++++++
 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..11eb28a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1706,6 +1706,17 @@ 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 RTC"
+	select REGMAP_MMIO
+	depends on ARCH_STM32 || COMPILE_TEST
+	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..fdd3a31
--- /dev/null
+++ b/drivers/rtc/rtc-stm32.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) Amelie Delaunay 2016
+ * Author:  Amelie Delaunay <amelie.delaunay@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_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(12, 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 *ck_rtc;
+	spinlock_t lock; /* Protects registers accesses */
+	int irq_alarm;
+};
+
+static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
+{
+	writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR);
+	writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
+{
+	writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	if (!(isr & STM32_RTC_ISR_INITF)) {
+		isr |= STM32_RTC_ISR_INIT;
+		writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+		/*
+		 * It takes around 2 ck_rtc clock cycles to enter in
+		 * initialization phase mode (and have INITF flag set). As
+		 * slowest ck_rtc frequency may be 32kHz and highest should be
+		 * 1MHz, we poll every 10 us with a timeout of 100ms.
+		 */
+		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 = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	isr &= ~STM32_RTC_ISR_INIT;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	isr &= ~STM32_RTC_ISR_RSF;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+	/*
+	 * Wait for RSF to be set to ensure the calendar registers are
+	 * synchronised, it takes around 2 ck_rtc clock cycles
+	 */
+	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 int isr, cr;
+
+	mutex_lock(&rtc->rtc_dev->ops_lock);
+
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+	if ((isr & STM32_RTC_ISR_ALRAF) &&
+	    (cr & STM32_RTC_CR_ALRAIE)) {
+		/* Alarm A flag - Alarm interrupt */
+		dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
+
+		/* Pass event to the kernel */
+		rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+		/* Clear event flag, otherwise new events won't be received */
+		writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF,
+			       rtc->base + STM32_RTC_ISR);
+	}
+
+	mutex_unlock(&rtc->rtc_dev->ops_lock);
+
+	return IRQ_HANDLED;
+}
+
+/* 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 = readl_relaxed(rtc->base + STM32_RTC_TR);
+	dr = readl_relaxed(rtc->base + 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;
+	}
+
+	writel_relaxed(tr, rtc->base + STM32_RTC_TR);
+	writel_relaxed(dr, rtc->base + STM32_RTC_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 = readl_relaxed(rtc->base + STM32_RTC_ALRMAR);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
+		/*
+		 * Date/day doesn't matter 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 matter 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 matter 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 matter 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;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+	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);
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	/* Clear event irqflags, otherwise new events won't be received */
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+	isr &= ~STM32_RTC_ISR_ALRAF;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return 0;
+}
+
+static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
+{
+	unsigned int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
+	unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+	unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+
+	cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+	cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+	cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+	cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+	cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+	cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+	/*
+	 * Assuming current date is M-D-Y H:M:S.
+	 * RTC alarm can't be set on a specific month and year.
+	 * So the valid alarm range is:
+	 *	M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
+	 * with a specific case for December...
+	 */
+	if ((((tm->tm_year > cur_year) &&
+	      (tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
+	     ((tm->tm_year == cur_year) &&
+	      (tm->tm_mon <= cur_mon + 1))) &&
+	    ((tm->tm_mday < cur_day) ||
+	     ((tm->tm_mday == cur_day) &&
+	     ((tm->tm_hour < cur_hour) ||
+	      ((tm->tm_hour == cur_hour) && (tm->tm_min < cur_min)) ||
+	      ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) &&
+	       (tm->tm_sec <= cur_sec))))))
+		return 0;
+
+	return -EINVAL;
+}
+
+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);
+
+	/*
+	 * RTC alarm can't be set on a specific date, unless this date is
+	 * up to the same day of month next month.
+	 */
+	if (stm32_rtc_valid_alrm(rtc, tm) < 0) {
+		dev_err(dev, "Alarm can be set only on upcoming month.\n");
+		return -EINVAL;
+	}
+
+	alrmar = 0;
+	/* tm_year and tm_mon are not used because not supported by RTC */
+	alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
+		  STM32_RTC_ALRMXR_DATE;
+	/* 24-hour format */
+	alrmar &= ~STM32_RTC_ALRMXR_PM;
+	alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
+		  STM32_RTC_ALRMXR_HOUR;
+	alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
+		  STM32_RTC_ALRMXR_MIN;
+	alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
+		  STM32_RTC_ALRMXR_SEC;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	/* Disable Alarm */
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_ALRAE;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	/*
+	 * Poll Alarm write flag to be sure that Alarm update is allowed: it
+	 * takes around 2 ck_rtc clock cycles
+	 */
+	ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+						isr,
+						(isr & STM32_RTC_ISR_ALRAWF),
+						10, 100000);
+
+	if (ret) {
+		dev_err(dev, "Alarm update not allowed\n");
+		goto end;
+	}
+
+	/* Write to Alarm register */
+	writel_relaxed(alrmar, rtc->base + STM32_RTC_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;
+	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+	prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+
+	/* Force 24h time format */
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_FMT;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	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_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, NULL);
+	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;
+
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+	/*
+	 * After a system reset, RTC_ISR.INITS flag can be read to check if
+	 * the calendar has been initalized or not. INITS flag is reset by a
+	 * power-on reset (no vbat, no power-supply). It is not reset if
+	 * ck_rtc parent clock has changed (so RTC prescalers need to be
+	 * changed). That's why we cannot rely on this flag to know if RTC
+	 * init has to be done.
+	 */
+	ret = stm32_rtc_init(pdev, rtc);
+	if (ret)
+		goto err;
+
+	rtc->irq_alarm = platform_get_irq(pdev, 0);
+	if (rtc->irq_alarm <= 0) {
+		dev_err(&pdev->dev, "no alarm irq\n");
+		ret = rtc->irq_alarm;
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	ret = device_init_wakeup(&pdev->dev, true);
+	if (ret)
+		dev_warn(&pdev->dev,
+			 "alarm won't be able to wake up the system");
+
+	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_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
+					stm32_rtc_alarm_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					pdev->name, rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
+			rtc->irq_alarm);
+		goto err;
+	}
+
+	/*
+	 * If INITS flag is reset (calendar year field set to 0x00), calendar
+	 * must be initialized
+	 */
+	if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS))
+		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
+
+	return 0;
+err:
+	clk_disable_unprepare(rtc->ck_rtc);
+
+	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 = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_ALRAIE;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+	stm32_rtc_wpr_lock(rtc);
+
+	clk_disable_unprepare(rtc->ck_rtc);
+
+	/* Enable backup domain write protection */
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+	device_init_wakeup(&pdev->dev, false);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32_rtc_suspend(struct device *dev)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		return enable_irq_wake(rtc->irq_alarm);
+
+	return 0;
+}
+
+static int stm32_rtc_resume(struct device *dev)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = stm32_rtc_wait_sync(rtc);
+	if (ret < 0)
+		return ret;
+
+	if (device_may_wakeup(dev))
+		return disable_irq_wake(rtc->irq_alarm);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
+			 stm32_rtc_suspend, stm32_rtc_resume);
+
+static struct platform_driver stm32_rtc_driver = {
+	.probe		= stm32_rtc_probe,
+	.remove		= stm32_rtc_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.pm	= &stm32_rtc_pm_ops,
+		.of_match_table = stm32_rtc_of_match,
+	},
+};
+
+module_platform_driver(stm32_rtc_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 2/8] dt-bindings: document the STM32 RTC bindings
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch adds documentation of device tree bindings for the STM32 RTC.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/rtc/st,stm32-rtc.txt       | 27 ++++++++++++++++++++++
 1 file changed, 27 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..e2837b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
@@ -0,0 +1,27 @@
+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.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  (RTC registers) write protection.
+
+Optional properties (to override default ck_rtc parent clock):
+- assigned-clocks: reference to the ck_rtc clock entry.
+- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+
+Example:
+
+	rtc: rtc at 40002800 {
+		compatible = "st,stm32-rtc";
+		reg = <0x40002800 0x400>;
+		clocks = <&rcc 1 CLK_RTC>;
+		assigned-clocks = <&rcc 1 CLK_RTC>;
+		assigned-clock-parents = <&rcc 1 CLK_LSE>;
+		interrupt-parent = <&exti>;
+		interrupts = <17 1>;
+		st,syscfg = <&pwrcfg>;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 1/8] ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch set HSE_RTC clock frequency to 1 MHz, as the clock supplied to
the RTC must be 1 MHz.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index b077f99..d195ccf 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -371,6 +371,8 @@
 			reg = <0x40023800 0x400>;
 			clocks = <&clk_hse>, <&clk_i2s_ckin>;
 			st,syscfg = <&pwrcfg>;
+			assigned-clocks = <&rcc 1 CLK_HSE_RTC>;
+			assigned-clock-rates = <1000000>;
 		};
 
 		dma1: dma-controller at 40026000 {
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 0/8] Add support for STM32 RTC
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

v3:
- rework set_alarm
- return platform_get_irq error code instead of -ENOENT

v2:
- remove clock-names and interrupt-names from bindings
- remove unuseful headers
- clean stm32_rtc structure
- replace stm32_rtc_readl/_writel by readl/writel_relaxed
- use threaded IRQ
- rework set_alarm
- add various comments
- select COMPILE_TEST and REGMAP_MMIO

This patchset adds support for the STM32 Real-Time Clock.
This RTC is an independent BCD timer/counter and provides a time-of-day
clock/calendar with programmable alarm interrupt.
RTC calendar can be driven by three clock sources LSE, LSI or HSE.

Amelie Delaunay (8):
  ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
  dt-bindings: document the STM32 RTC bindings
  rtc: add STM32 RTC driver
  ARM: dts: stm32: Add RTC support for STM32F429 MCU
  ARM: dts: stm32: enable RTC on stm32f429-disco
  ARM: dts: stm32: enable RTC on stm32f469-disco
  ARM: dts: stm32: enable RTC on stm32429i-eval
  ARM: configs: stm32: Add RTC support in STM32 defconfig

 .../devicetree/bindings/rtc/st,stm32-rtc.txt       |  27 +
 arch/arm/boot/dts/stm32429i-eval.dts               |   4 +
 arch/arm/boot/dts/stm32f429-disco.dts              |   6 +
 arch/arm/boot/dts/stm32f429.dtsi                   |  16 +
 arch/arm/boot/dts/stm32f469-disco.dts              |   4 +
 arch/arm/configs/stm32_defconfig                   |   2 +
 drivers/rtc/Kconfig                                |  11 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-stm32.c                            | 776 +++++++++++++++++++++
 9 files changed, 847 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
 create mode 100644 drivers/rtc/rtc-stm32.c

-- 
1.9.1

^ permalink raw reply

* [PATCHv2 0/5] Support for Marvell switches with integrated CPUs
From: Andrew Lunn @ 2017-01-05 13:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <185147a37cab4d7eaea5f79d86cc9451@svr-chch-ex1.atlnz.lc>

> I'd love to see a switchdev driver but it's a huge task (and no I'm not 
> committing to writing it). As it stands Marvell ship a switch SDK 
> largely executes in userspace with a small kernel module providing some 
> linkage to the underlying hardware.

Is there any similarity to the mv88e6xxx family?

If it was similar registers, just a different access mechanising, we
could probably extend the mv88e6xxx to support MMIO as well as MDIO.

   Andrew

^ permalink raw reply

* [PATCH v2 5/5] drm/rockchip: Implement CRC debugfs API
From: Tomeu Vizoso @ 2017-01-05 13:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105130648.3139-1-tomeu.vizoso@collabora.com>

Implement the .set_crc_source() callback and call the DP helpers
accordingly to start and stop CRC capture.

This is only done if this CRTC is currently using the eDP connector.

Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---

 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 48 +++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index fb5f001f51c3..5e19bef6d5b4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -19,6 +19,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_flip_work.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/bridge/analogix_dp.h>
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -1105,6 +1106,52 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc,
 	kfree(s);
 }
 
+static struct drm_connector *vop_get_edp_connector(struct vop *vop)
+{
+	struct drm_crtc *crtc = &vop->crtc;
+	struct drm_connector *connector;
+
+	mutex_lock(&crtc->dev->mode_config.mutex);
+	drm_for_each_connector(connector, crtc->dev)
+		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+			mutex_unlock(&crtc->dev->mode_config.mutex);
+			return connector;
+		}
+	mutex_unlock(&crtc->dev->mode_config.mutex);
+
+	return NULL;
+}
+
+static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
+				   const char *source_name, size_t *values_cnt)
+{
+	struct vop *vop = to_vop(crtc);
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
+	struct drm_connector *connector;
+	int ret;
+
+	connector = vop_get_edp_connector(vop);
+	if (!connector)
+		return -EINVAL;
+
+	*values_cnt = 3;
+
+	if (source_name &&
+	    strcmp(source_name, "auto") == 0) {
+
+		if (s->output_type != DRM_MODE_CONNECTOR_eDP)
+			return -EINVAL;
+
+		ret = analogix_dp_start_crc(connector);
+	} else if (!source_name)
+
+		ret = analogix_dp_stop_crc(connector);
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
 static const struct drm_crtc_funcs vop_crtc_funcs = {
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
@@ -1112,6 +1159,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {
 	.reset = vop_crtc_reset,
 	.atomic_duplicate_state = vop_crtc_duplicate_state,
 	.atomic_destroy_state = vop_crtc_destroy_state,
+	.set_crc_source = vop_crtc_set_crc_source,
 };
 
 static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 0/5] drm/dp: Implement CRC debugfs API
From: Tomeu Vizoso @ 2017-01-05 13:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

this series builds up on the API for exposing captured CRCs through
debugfs.

It adds new DP helpers for starting and stopping CRC capture and gets
the Rockchip driver to use it.

Also had to add a connector backpointer to the drm_dp_aux struct so we could
wait for the right vblank and store the CRCs afterwards, I will be glad
to hear about better alternatives.

Thanks,

Tomeu


Tomeu Vizoso (5):
  drm/dp: add connector backpointer to drm_dp_aux
  drm/bridge: analogix_dp: set connector to drm_dp_aux
  drm/dp: add helpers for capture of frame CRCs
  drm/bridge: analogix_dp: add helpers for capture of frame CRCs
  drm/rockchip: Implement CRC debugfs API

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  34 ++++--
 drivers/gpu/drm/drm_dp_helper.c                    | 120 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |  48 +++++++++
 include/drm/bridge/analogix_dp.h                   |   3 +
 include/drm/drm_dp_helper.h                        |   9 ++
 5 files changed, 206 insertions(+), 8 deletions(-)

-- 
2.9.3

^ permalink raw reply

* [PATCH 1/5] ARM: dts: armada388-clearfog: add phy reset gpio-hog
From: Gregory CLEMENT @ 2017-01-05 13:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105103134.GS14217@n2100.armlinux.org.uk>

Hi Russell King,
 
 On jeu., janv. 05 2017, Russell King - ARM Linux <linux@armlinux.org.uk> wrote:

> On Thu, Jan 05, 2017 at 11:29:48AM +0100, Gregory CLEMENT wrote:
>> Hi Russell King,
>>  
>>  On jeu., janv. 05 2017, Russell King - ARM Linux <linux@armlinux.org.uk> wrote:
>> 
>> > On Wed, Jan 04, 2017 at 05:26:08PM +0100, Gregory CLEMENT wrote:
>> >> Hi Russell,
>> >>  
>> >>  On lun., janv. 02 2017, Russell King <rmk+kernel@armlinux.org.uk> wrote:
>> >> 
>> >> 
>> >> It would be nice to have some word here about this patch. Especially why
>> >> we need it now. I guess it is for being less dependent on the
>> >> initialization done by the bootloader but maybe you have other reasons.
>> >
>> > I'm not sure I follow.  This is adding it to the new platform, not the
>> > old one.  I guess I should've rolled this into the patch creating the
>> > clearfog-base dts file, and this question wouldn't have come up.
>> >
>> 
>> Indeed I missed the fact that it was on the new board as all the other
>> patches were related to the common part.
>> 
>> Do you agree that I squash this patch into the "ARM: dts:
>> armada388-clearfog: add base model DTS file" patch?
>
> Yep, thanks.

It's done and it is also part of mvebu/for-next now.

Gregory

>
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH v3] ARM: dts: turris-omnia: add support for ethernet switch
From: Gregory CLEMENT @ 2017-01-05 12:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170103193501.4827-1-uwe@kleine-koenig.org>

Hi Uwe,
 
 On mar., janv. 03 2017, Uwe Kleine-K?nig <uwe@kleine-koenig.org> wrote:

> The Turris Omnia features a Marvell MV88E6176 ethernet switch. Add it to
> the dts.
>
> Signed-off-by: Uwe Kleine-K?nig <uwe@kleine-koenig.org>

Applied on mvebu/dt with Reviewed-by flag from Andrew Lunn
<andrew@lunn.ch> and Tested-by flag from Andreas F?rber.

Thanks,

Gregory
> ---
> Changes since (implicit) v1:
>  - drop mdio bus and per port phy-handle as they match the default
>    setup.
>
> Changes since v2:
>  - Fix switch type in comment and commit log
>  - drop 2nd cpu port
>
>  arch/arm/boot/dts/armada-385-turris-omnia.dts | 58 +++++++++++++++++++++++++--
>  1 file changed, 55 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/boot/dts/armada-385-turris-omnia.dts b/arch/arm/boot/dts/armada-385-turris-omnia.dts
> index ab49acb2d452..28eede180e4f 100644
> --- a/arch/arm/boot/dts/armada-385-turris-omnia.dts
> +++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts
> @@ -122,7 +122,7 @@
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&ge0_rgmii_pins>;
>  	status = "okay";
> -	phy-mode = "rgmii-id";
> +	phy-mode = "rgmii";
>  
>  	fixed-link {
>  		speed = <1000>;
> @@ -135,7 +135,7 @@
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&ge1_rgmii_pins>;
>  	status = "okay";
> -	phy-mode = "rgmii-id";
> +	phy-mode = "rgmii";
>  
>  	fixed-link {
>  		speed = <1000>;
> @@ -273,7 +273,59 @@
>  		/* irq is connected to &pcawan pin 7 */
>  	};
>  
> -	/* Switch MV88E7176 at address 0x10 */
> +	/* Switch MV88E6176 at address 0x10 */
> +	switch at 10 {
> +		compatible = "marvell,mv88e6085";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		dsa,member = <0 0>;
> +
> +		reg = <0x10>;
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			ports at 0 {
> +				reg = <0>;
> +				label = "lan0";
> +			};
> +
> +			ports at 1 {
> +				reg = <1>;
> +				label = "lan1";
> +			};
> +
> +			ports at 2 {
> +				reg = <2>;
> +				label = "lan2";
> +			};
> +
> +			ports at 3 {
> +				reg = <3>;
> +				label = "lan3";
> +			};
> +
> +			ports at 4 {
> +				reg = <4>;
> +				label = "lan4";
> +			};
> +
> +			ports at 5 {
> +				reg = <5>;
> +				label = "cpu";
> +				ethernet = <&eth1>;
> +				phy-mode = "rgmii-id";
> +
> +				fixed-link {
> +					speed = <1000>;
> +					full-duplex;
> +				};
> +			};
> +
> +			/* port 6 is connected to eth0 */
> +		};
> +	};
>  };
>  
>  &pinctrl {
> -- 
> 2.11.0
>

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH 3/8] ARM: dts: armada-388-clearfog: Utilize new DSA binding
From: Gregory CLEMENT @ 2017-01-05 12:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5a40436a-ebad-8a94-c5c5-546ba33ba545@gmail.com>

Hi Florian,
 
 On mer., janv. 04 2017, Florian Fainelli <f.fainelli@gmail.com> wrote:

> On 01/04/2017 09:23 AM, Gregory CLEMENT wrote:
>> Hi Florian,
>>  
>>  On lun., janv. 02 2017, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> 
>>> Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net:
>>> dsa: Document new binding"). The legacy binding node is kept included, but is
>>> marked disabled.
>>>
>> 
>> I tested this patch on mvebu/dt (I needed to reduce the context to apply
>> the patch due to the changes made by Russell King on this file). I also
>> set the status of the old binding to "disable" (instead of "okay").
>
> Yes, that needs fixing, thanks for mentioning that.
>
>> 
>> It seems to work with the limited test did:
>> ifconfig eth1 up
>> udhcpc -i lan1
>> iperf -c mylaptop
>> 
>> (same for lan4)
>> 
>> However is there a way to be sure that the new binding is used?
>
> The best way is probably to make sure that your switch device appears
> parented to the MDIO bus driver under /sys/class/mdio_bus/*mvmdio*.
> Alternatively, if you see a message like:
>
> DSA: switch 0 0 parsed
>
> in your dmesg, that would also be indicative of using the new binding
> and corresponding code.

So it's OK I had this message.

Gregory


>
> Thanks a lot for trying that out!
> -- 
> Florian

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH v5 1/4] clk: rockchip: add dt-binding header for rk3328
From: Heiko Stuebner @ 2017-01-05 12:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6625105.hZYF0iglUL@phil>

Am Donnerstag, 5. Januar 2017, 13:39:38 CET schrieb Heiko Stuebner:
> Am Donnerstag, 29. Dezember 2016, 10:45:08 CET schrieb Elaine Zhang:
> > Add the dt-bindings header for the rk3328, that gets shared between
> > the clock controller and the clock references in the dts.
> > Add softreset ID for rk3328.
> > 
> > Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> 
> applied, after moving the clock-ids a bit more together [0],
> as limiting the number of empty entries in the clk-id array saves us a bit
> of space. But please double check and shout if something looks wrong :-)

forgot to add, that I also moved your mac2phy clock-ids into the regular sclk-
area, as we want to add them via the muxgrf clktype.


> Thanks
> Heiko
> 
> [0]
> https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commi
> t/?id=6cc1aef0ad0daea0c6ba5432a8a6fe1c30661e4c

^ permalink raw reply

* [PATCH v5 4/4] clk: rockchip: add clock controller for rk3328
From: Heiko Stuebner @ 2017-01-05 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482979511-6847-5-git-send-email-zhangqing@rock-chips.com>

Am Donnerstag, 29. Dezember 2016, 10:45:11 CET schrieb Elaine Zhang:
> Add the clock tree definition for the new rk3328 SoC.
> 
> Changes in v5:
>   fix up some code style, remove grf clk init and cru dump.
> Changes in v4:
>   adjust the pacth 3 and 4 order.
> Changes in v3:
>   fix up the pll parent only xin24m.
> Changes in v2:
>   fix up these *_sample error description.
> 
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>

applied for 4.11.

You might also want to readd your mac2phy grf clocks via the newly
introduced muxgrf clock-type [0] in a follow-up-patch.

Heiko

[0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=cb1d9f6ddaa436f2dce2710740b7a3546700949c

^ permalink raw reply

* [PATCH v6 05/14] ACPI: platform-msi: retrieve dev id from IORT
From: Hanjun Guo @ 2017-01-05 12:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170104191805.GE8604@red-moon>

Hi Lorenzo,

On 2017/1/5 3:18, Lorenzo Pieralisi wrote:
> On Mon, Jan 02, 2017 at 09:31:36PM +0800, Hanjun Guo wrote:
>> For devices connecting to ITS, it needs dev id to identify
>> itself, and this dev id is represented in the IORT table in
>> named componant node [1] for platform devices, so in this
>> patch we will scan the IORT to retrieve device's dev id.
>>
>> Introduce iort_pmsi_get_dev_id() with pointer dev passed
>> in for that purpose.
>>
>> [1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> Tested-by: Sinan Kaya <okaya@codeaurora.org>
>> Tested-by: Majun <majun258@huawei.com>
>> Tested-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Cc: Tomasz Nowicki <tn@semihalf.com>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> ---
>>  drivers/acpi/arm64/iort.c                     | 26 ++++++++++++++++++++++++++
>>  drivers/irqchip/irq-gic-v3-its-platform-msi.c |  4 +++-
>>  include/linux/acpi_iort.h                     |  8 ++++++++
>>  3 files changed, 37 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
>> index 174e983..ab7bae7 100644
>> --- a/drivers/acpi/arm64/iort.c
>> +++ b/drivers/acpi/arm64/iort.c
>> @@ -444,6 +444,32 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>>  }
>>
>>  /**
>> + * iort_pmsi_get_dev_id() - Get the device id for a device
>> + * @dev: The device for which the mapping is to be done.
>> + * @dev_id: The device ID found.
>> + *
>> + * Returns: 0 for successful find a dev id, errors otherwise
>> + */
>> +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
>> +{
>> +	struct acpi_iort_node *node;
>> +
>> +	if (!iort_table)
>> +		return -ENODEV;
>> +
>> +	node = iort_find_dev_node(dev);
>> +	if (!node) {
>> +		dev_err(dev, "can't find related IORT node\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if(!iort_node_get_id(node, dev_id, IORT_MSI_TYPE, 0))
>
> I disagree with this approach. For named components we know that
> there are always two steps involved (second optional):
>
> (1) Retrieve the initial id (this may well provide the final mapping)
> (2) Map the id (optional if (1) represents the map type we need)
>
> That's the reason why I kept iort_node_get_id() and iort_node_map_rid()
> separated.
>
> Now, what we can do is to create an iort_node_map_id() function that is
> PCI agnostic (ie rename rid to id :)), whose rid_in is either a PCI RID
> or the outcome of a previous call to iort_node_get_id() for named
> components, that's in my opinion cleaner.

iort_node_map_rid() was designed for that purpose, and we can use it
for platform device, the issue that we need to pass a req id
unconditionally which is not needed for platform device, Tomasz
proposed a similar solution to rework iort_node_map_rid(), and
I think it makes sense.

>
> It would be even cleaner if you passed a type_mask (or write a
> wrapper function for that) that is:
>
> (IORT_MSI_TYPE | IORT_IOMMU_TYPE)

Sorry, I got little lost here, could you explain it in detail?

>
> and we just use the returned parent pointer to check if the mapping
> providing the initial id correspond to the type we are looking for (eg
> ITS) or we need to map the retrieved initial id any further, with
> iort_node_map_id(), to get to the final identifier.
>
> Thoughts ?

I think rework iort_node_map_rid() and not extend iort_node_get_id()
is the right direction, could you explain a bit more then I can demo
the code?

Thanks
Hanjun

^ permalink raw reply

* [PATCH v5 2/4] dt-bindings: add bindings for rk3328 clock controller
From: Heiko Stuebner @ 2017-01-05 12:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482979511-6847-3-git-send-email-zhangqing@rock-chips.com>

Am Donnerstag, 29. Dezember 2016, 10:45:09 CET schrieb Elaine Zhang:
> Add devicetree bindings for Rockchip cru which found on
> Rockchip SoCs.
> 
> Changes in v4:
>   dropping the "rockchip,cru" and "syscon" properties for bindings of rk3328
> 
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>

applied for 4.11 with Rob's Ack

^ permalink raw reply

* [PATCH v3] ARM: dts: turris-omnia: add support for ethernet switch
From: Andreas Färber @ 2017-01-05 12:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170104134131.GJ10768@lunn.ch>

Am 04.01.2017 um 14:41 schrieb Andrew Lunn:
> On Wed, Jan 04, 2017 at 11:49:12AM +0100, Andreas F?rber wrote:
>> Am 03.01.2017 um 20:35 schrieb Uwe Kleine-K?nig:
>>> The Turris Omnia features a Marvell MV88E6176 ethernet switch. Add it to
>>> the dts.
>>>
>>> Signed-off-by: Uwe Kleine-K?nig <uwe@kleine-koenig.org>
>>
>> It's still not working for me on next-20170104 with this v3.
>> Are there any other patches needed?
[...]
>> I've been using the WAN port (eth2) just fine. (=eth1 in OpenWrt)
>>
>> With this patch, eth0 and eth1 are shown as UP by default. If however I
>> enslave eth0 and eth1 in a br-lan bridge, as seen under OpenWrt for
>> eth0+eth2, then eth1 is DOWN while eth0 remains UP, and br-lan remains
>> DOWN. Same issue if I drop eth0 from the bridge - after a reboot eth1 is
>> UP but br-lan is still DOWN.
>> I had to manually enable CONFIG_BRIDGE, so maybe I'm missing more kernel
>> options? Or did you simply not try using a bridge?
> 
> That is not how you use DSA. It is very different to how OpenWRT
> swconfig works. The mainline kernel philosophy is that switch
> interfaces are just normal linux interfaces.
> 
> You need eth0 up, in order that the slave interfaces work. But then
> you can use the slave interfaces just like normal Linux
> interfaces. You can put an IP address on them. You can put them into a
> bridge, etc. But leave eth0 alone, other than having it up.

Thanks, s/eth0/eth1/g here.

There were two hurdles, for one only eth0..eth2 were shown in our yast
tool (https://bugzilla.opensuse.org/show_bug.cgi?id=1018271), and for
another the interface name in manually written config files needed to be
just lan0 instead of lan0 at eth1 as shown in ip a.

A br-lan bridge across lan0..lan4 works as expected. Great!

Tested-by: Andreas F?rber <afaerber@suse.de>

Unrelated remaining issue is still the misconfigured stdout-path.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply

* [PATCH v5 1/4] clk: rockchip: add dt-binding header for rk3328
From: Heiko Stuebner @ 2017-01-05 12:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482979511-6847-2-git-send-email-zhangqing@rock-chips.com>

Am Donnerstag, 29. Dezember 2016, 10:45:08 CET schrieb Elaine Zhang:
> Add the dt-bindings header for the rk3328, that gets shared between
> the clock controller and the clock references in the dts.
> Add softreset ID for rk3328.
> 
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>

applied, after moving the clock-ids a bit more together [0],
as limiting the number of empty entries in the clk-id array saves us a bit of
space. But please double check and shout if something looks wrong :-)


Thanks
Heiko

[0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=6cc1aef0ad0daea0c6ba5432a8a6fe1c30661e4c

^ permalink raw reply

* [PATCH 02/10] iommu/of: Prepare for deferred IOMMU configuration
From: Lorenzo Pieralisi @ 2017-01-05 12:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <003601d2672e$91744b40$b45ce1c0$@codeaurora.org>

On Thu, Jan 05, 2017 at 02:04:37PM +0530, Sricharan wrote:
> Hi Robin/Lorenzo,
> 
> >Hi Robin,Lorenzo,
> >
> >>On Wed, Nov 30, 2016 at 04:42:27PM +0000, Robin Murphy wrote:
> >>> On 30/11/16 16:17, Lorenzo Pieralisi wrote:
> >>> > Sricharan, Robin,
> >>> >
> >>> > I gave this series a go on ACPI and apart from an SMMU v3 fix-up
> >>> > it seems to work, more thorough testing required though.
> >>> >
> >>> > A key question below.
> >>> >
> >>> > On Wed, Nov 30, 2016 at 05:52:16AM +0530, Sricharan R wrote:
> >>> >> From: Robin Murphy <robin.murphy@arm.com>
> >>> >>
> >>> >> IOMMU configuration represents unchanging properties of the hardware,
> >>> >> and as such should only need happen once in a device's lifetime, but
> >>> >> the necessary interaction with the IOMMU device and driver complicates
> >>> >> exactly when that point should be.
> >>> >>
> >>> >> Since the only reasonable tool available for handling the inter-device
> >>> >> dependency is probe deferral, we need to prepare of_iommu_configure()
> >>> >> to run later than it is currently called (i.e. at driver probe rather
> >>> >> than device creation), to handle being retried, and to tell whether a
> >>> >> not-yet present IOMMU should be waited for or skipped (by virtue of
> >>> >> having declared a built-in driver or not).
> >>> >>
> >>> >> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> >>> >> ---
> >>> >>  drivers/iommu/of_iommu.c | 30 +++++++++++++++++++++++++++++-
> >>> >>  1 file changed, 29 insertions(+), 1 deletion(-)
> >>> >>
> >>> >> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> >>> >> index ee49081..349bd1d 100644
> >>> >> --- a/drivers/iommu/of_iommu.c
> >>> >> +++ b/drivers/iommu/of_iommu.c
> >>> >> @@ -104,12 +104,20 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
> >>> >>  	int err;
> >>> >>
> >>> >>  	ops = iommu_get_instance(fwnode);
> >>> >> -	if (!ops || !ops->of_xlate)
> >>> >> +	if ((ops && !ops->of_xlate) ||
> >>> >> +	    (!ops && !of_match_node(&__iommu_of_table, iommu_spec->np)))
> >>> >
> >>> > IIUC of_match_node() here is there to check there is a driver compiled
> >>> > in for this device_node (aka compatible string in OF world), correct ?
> >>>
> >>> Yes - specifically, it's checking the magic table for a matching
> >>> IOMMU_OF_DECLARE entry.
> >>>
> >>> > If that's the case (and I think that's what Sricharan was referring to
> >>> > in his ACPI query) I need to cook-up something on the ACPI side to
> >>> > emulate the OF linker table behaviour (or anyway to detect a driver is
> >>> > actually in the kernel), it is not that difficult but it is key to know,
> >>> > I will give it some thought to make it as clean as possible.
> >>>
> >>> I didn't think this would be a concern for ACPI, since IORT works much
> >>> the same way the current of_iommu_init_fn/of_platform_device_create()
> >>> bodges in drivers so for DT. If you can only discover SMMUs from IORT,
> >>> then iort_init_platform_devices() will have already created every SMMU
> >>> that's going to exist before discovering other devices from wherever
> >>> they come from, thus you could never get into the situation of probing a
> >>> device without its SMMU being ready (if it's ever going to be). Is that
> >>> not right?
> >>
> >>It is right, my point and question is: we are probing a device and we
> >>have to know whether it is worth deferring its IOMMU DMA setup. On DT,
> >>through of_match_node(&__iommu_of_table, iommu_device_node) we check at
> >>once that:
> >>
> >>1 - A device for the IOMMU exists
> >>
> >>AND
> >>
> >>2 - A driver for the IOMMU is compiled in the kernel
> >>
> >>Is this correct ? As you said (1) is not a concern on ACPI IORT (because
> >>we create the IOMMU device before _any_ other device so either the IOMMU
> >>device is there or it will never be by the time master devices are
> >>probed), but for (2) I need to slightly change how the IORT linker entry
> >>work to make sure we can detect a driver is actually compiled in the
> >>kernel, it is easy, I was just asking if my understanding was correct
> >>and I think that was what Sricharan was referring to in his query.
> >>
> >
> >Yes right, this was what i was looking for in the ACPI case and putting this
> >in the iort_iommu_xlate was needed to return EPROBE_DEFER when the
> >driver is not yet been probed.
> 
> With the thinking of taking this series through, would it be fine if i
> cleanup the pci configure hanging outside and push it in to
> of/acpi_iommu configure respectively ? This time with all neeeded for
> ACPI added as well.  Also on the last post of V4, Lorenzo commented
> that it worked for him, although still the of_match_node equivalent in
> ACPI has to be added. If i can get that, then i will add that as well
> to make this complete.

Question: I had a look into this and instead of fiddling about with the
linker script entries in ACPI (ie IORT_ACPI_DECLARE - which I hope this
patchset would help remove entirely), I think that the only check we
need in IORT is, depending on what type of SMMU a given device is
connected to, to check if the respective SMMU driver is compiled in the
kernel and it will be probed, _eventually_.

As Robin said, by the time a device is probed the respective SMMU
devices are already created and registered with IORT kernel code or
they will never be, so to understand if we should defer probing
SMMU device creation is _not_ really a problem in ACPI.

To check if a SMMU driver is enabled, do we really need a linker
table ?

Would not a check based on eg:

/**
 * @type: IOMMU IORT node type of the IOMMU a device is connected to
 */
static bool iort_iommu_driver_enabled(u8 type)
{
	switch (type) {
	case ACPI_IORT_SMMU_V3:
		return IS_ENABLED(CONFIG_ARM_SMMU_V3);
	case ACPI_IORT_SMMU:
		return IS_ENABLED(CONFIG_ARM_SMMU);
	default:
		pr_warn("Unknown IORT SMMU type\n");
		return false;
	}
}

be sufficient (it is a bit gross, agreed, but it is to understand if
that's all we need) ? Is there anything I am missing ?

Let me know, I will put together a patch for you I really do not
want to block your series for this trivial niggle.

Thanks,
Lorenzo

^ permalink raw reply


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