* [RFC PATCH 1/3] ARM64: meson: Add Amlogic Meson GX PM Suspend
From: Mark Rutland @ 2016-11-03 15:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478183365-23708-2-git-send-email-narmstrong@baylibre.com>
On Thu, Nov 03, 2016 at 03:29:23PM +0100, Neil Armstrong wrote:
> The Amlogic Meson GX SoCs uses a non-standard argument to the
> PSCI CPU_SUSPEND call to enter system suspend.
>
> Implement such call within platform_suspend_ops.
While I am very much not happy with platform-specific extensions to PSCI, if
this needs to go anywhere, it should live in the existing PSCI driver.
That is to say, NAK to other driver invoking PSCI functions.
Thanks,
Mark.
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> drivers/firmware/meson/Kconfig | 6 +++
> drivers/firmware/meson/Makefile | 1 +
> drivers/firmware/meson/meson_gx_pm.c | 86 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 93 insertions(+)
> create mode 100644 drivers/firmware/meson/meson_gx_pm.c
>
> diff --git a/drivers/firmware/meson/Kconfig b/drivers/firmware/meson/Kconfig
> index 170d7e8..5b3fea3 100644
> --- a/drivers/firmware/meson/Kconfig
> +++ b/drivers/firmware/meson/Kconfig
> @@ -7,3 +7,9 @@ config MESON_SM
> depends on ARM64_4K_PAGES
> help
> Say y here to enable the Amlogic secure monitor driver
> +
> +config MESON_GX_PM
> + bool
> + default ARCH_MESON if ARM64
> + help
> + Say y here to enable the Amlogic GX SoC Power Management
> diff --git a/drivers/firmware/meson/Makefile b/drivers/firmware/meson/Makefile
> index 9ab3884..b6e285d 100644
> --- a/drivers/firmware/meson/Makefile
> +++ b/drivers/firmware/meson/Makefile
> @@ -1 +1,2 @@
> obj-$(CONFIG_MESON_SM) += meson_sm.o
> +obj-$(CONFIG_MESON_GX_PM) += meson_gx_pm.o
> diff --git a/drivers/firmware/meson/meson_gx_pm.c b/drivers/firmware/meson/meson_gx_pm.c
> new file mode 100644
> index 0000000..c104c2e
> --- /dev/null
> +++ b/drivers/firmware/meson/meson_gx_pm.c
> @@ -0,0 +1,86 @@
> +/*
> + * Amlogic Meson GX Power Management
> + *
> + * Copyright (c) 2016 Baylibre, SAS.
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/suspend.h>
> +#include <linux/arm-smccc.h>
> +
> +#include <uapi/linux/psci.h>
> +
> +#include <asm/suspend.h>
> +
> +/*
> + * The Amlogic GX SoCs uses a special argument value to the
> + * PSCI CPU_SUSPEND method to enter SUSPEND_MEM.
> + */
> +
> +#define MESON_SUSPEND_PARAM 0x0010000
> +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
> +
> +static int meson_gx_suspend_finish(unsigned long arg)
> +{
> + struct arm_smccc_res res;
> +
> + arm_smccc_smc(PSCI_FN_NATIVE(0_2, CPU_SUSPEND), arg,
> + virt_to_phys(cpu_resume), 0, 0, 0, 0, 0, &res);
> +
> + return res.a0;
> +}
> +
> +static int meson_gx_suspend_enter(suspend_state_t state)
> +{
> + switch (state) {
> + case PM_SUSPEND_MEM:
> + return cpu_suspend(MESON_SUSPEND_PARAM,
> + meson_gx_suspend_finish);
> + }
> +
> + return -EINVAL;
> +}
> +
> +static const struct platform_suspend_ops meson_gx_pm_ops = {
> + .enter = meson_gx_suspend_enter,
> + .valid = suspend_valid_only_mem,
> +};
> +
> +static const struct of_device_id meson_gx_pm_match[] = {
> + { .compatible = "amlogic,meson-gx-pm", },
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, meson_gx_pm_match);
> +
> +static int meson_gx_pm_probe(struct platform_device *pdev)
> +{
> + suspend_set_ops(&meson_gx_pm_ops);
> +
> + return 0;
> +}
> +
> +static struct platform_driver meson_gx_pm_driver = {
> + .probe = meson_gx_pm_probe,
> + .driver = {
> + .name = "meson-gx-pm",
> + .of_match_table = meson_gx_pm_match,
> + },
> +};
> +
> +module_platform_driver(meson_gx_pm_driver);
> +
> +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
> +MODULE_DESCRIPTION("Amlogic Meson GX PM driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [RFC PATCH 0/3] ARM64: meson-gxbb: Add support for system suspend
From: Mark Rutland @ 2016-11-03 15:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478183365-23708-1-git-send-email-narmstrong@baylibre.com>
On Thu, Nov 03, 2016 at 03:29:22PM +0100, Neil Armstrong wrote:
> Thie patchset is a very experiment patchset to support the System Suspend
> feature of the Amlogic Meson GX SoCs.
>
> These SoCs implements system suspend using a non-standard PSCI CPU_SUSPEND
> parameter to enter system suspend.
This sounds like a violation of the CPU_SUSPEND semantics.
> A small driver is added to properly fill the platform_suspend_ops and make
> to correct SMC call.
Ignoring the fact that this is a blatant violation of the PSCI CPU_SUSPEND
semantics, this certainly should not be a separate driver.
> In order to wake up from an alarm, these SoCs have a special memory mapped
> register where an alarm time delay in seconds is stored.
> In order to reuse the RTC wakealarm feature, implement a fake RTC device
> that uses the system time to calculate a delay to write to the register.
>
> Note that this RFC is here to seek a better way to handle these platform
> specific features.
>
> Neil Armstrong (3):
> ARM64: meson: Add Amlogic Meson GX PM Suspend
> rtc: Add Amlogic Virtual Wake RTC
> ARM64: dts: meson-gxbb: Add support for PM and Virtual RTC
>
> arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 ++
> drivers/firmware/meson/Kconfig | 6 +
> drivers/firmware/meson/Makefile | 1 +
> drivers/firmware/meson/meson_gx_pm.c | 86 +++++++++++++++
> drivers/rtc/Kconfig | 10 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-meson-vrtc.c | 164 ++++++++++++++++++++++++++++
> 7 files changed, 277 insertions(+)
> create mode 100644 drivers/firmware/meson/meson_gx_pm.c
> create mode 100644 drivers/rtc/rtc-meson-vrtc.c
>
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2] of, numa: Return NUMA_NO_NODE from disable of_node_to_nid() if nid not possible.
From: David Daney @ 2016-11-03 15:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_JsqKnXk99SUa1cjC2QFA9rizjn4=JHZh3ua_gvcOtpGx8jg@mail.gmail.com>
On 11/02/2016 08:37 PM, Rob Herring wrote:
> On Fri, Oct 28, 2016 at 4:15 PM, David Daney <ddaney.cavm@gmail.com> wrote:
>> From: David Daney <david.daney@cavium.com>
>>
>> On arm64 NUMA kernels we can pass "numa=off" on the command line to
>> disable NUMA. A side effect of this is that kmalloc_node() calls to
>> non-zero nodes will crash the system with an OOPS:
>>
>> [ 0.000000] ITS at 0x0000901000020000: allocated 2097152 Devices @10002000000 (flat, esz 8, psz 64K, shr 1)
>> [ 0.000000] Unable to handle kernel NULL pointer dereference at virtual address 00001680
>> [ 0.000000] pgd = fffffc0009470000
>> [ 0.000000] [00001680] *pgd=0000010ffff90003, *pud=0000010ffff90003, *pmd=0000010ffff90003, *pte=0000000000000000
>> [ 0.000000] Internal error: Oops: 96000006 [#1] SMP
>> .
>> .
>> .
>> [ 0.000000] [<fffffc00081c8950>] __alloc_pages_nodemask+0xa4/0xe68
>> [ 0.000000] [<fffffc000821fa70>] new_slab+0xd0/0x564
>> [ 0.000000] [<fffffc0008221e24>] ___slab_alloc+0x2e4/0x514
>> [ 0.000000] [<fffffc0008239498>] __slab_alloc+0x48/0x58
>> [ 0.000000] [<fffffc0008222c20>] __kmalloc_node+0xd0/0x2dc
>> [ 0.000000] [<fffffc0008115374>] __irq_domain_add+0x7c/0x164
>> [ 0.000000] [<fffffc0008b461dc>] its_probe+0x784/0x81c
>> [ 0.000000] [<fffffc0008b462bc>] its_init+0x48/0x1b0
>> [ 0.000000] [<fffffc0008b4543c>] gic_init_bases+0x228/0x360
>> [ 0.000000] [<fffffc0008b456bc>] gic_of_init+0x148/0x1cc
>> [ 0.000000] [<fffffc0008b5aec8>] of_irq_init+0x184/0x298
>> [ 0.000000] [<fffffc0008b43f9c>] irqchip_init+0x14/0x38
>> [ 0.000000] [<fffffc0008b12d60>] init_IRQ+0xc/0x30
>> [ 0.000000] [<fffffc0008b10a3c>] start_kernel+0x240/0x3b8
>> [ 0.000000] [<fffffc0008b101c4>] __primary_switched+0x30/0x6c
>> [ 0.000000] Code: 912ec2a0 b9403809 0a0902fb 37b007db (f9400300)
>> .
>> .
>> .
>>
>> This is caused by code like this in kernel/irq/irqdomain.c
>>
>> domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
>> GFP_KERNEL, of_node_to_nid(of_node));
>>
>> When NUMA is disabled, the concept of a node is really undefined, so
>> of_node_to_nid() should unconditionally return NUMA_NO_NODE.
>>
>> Fix by returning NUMA_NO_NODE when the nid is not in the set of
>> possible nodes.
>>
>> Reported-by: Gilbert Netzer <noname@pdc.kth.se>
>> Signed-off-by: David Daney <david.daney@cavium.com>
>
> Does this need to go in 4.9?
That would be my preference.
> stable? If so, since what kernel version?
>
v4.7 and later would be nice.
I guess if you merge it, you could add the Cc: stable@ tag
Thanks for looking at this,
David Daney
^ permalink raw reply
* [PATCH v8 3/3] ARM: dts: alt: Enable UHS-I SDR-104
From: Simon Horman @ 2016-11-03 15:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478185645-25556-1-git-send-email-horms+renesas@verge.net.au>
And the sd-uhs-sdr104 property to SDHI0.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
arch/arm/boot/dts/r8a7794-alt.dts | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index 325d3f972c57..ccb80d66076f 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -277,6 +277,7 @@
cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>;
wp-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
sd-uhs-sdr50;
+ sd-uhs-sdr104;
status = "okay";
};
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH v8 2/3] ARM: dts: koelsch: Enable UHS-I SDR-104
From: Simon Horman @ 2016-11-03 15:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478185645-25556-1-git-send-email-horms+renesas@verge.net.au>
And the sd-uhs-sdr104 property to SDHI0.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
arch/arm/boot/dts/r8a7791-koelsch.dts | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index c457b43deb7d..57e69af65136 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -499,6 +499,7 @@
cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>;
wp-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>;
sd-uhs-sdr50;
+ sd-uhs-sdr104;
status = "okay";
};
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH v8 1/3] ARM: dts: lager: Enable UHS-I SDR-104
From: Simon Horman @ 2016-11-03 15:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478185645-25556-1-git-send-email-horms+renesas@verge.net.au>
Add the sd-uhs-sdr104 property to SDHI0.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
arch/arm/boot/dts/r8a7790-lager.dts | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index 434268262d88..e42748a5fe10 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -575,6 +575,7 @@
vqmmc-supply = <&vccq_sdhi0>;
cd-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
sd-uhs-sdr50;
+ sd-uhs-sdr104;
status = "okay";
};
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH v8 0/3] ARM, arm64: renesas: Enable UHS-I SDR-104
From: Simon Horman @ 2016-11-03 15:07 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
this series enables SDHI UHS-I SDR-104 on:
* r8a7790/lager
* r8a7791/koelsch
* r8a7794/alt
It is based on renesas-next-20161102-v4.9-rc1.
For functional SDR-104 support the following dependencies are needed:
* [PATCH v8 0/6] UHS-I SDR-104 support for sh_mobile_sdhi
To aid review the following git branches are provided:
* This patchset:
https:://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git topic/sdr104-integration-v8
* This patch-set and above dependency
https:://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git topic/sdr104-v8
Changes since v7:
* Dropped merged matches
* Dropped r8a779[56]/salvator-x patches for now as it seems further work is
required in order to reliably enable SDR104 on those SoCs.
Simon Horman (3):
ARM: dts: lager: Enable UHS-I SDR-104
ARM: dts: koelsch: Enable UHS-I SDR-104
ARM: dts: alt: Enable UHS-I SDR-104
arch/arm/boot/dts/r8a7790-lager.dts | 1 +
arch/arm/boot/dts/r8a7791-koelsch.dts | 1 +
arch/arm/boot/dts/r8a7794-alt.dts | 1 +
3 files changed, 3 insertions(+)
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply
* [PATCH v7 3/3] iio: adc: add support for Allwinner SoCs ADC
From: Lee Jones @ 2016-11-03 14:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161103101601.24529-4-quentin.schulz@free-electrons.com>
On Thu, 03 Nov 2016, Quentin Schulz wrote:
> The Allwinner SoCs all have an ADC that can also act as a touchscreen
> controller and a thermal sensor. This patch adds the ADC driver which is
> based on the MFD for the same SoCs ADC.
>
> This also registers the thermal adc channel in the iio map array so
> iio_hwmon could use it without modifying the Device Tree. This registers
> the driver in the thermal framework.
>
> The thermal sensor requires the IP to be in touchscreen mode to return correct
> values. Therefore, if the user is continuously reading the ADC channel(s), the
> thermal framework in which the thermal sensor is registered will switch the IP
> in touchscreen mode to get a temperature value and requires a delay of 100ms
> (because of the mode switching), then the ADC will switch back to ADC mode and
> requires also a delay of 100ms. If the ADC readings are critical to user and the
> SoC temperature is not, this driver is capable of not registering the thermal
> sensor in the thermal framework and thus, "quicken" the ADC readings.
>
> This driver probes on three different platform_device_id to take into
> account slight differences (registers bit and temperature computation)
> between Allwinner SoCs ADCs.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>
> v7:
> - add Kconfig depends on !TOUCHSCREEN_SUN4I,
> - remove Kconfig selects THERMAL_OF,
> - do not register thermal sensor if CONFIG_THERMAL_OF is disabled,
> - disable irq in irq_handler rather than in read_raw,
> - add delay when switching the IP's mode or channel (delay empirically found),
> - quicken thermal sensor interrupt period,
> - add masks for channel bits,
> - fix deadlock in sun4i_gpadc_read if regmap_read/write fails,
> - move some logic from sun4i_gpadc_read to sun4i_prepare_for_irq,
> - mark last busy for runtime_pm only on success in sun4i_gpadc_read,
> - remove cached values,
> - increase wait_for_completion_timeout timeout to 1s to be sure to not miss the
> thermal interrupt,
> - add voltage scale,
> - use devm_iio_device_register,
>
> v6:
> - remove "-mfd" from filenames and variables inside MFD driver,
> - use DEFINE_RES_IRQ_NAMED instead of setting resources manually,
> - cosmetic changes,
> - use IDs and switch over ID to get cells specific to an architecture, instead
> of using cells direclty, in of_device_id.data,
> - compute size of mfd_cells array instead of hardcoded one,
>
> v5:
> - correct mail address,
>
> v4:
> - rename files and variables from sunxi* to sun4i*,
> - rename defines from SUNXI_* to SUN4I_* or SUN6I_*,
> - remove TP in defines name,
> - rename SUNXI_IRQ_* to SUN4I_GPADC_IRQ_* for consistency,
> - use devm functions for regmap_add_irq_chip and mfd_add_devices,
> - remove remove functions (now empty thanks to devm functions),
>
> v3:
> - use defines in regmap_irq instead of hard coded BITs,
> - use of_device_id data field to chose which MFD cells to add considering
> the compatible responsible of the MFD probe,
> - remove useless initializations,
> - disable all interrupts before adding them to regmap_irqchip,
> - add goto error label in probe,
> - correct wrapping in header license,
> - move defines from IIO driver to header,
> - use GENMASK to limit the size of the variable passed to a macro,
> - prefix register BIT defines with the name of the register,
> - reorder defines,
>
> v2:
> - add license headers,
> - reorder alphabetically includes,
> - add SUNXI_GPADC_ prefixes for defines,
>
> drivers/iio/adc/Kconfig | 17 ++
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/sun4i-gpadc-iio.c | 605 ++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/sun4i-gpadc.h | 2 +
> 4 files changed, 625 insertions(+)
> create mode 100644 drivers/iio/adc/sun4i-gpadc-iio.c
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 7edcf32..9aa3c945 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -434,6 +434,23 @@ config STX104
> The base port addresses for the devices may be configured via the base
> array module parameter.
>
> +config SUN4I_GPADC
> + tristate "Support for the Allwinner SoCs GPADC"
> + depends on IIO
> + depends on MFD_SUN4I_GPADC
> + depends on !TOUCHSCREEN_SUN4I
> + help
> + Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
> + GPADC. This ADC provides 4 channels which can be used as an ADC or as
> + a touchscreen input and one channel for thermal sensor.
> +
> + The thermal sensor is activated by default but slows down ADC
> + readings. You can disable CONFIG_THERMAL_OF to disable the CPU thermal
> + sensor if you want faster ADC readings.
> +
> + To compile this driver as a module, choose M here: the module will be
> + called sun4i-gpadc-iio.
> +
> config TI_ADC081C
> tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
> depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 7a40c04..18ce8d6 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -41,6 +41,7 @@ obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
> obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
> obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
> obj-$(CONFIG_STX104) += stx104.o
> +obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
> obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
> obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
> obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
> new file mode 100644
> index 0000000..f275ccb
> --- /dev/null
> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
> @@ -0,0 +1,605 @@
> +/* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC
> + *
> + * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + *
> + * The Allwinner SoCs all have an ADC that can also act as a touchscreen
> + * controller and a thermal sensor.
> + * The thermal sensor works only when the ADC acts as a touchscreen controller
> + * and is configured to throw an interrupt every fixed periods of time (let say
> + * every X seconds).
> + * One would be tempted to disable the IP on the hardware side rather than
> + * disabling interrupts to save some power but that resets the internal clock of
> + * the IP, resulting in having to wait X seconds every time we want to read the
> + * value of the thermal sensor.
> + * This is also the reason of using autosuspend in pm_runtime. If there was no
> + * autosuspend, the thermal sensor would need X seconds after every
> + * pm_runtime_get_sync to get a value from the ADC. The autosuspend allows the
> + * thermal sensor to be requested again in a certain time span before it gets
> + * shutdown for not being used.
> + */
> +
> +#include <linux/completion.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/thermal.h>
> +#include <linux/delay.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/driver.h>
> +#include <linux/iio/machine.h>
> +#include <linux/mfd/sun4i-gpadc.h>
> +
> +static unsigned int sun4i_gpadc_chan_select(unsigned int chan)
> +{
> + return SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
> +}
> +
> +static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
> +{
> + return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
> +}
> +
> +struct gpadc_data {
> + int temp_offset;
> + int temp_scale;
> + unsigned int tp_mode_en;
> + unsigned int tp_adc_select;
> + unsigned int (*adc_chan_select)(unsigned int chan);
> + unsigned int adc_chan_mask;
> +};
> +
> +static const struct gpadc_data sun4i_gpadc_data = {
> + .temp_offset = -1932,
> + .temp_scale = 133,
> + .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
> + .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
> + .adc_chan_select = &sun4i_gpadc_chan_select,
> + .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
> +};
> +
> +static const struct gpadc_data sun5i_gpadc_data = {
> + .temp_offset = -1447,
> + .temp_scale = 100,
> + .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
> + .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
> + .adc_chan_select = &sun4i_gpadc_chan_select,
> + .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
> +};
> +
> +static const struct gpadc_data sun6i_gpadc_data = {
> + .temp_offset = -1623,
> + .temp_scale = 167,
> + .tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
> + .tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
> + .adc_chan_select = &sun6i_gpadc_chan_select,
> + .adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
> +};
> +
> +struct sun4i_gpadc_iio {
> + struct iio_dev *indio_dev;
> + struct completion completion;
> + int temp_data;
> + u32 adc_data;
> + struct regmap *regmap;
> + unsigned int fifo_data_irq;
> + atomic_t ignore_fifo_data_irq;
> + unsigned int temp_data_irq;
> + atomic_t ignore_temp_data_irq;
> + const struct gpadc_data *data;
> + /* prevents concurrent reads of temperature and ADC */
> + struct mutex mutex;
> +};
> +
> +#define SUN4I_GPADC_ADC_CHANNEL(_channel, _name) { \
> + .type = IIO_VOLTAGE, \
> + .indexed = 1, \
> + .channel = _channel, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> + .datasheet_name = _name, \
> +}
> +
> +static struct iio_map sun4i_gpadc_hwmon_maps[] = {
> + {
> + .adc_channel_label = "temp_adc",
> + .consumer_dev_name = "iio_hwmon.0",
> + },
> + { /* sentinel */ },
> +};
> +
> +static const struct iio_chan_spec sun4i_gpadc_channels[] = {
> + SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
> + SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
> + SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
> + SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
> + {
> + .type = IIO_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE) |
> + BIT(IIO_CHAN_INFO_OFFSET),
> + .datasheet_name = "temp_adc",
> + },
> +};
> +
> +static const struct iio_chan_spec sun4i_gpadc_channels_no_temp[] = {
> + SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
> + SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
> + SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
> + SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
> +};
> +
> +static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
> + unsigned int irq)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
> + int ret;
> + u32 reg;
> +
> + pm_runtime_get_sync(indio_dev->dev.parent);
> +
> + reinit_completion(&info->completion);
> +
> + ret = regmap_write(info->regmap, SUN4I_GPADC_INT_FIFOC,
> + SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(1) |
> + SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(info->regmap, SUN4I_GPADC_CTRL1, ®);
> + if (ret)
> + return ret;
> +
> + if (irq == info->fifo_data_irq) {
> + ret = regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
> + info->data->tp_mode_en |
> + info->data->tp_adc_select |
> + info->data->adc_chan_select(channel));
> + /*
> + * When the IP changes channel, it needs a bit of time to get
> + * correct values.
> + */
> + if ((reg & info->data->adc_chan_mask) !=
> + info->data->adc_chan_select(channel))
> + mdelay(10);
> +
> + } else {
> + /*
> + * The temperature sensor returns valid data only when the ADC
> + * operates in touchscreen mode.
> + */
> + ret = regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
> + info->data->tp_mode_en);
> + }
> +
> + if (ret)
> + return ret;
> +
> + /*
> + * When the IP changes mode between ADC or touchscreen, it
> + * needs a bit of time to get correct values.
> + */
> + if ((reg & info->data->tp_adc_select) != info->data->tp_adc_select)
> + mdelay(100);
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val,
> + unsigned int irq)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
> + int ret;
> +
> + mutex_lock(&info->mutex);
> +
> + ret = sun4i_prepare_for_irq(indio_dev, channel, irq);
> + if (ret)
> + goto err;
> +
> + enable_irq(irq);
> +
> + /*
> + * The temperature sensor throws an interruption periodically (currently
> + * set at periods of ~0.6s in sun4i_gpadc_runtime_resume). A 1s delay
> + * makes sure an interruption occurs in normal conditions. If it doesn't
> + * occur, then there is a timeout.
> + */
> + if (!wait_for_completion_timeout(&info->completion,
> + msecs_to_jiffies(1000))) {
> + ret = -ETIMEDOUT;
> + goto err;
> + }
> +
> + if (irq == info->fifo_data_irq)
> + *val = info->adc_data;
> + else
> + *val = info->temp_data;
> +
> + ret = 0;
> + pm_runtime_mark_last_busy(indio_dev->dev.parent);
> +
> +err:
> + pm_runtime_put_autosuspend(indio_dev->dev.parent);
> + mutex_unlock(&info->mutex);
> +
> + return ret;
> +}
> +
> +static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
> + int *val)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
> +
> + return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
> +}
> +
> +static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
> +
> + return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
> +}
> +
> +static int sun4i_gpadc_temp_offset(struct iio_dev *indio_dev, int *val)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
> +
> + *val = info->data->temp_offset;
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_temp_scale(struct iio_dev *indio_dev, int *val)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
> +
> + *val = info->data->temp_scale;
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_OFFSET:
> + ret = sun4i_gpadc_temp_offset(indio_dev, val);
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_RAW:
> + if (chan->type == IIO_VOLTAGE)
> + ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
> + val);
> + else
> + ret = sun4i_gpadc_temp_read(indio_dev, val);
> +
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_SCALE:
> + if (chan->type == IIO_VOLTAGE) {
> + /* 3000mV / 4096 * raw */
> + *val = 0;
> + *val2 = 732421875;
> + return IIO_VAL_INT_PLUS_MICRO;
> + }
> +
> + ret = sun4i_gpadc_temp_scale(indio_dev, val);
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static const struct iio_info sun4i_gpadc_iio_info = {
> + .read_raw = sun4i_gpadc_read_raw,
> + .driver_module = THIS_MODULE,
> +};
> +
> +static irqreturn_t sun4i_gpadc_temp_data_irq_handler(int irq, void *dev_id)
> +{
> + struct sun4i_gpadc_iio *info = dev_id;
> +
> + if (atomic_read(&info->ignore_temp_data_irq))
> + goto out;
> +
> + if (!regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, &info->temp_data))
> + complete(&info->completion);
> +
> +out:
> + disable_irq_nosync(info->temp_data_irq);
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
> +{
> + struct sun4i_gpadc_iio *info = dev_id;
> +
> + if (atomic_read(&info->ignore_fifo_data_irq))
> + goto out;
> +
> + if (!regmap_read(info->regmap, SUN4I_GPADC_DATA, &info->adc_data))
> + complete(&info->completion);
> +
> +out:
> + disable_irq_nosync(info->fifo_data_irq);
> + return IRQ_HANDLED;
> +}
> +
> +static int sun4i_gpadc_runtime_suspend(struct device *dev)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
> +
> + /* Disable the ADC on IP */
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
> + /* Disable temperature sensor on IP */
> + regmap_write(info->regmap, SUN4I_GPADC_TPR, 0);
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_runtime_resume(struct device *dev)
> +{
> + struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
> +
> + /* clkin = 6MHz */
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
> + SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
> + SUN4I_GPADC_CTRL0_FS_DIV(7) |
> + SUN4I_GPADC_CTRL0_T_ACQ(63));
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL1, info->data->tp_mode_en);
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL3,
> + SUN4I_GPADC_CTRL3_FILTER_EN |
> + SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
> + /* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s */
> + regmap_write(info->regmap, SUN4I_GPADC_TPR,
> + SUN4I_GPADC_TPR_TEMP_ENABLE |
> + SUN4I_GPADC_TPR_TEMP_PERIOD(800));
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_get_temp(void *data, int *temp)
> +{
> + struct sun4i_gpadc_iio *info = (struct sun4i_gpadc_iio *)data;
> + int val, scale, offset;
> +
> + if (sun4i_gpadc_temp_read(info->indio_dev, &val))
> + return -ETIMEDOUT;
> +
> + sun4i_gpadc_temp_scale(info->indio_dev, &scale);
> + sun4i_gpadc_temp_offset(info->indio_dev, &offset);
> +
> + *temp = (val + offset) * scale;
> +
> + return 0;
> +}
> +
> +static const struct thermal_zone_of_device_ops sun4i_ts_tz_ops = {
> + .get_temp = &sun4i_gpadc_get_temp,
> +};
> +
> +static const struct dev_pm_ops sun4i_gpadc_pm_ops = {
> + .runtime_suspend = &sun4i_gpadc_runtime_suspend,
> + .runtime_resume = &sun4i_gpadc_runtime_resume,
> +};
> +
> +static int sun4i_irq_init(struct platform_device *pdev, const char *name,
> + irq_handler_t handler, const char *devname,
> + unsigned int *irq, atomic_t *atomic)
> +{
> + int ret;
> + struct sun4i_gpadc_dev *mfd_dev = dev_get_drvdata(pdev->dev.parent);
> + struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(&pdev->dev));
> +
> + /*
> + * Once the interrupt is activated, the IP continuously performs
> + * conversions thus throws interrupts. The interrupt is activated right
> + * after being requested but we want to control when these interrupts
> + * occur thus we disable it right after being requested. However, an
> + * interrupt might occur between these two instructions and we have to
> + * make sure that does not happen, by using atomic flags. We set the
> + * flag before requesting the interrupt and unset it right after
> + * disabling the interrupt. When an interrupt occurs between these two
> + * instructions, reading the atomic flag will tell us to ignore the
> + * interrupt.
> + */
> + atomic_set(atomic, 1);
> +
> + *irq = platform_get_irq_byname(pdev, name);
> + if (*irq < 0) {
> + dev_err(&pdev->dev, "no %s interrupt registered\n", name);
> + return *irq;
> + }
> +
> + *irq = regmap_irq_get_virq(mfd_dev->regmap_irqc, *irq);
> + ret = devm_request_any_context_irq(&pdev->dev, *irq, handler, 0,
> + devname, info);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "could not request %s interrupt: %d\n",
> + name, ret);
> + return ret;
> + }
> +
> + disable_irq(*irq);
> + atomic_set(atomic, 0);
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_probe(struct platform_device *pdev)
> +{
> + struct sun4i_gpadc_iio *info;
> + struct iio_dev *indio_dev;
> + int ret;
> + struct sun4i_gpadc_dev *sun4i_gpadc_dev;
> + struct thermal_zone_device *tzd;
> +
> + sun4i_gpadc_dev = dev_get_drvdata(pdev->dev.parent);
> +
> + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + info = iio_priv(indio_dev);
> + platform_set_drvdata(pdev, indio_dev);
> +
> + mutex_init(&info->mutex);
> + info->regmap = sun4i_gpadc_dev->regmap;
> + info->indio_dev = indio_dev;
> + init_completion(&info->completion);
> + indio_dev->name = dev_name(&pdev->dev);
> + indio_dev->dev.parent = &pdev->dev;
> + indio_dev->dev.of_node = pdev->dev.of_node;
> + indio_dev->info = &sun4i_gpadc_iio_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels);
> + indio_dev->channels = sun4i_gpadc_channels;
> +
> + info->data = (struct gpadc_data *)platform_get_device_id(pdev)->driver_data;
> +
> + /*
> + * Since the thermal sensor needs the IP to be in touchscreen mode and
> + * there is no register to know if the IP has finished its transition
> + * between the two modes, a delay is required when switching modes. This
> + * slows down ADC readings while the latter are critical data to the
> + * user. Disabling CONFIG_THERMAL_OF in kernel configuration allows the
> + * user to avoid registering the thermal sensor (thus unavailable) and
> + * does not switch between modes thus "quicken" the ADC readings.
> + * The thermal sensor should be enabled by default since the SoC
> + * temperature is usually more critical than ADC readings.
> + */
> +
> + if (IS_ENABLED(CONFIG_THERMAL_OF)) {
> + /*
> + * This driver is a child of an MFD which has a node in the DT but not
> + * its children. Therefore, the resulting devices of this driver do not
> + * have an of_node variable.
> + * However, its parent (the MFD driver) has an of_node variable and
> + * since devm_thermal_zone_of_sensor_register uses its first argument to
> + * match the phandle defined in the node of the thermal driver with the
> + * of_node of the device passed as first argument and the third argument
> + * to call ops from thermal_zone_of_device_ops, the solution is to use
> + * the parent device as first argument to match the phandle with its
> + * of_node, and the device from this driver as third argument to return
> + * the temperature.
> + */
> + tzd = devm_thermal_zone_of_sensor_register(pdev->dev.parent, 0,
> + info,
> + &sun4i_ts_tz_ops);
> + if (IS_ERR(tzd)) {
> + dev_err(&pdev->dev,
> + "could not register thermal sensor: %ld\n",
> + PTR_ERR(tzd));
> + goto err;
> + }
> + } else {
> + indio_dev->num_channels =
> + ARRAY_SIZE(sun4i_gpadc_channels_no_temp);
> + indio_dev->channels = sun4i_gpadc_channels_no_temp;
> + }
> +
> + pm_runtime_set_autosuspend_delay(&pdev->dev,
> + SUN4I_GPADC_AUTOSUSPEND_DELAY);
> + pm_runtime_use_autosuspend(&pdev->dev);
> + pm_runtime_set_suspended(&pdev->dev);
> + pm_runtime_enable(&pdev->dev);
> +
> + if (IS_ENABLED(CONFIG_THERMAL_OF)) {
> + ret = sun4i_irq_init(pdev, "TEMP_DATA_PENDING",
> + sun4i_gpadc_temp_data_irq_handler,
> + "temp_data", &info->temp_data_irq,
> + &info->ignore_temp_data_irq);
> + if (ret < 0)
> + goto err;
> + }
> +
> + ret = sun4i_irq_init(pdev, "FIFO_DATA_PENDING",
> + sun4i_gpadc_fifo_data_irq_handler, "fifo_data",
> + &info->fifo_data_irq, &info->ignore_fifo_data_irq);
> + if (ret < 0)
> + goto err;
> +
> + if (IS_ENABLED(CONFIG_THERMAL_OF)) {
> + ret = iio_map_array_register(indio_dev, sun4i_gpadc_hwmon_maps);
> + if (ret < 0) {
> + dev_err(&pdev->dev,
> + "failed to register iio map array\n");
> + goto err;
> + }
> + }
> +
> + ret = devm_iio_device_register(&pdev->dev, indio_dev);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "could not register the device\n");
> + goto err_map;
> + }
> +
> + return 0;
> +
> +err_map:
> + if (IS_ENABLED(CONFIG_THERMAL_OF))
> + iio_map_array_unregister(indio_dev);
> +
> +err:
> + pm_runtime_put(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> +
> + return ret;
> +}
> +
> +static int sun4i_gpadc_remove(struct platform_device *pdev)
> +{
> + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +
> + pm_runtime_put(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> + if (IS_ENABLED(CONFIG_THERMAL_OF))
> + iio_map_array_unregister(indio_dev);
> +
> + return 0;
> +}
> +
> +static const struct platform_device_id sun4i_gpadc_id[] = {
> + { "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data },
> + { "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data },
> + { "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data },
> + { /* sentinel */ },
> +};
> +
> +static struct platform_driver sun4i_gpadc_driver = {
> + .driver = {
> + .name = "sun4i-gpadc-iio",
> + .pm = &sun4i_gpadc_pm_ops,
> + },
> + .id_table = sun4i_gpadc_id,
> + .probe = sun4i_gpadc_probe,
> + .remove = sun4i_gpadc_remove,
> +};
> +
> +module_platform_driver(sun4i_gpadc_driver);
> +
> +MODULE_DESCRIPTION("ADC driver for sunxi platforms");
> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
> index d7a29f2..509e736 100644
> --- a/include/linux/mfd/sun4i-gpadc.h
> +++ b/include/linux/mfd/sun4i-gpadc.h
> @@ -28,6 +28,7 @@
> #define SUN4I_GPADC_CTRL1_TP_MODE_EN BIT(4)
> #define SUN4I_GPADC_CTRL1_TP_ADC_SELECT BIT(3)
> #define SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(2, 0) & (x))
> +#define SUN4I_GPADC_CTRL1_ADC_CHAN_MASK GENMASK(2, 0)
>
> /* TP_CTRL1 bits for sun6i SOCs */
> #define SUN6I_GPADC_CTRL1_TOUCH_PAN_CALI_EN BIT(7)
> @@ -35,6 +36,7 @@
> #define SUN6I_GPADC_CTRL1_TP_MODE_EN BIT(5)
> #define SUN6I_GPADC_CTRL1_TP_ADC_SELECT BIT(4)
> #define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x))
> +#define SUN6I_GPADC_CTRL1_ADC_CHAN_MASK GENMASK(3, 0)
>
> #define SUN4I_GPADC_CTRL2 0x08
>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v2 1/2] PM/devfreq: add suspend frequency support
From: kbuild test robot @ 2016-11-03 14:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478153770-8433-2-git-send-email-hl@rock-chips.com>
Hi Lin,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc3 next-20161028]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Lin-Huang/set-specific-ddr-frequency-when-stop-ddr-dvfs/20161103-142055
config: x86_64-randconfig-x015-201644 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/devfreq/devfreq.c: In function 'devfreq_monitor_suspend':
>> drivers/devfreq/devfreq.c:368:3: error: too many arguments to function 'update_devfreq'
update_devfreq(devfreq, devfreq->suspend_freq);
^~~~~~~~~~~~~~
drivers/devfreq/devfreq.c:228:5: note: declared here
int update_devfreq(struct devfreq *devfreq)
^~~~~~~~~~~~~~
vim +/update_devfreq +368 drivers/devfreq/devfreq.c
362 if (devfreq->stop_polling) {
363 mutex_unlock(&devfreq->lock);
364 return;
365 }
366
367 if (devfreq->suspend_freq)
> 368 update_devfreq(devfreq, devfreq->suspend_freq);
369 else
370 devfreq_update_status(devfreq, devfreq->previous_freq);
371 devfreq->stop_polling = true;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 23592 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161103/9251898a/attachment-0001.gz>
^ permalink raw reply
* [PATCHv3 1/4] dt-bindings: mfd: Add Altera Arria10 SR Monitor
From: Lee Jones @ 2016-11-03 14:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478097178-24341-2-git-send-email-tthayer@opensource.altera.com>
On Wed, 02 Nov 2016, tthayer at opensource.altera.com wrote:
> From: Thor Thayer <tthayer@opensource.altera.com>
>
> Add the Arria10 DevKit System Resource Chip register and state
> monitoring module to the MFD.
>
> Signed-off-by: Thor Thayer <tthayer@opensource.altera.com>
> ---
> Note: This needs to be applied to the bindings document that
> was Acked & Applied but didn't reach the for-next branch.
> See https://patchwork.ozlabs.org/patch/629397/
> ---
> v2 Change compatible string -mon to -monitor for clarity
> v3 Replace node name a10sr_monitor with just monitor.
> Replace node name a10sr_gpio with just gpio.
> ---
> Documentation/devicetree/bindings/mfd/altera-a10sr.txt | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> diff --git a/Documentation/devicetree/bindings/mfd/altera-a10sr.txt b/Documentation/devicetree/bindings/mfd/altera-a10sr.txt
> index ea151f2..69243d2 100644
> --- a/Documentation/devicetree/bindings/mfd/altera-a10sr.txt
> +++ b/Documentation/devicetree/bindings/mfd/altera-a10sr.txt
> @@ -17,7 +17,8 @@ The A10SR consists of these sub-devices:
>
> Device Description
> ------ ----------
> -a10sr_gpio GPIO Controller
> +gpio GPIO Controller
> +monitor Register and State Monitoring
>
> Arria10 GPIO
> Required Properties:
> @@ -27,6 +28,10 @@ Required Properties:
> the second cell is used to specify flags.
> See ../gpio/gpio.txt for more information.
>
> +Arria10 Register and State Monitor
> +Required Properties:
> +- compatible : Should be "altr,a10sr-monitor"
> +
> Example:
>
> resource-manager at 0 {
> @@ -43,4 +48,8 @@ Example:
> gpio-controller;
> #gpio-cells = <2>;
> };
> +
> + monitor {
> + compatible = "altr,a10sr-monitor";
> + };
> };
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH] clk: rockchip: fix some clocks' name to be more standard style
From: Heiko Stübner @ 2016-11-03 14:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <763cad68-a068-9a4b-e26d-2c459c2d4808@rock-chips.com>
Am Donnerstag, 3. November 2016, 16:52:48 schrieb Shawn Lin:
> On 2016/11/2 15:04, Jianqun Xu wrote:
> > Fix aclk_emmcgrf to aclk_emmc_grf, and fix aclk_emmccore to be
> > aclk_emmc_core.
>
> What is the standard style should be?
>
> TRM uses aclk_emmccore but not aclk_emmc_core, so should it be more
> standrad to keep it as-is?
I tend to agree with Shawn. While it looks like the missing "_" is some sort
of mistake, we should strive to follow TRM naming, so grepping so it becomes
easier to look for informations in these things in the TRM.
Same reason for naming our regulators and pinctrl after the names used in
device schematics, if available.
Heiko
^ permalink raw reply
* [PATCH 1/1] KVM: ARM64: Fix the issues when PMCCFILTR is configured
From: Wei Huang @ 2016-11-03 14:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <db2cdc7caf7dc40b0895e1b6f91c7758@codeaurora.org>
On 11/02/2016 11:11 PM, cov at codeaurora.org wrote:
> Hi Wei,
>
> On 2016-11-02 14:55, Wei Huang wrote:
>> KVM calls kvm_pmu_set_counter_event_type() when PMCCFILTR is configured.
>> But this function can't deals with PMCCFILTR correctly because the
>> evtCount
>> bit of PMCCFILTR, which is reserved 0, conflits with the SW_INCR event
>> type of other PMXEVTYPER<n> registers. To fix it, when eventsel == 0, KVM
>> shouldn't return immediately, but instead it needs to check further if
>> select_idx is ARMV8_PMU_CYCLE_IDX.
>>
>> Another issue is that KVM shouldn't copy the eventsel bits of PMCCFILTER
>> directly to attr.config. Istead it shoudl convert the request to
>> perf_event of type 0x11 (i.e. the "cpu cycle" event type).
>>
>> Signed-off-by: Wei Huang <wei@redhat.com>
>> ---
>> virt/kvm/arm/pmu.c | 5 +++--
>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> index 6e9c40e..13cc812 100644
>> --- a/virt/kvm/arm/pmu.c
>> +++ b/virt/kvm/arm/pmu.c
>> @@ -379,7 +379,8 @@ void kvm_pmu_set_counter_event_type(struct
>> kvm_vcpu *vcpu, u64 data,
>> eventsel = data & ARMV8_PMU_EVTYPE_EVENT;
>>
>> /* Software increment event does't need to be backed by a perf
>> event */
>> - if (eventsel == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
>> + if (eventsel == ARMV8_PMU_EVTYPE_EVENT_SW_INCR &&
>> + select_idx != ARMV8_PMU_CYCLE_IDX)
>> return;
>>
>> memset(&attr, 0, sizeof(struct perf_event_attr));
>> @@ -391,7 +392,7 @@ void kvm_pmu_set_counter_event_type(struct
>> kvm_vcpu *vcpu, u64 data,
>> attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
>> attr.exclude_hv = 1; /* Don't count EL2 events */
>> attr.exclude_host = 1; /* Don't count host events */
>> - attr.config = eventsel;
>> + attr.config = (select_idx == ARMV8_PMU_CYCLE_IDX) ? 0x011 :
>> eventsel;
>
> Nit: Is there some way you could use ARMV8_PMUV3_PERFCTR_CPU_CYCLES
> currently
> defined in arch/arm64/kernel/perf_event.c?
The event definitions in perf_event.c are local to this file. To use
them, I have to re-factor them out to a header file, which is bigger
than this patch intended. How about adding the following line to
arch/arm64/include/asm/perf_event.h (i.e. the same file of
ARMV8_PMU_EVTYPE_EVENT_SW_INCR)?
#define ARMV8_PMU_EVTYPE_EVENT_CPU_CYCLES 0x11
>
> Thanks,
> Cov
^ permalink raw reply
* [RFC PATCH 3/3] ARM64: dts: meson-gxbb: Add support for PM and Virtual RTC
From: Neil Armstrong @ 2016-11-03 14:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478183365-23708-1-git-send-email-narmstrong@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 2d69a3b..6c08d21 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -56,6 +56,10 @@
};
};
+ system-suspend {
+ compatible = "amlogic,meson-gx-pm";
+ };
+
efuse: efuse {
compatible = "amlogic,meson-gxbb-efuse";
#address-cells = <1>;
@@ -355,6 +359,11 @@
#reset-cells = <1>;
};
+ vrtc: rtc at 0a8 {
+ compatible = "amlogic,meson-vrtc";
+ reg = <0x0 0x000a8 0x0 0x4>;
+ };
+
ir: ir at 580 {
compatible = "amlogic,meson-gxbb-ir";
reg = <0x0 0x00580 0x0 0x40>;
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 2/3] rtc: Add Amlogic Virtual Wake RTC
From: Neil Armstrong @ 2016-11-03 14:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478183365-23708-1-git-send-email-narmstrong@baylibre.com>
The Amlogic Meson GX SoCs uses a special register to store the
time in seconds to wakeup after a system suspend.
In order to be able to reuse the RTC wakealarm feature, this
driver implements a fake RTC device which uses the system time
to deduce a suspend delay.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/rtc/Kconfig | 10 +++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-meson-vrtc.c | 164 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 175 insertions(+)
create mode 100644 drivers/rtc/rtc-meson-vrtc.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e859d14..d0f65fb 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -351,6 +351,16 @@ config RTC_DRV_MAX77686
This driver can also be built as a module. If so, the module
will be called rtc-max77686.
+config RTC_DRV_MESON_VRTC
+ tristate "Amlogic Meson Virtual RTC"
+ depends on ARCH_MESON
+ help
+ If you say yes here you will get support for the
+ Virtual RTC of Amlogic SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-meson-vrtc.
+
config RTC_DRV_RK808
tristate "Rockchip RK808/RK818 RTC"
depends on MFD_RK808
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a..feb83ad 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
+obj-$(CONFIG_RTC_DRV_MESON_VRTC)+= rtc-meson-vrtc.o
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
diff --git a/drivers/rtc/rtc-meson-vrtc.c b/drivers/rtc/rtc-meson-vrtc.c
new file mode 100644
index 0000000..34c45bd
--- /dev/null
+++ b/drivers/rtc/rtc-meson-vrtc.c
@@ -0,0 +1,164 @@
+/*
+ * drivers/rtc/rtc-meson-vrtc.c
+ *
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/pm_wakeup.h>
+#include <linux/time64.h>
+
+struct meson_vrtc_data {
+ struct platform_device *pdev;
+ void __iomem *io_alarm;
+ struct rtc_device *rtc;
+ unsigned long alarm_time;
+};
+
+static int meson_vrtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long local_time;
+ struct timeval time;
+
+ do_gettimeofday(&time);
+ local_time = time.tv_sec - (sys_tz.tz_minuteswest * 60);
+ rtc_time_to_tm(local_time, tm);
+
+ return 0;
+}
+
+static void meson_vrtc_set_wakeup_time(struct meson_vrtc_data *vrtc,
+ unsigned long time)
+{
+ writel_relaxed(time, vrtc->io_alarm);
+
+ dev_dbg(&vrtc->pdev->dev, "set_wakeup_time: %lu\n", time);
+}
+
+static int meson_vrtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct meson_vrtc_data *vrtc = dev_get_drvdata(dev);
+ struct timeval time;
+ unsigned long local_time;
+ unsigned long alarm_secs;
+ int ret;
+
+ if (alarm->enabled) {
+ ret = rtc_tm_to_time(&alarm->time, &alarm_secs);
+ if (ret)
+ return ret;
+
+ do_gettimeofday(&time);
+ local_time = time.tv_sec - (sys_tz.tz_minuteswest * 60);
+
+ vrtc->alarm_time = alarm_secs;
+
+ if (alarm_secs >= local_time) {
+ alarm_secs = alarm_secs - local_time;
+
+ meson_vrtc_set_wakeup_time(vrtc, alarm_secs);
+
+ pr_debug("system will wakeup %lus later\n", alarm_secs);
+ }
+ } else {
+ vrtc->alarm_time = 0;
+ meson_vrtc_set_wakeup_time(vrtc, 0);
+ }
+
+ return 0;
+}
+
+static int meson_vrtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct meson_vrtc_data *vrtc = dev_get_drvdata(dev);
+
+ if (!vrtc->alarm_time) {
+ alm->enabled = true;
+
+ rtc_time_to_tm(vrtc->alarm_time, &alm->time);
+ }
+
+ return 0;
+}
+
+static const struct rtc_class_ops meson_vrtc_ops = {
+ .read_time = meson_vrtc_read_time,
+ .set_alarm = meson_vrtc_set_alarm,
+ .read_alarm = meson_vrtc_read_alarm,
+};
+
+static int meson_vrtc_probe(struct platform_device *pdev)
+{
+ struct meson_vrtc_data *vrtc;
+ struct resource *res;
+
+ vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL);
+ if (!vrtc)
+ return -ENOMEM;
+
+ vrtc->pdev = pdev;
+
+ /* Alarm registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ vrtc->io_alarm = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(vrtc->io_alarm))
+ return PTR_ERR(vrtc->io_alarm);
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ platform_set_drvdata(pdev, vrtc);
+
+ vrtc->rtc = devm_rtc_device_register(&pdev->dev, "meson-vrtc",
+ &meson_vrtc_ops, THIS_MODULE);
+ if (IS_ERR(vrtc->rtc))
+ return PTR_ERR(vrtc->rtc);
+
+ return 0;
+}
+
+int meson_vrtc_resume(struct platform_device *pdev)
+{
+ struct meson_vrtc_data *vrtc = platform_get_drvdata(pdev);
+
+ meson_vrtc_set_wakeup_time(vrtc, 0);
+
+ return 0;
+}
+
+static const struct of_device_id meson_vrtc_dt_match[] = {
+ { .compatible = "amlogic,meson-vrtc"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, meson_vrtc_dt_match);
+
+struct platform_driver meson_vrtc_driver = {
+ .driver = {
+ .name = "meson-vrtc",
+ .of_match_table = meson_vrtc_dt_match,
+ },
+ .probe = meson_vrtc_probe,
+ .resume = meson_vrtc_resume,
+};
+
+module_platform_driver(meson_vrtc_driver);
+
+MODULE_DESCRIPTION("Amlogic Virtual Wakeup RTC Timer driver");
+MODULE_LICENSE("GPL");
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 1/3] ARM64: meson: Add Amlogic Meson GX PM Suspend
From: Neil Armstrong @ 2016-11-03 14:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478183365-23708-1-git-send-email-narmstrong@baylibre.com>
The Amlogic Meson GX SoCs uses a non-standard argument to the
PSCI CPU_SUSPEND call to enter system suspend.
Implement such call within platform_suspend_ops.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/firmware/meson/Kconfig | 6 +++
drivers/firmware/meson/Makefile | 1 +
drivers/firmware/meson/meson_gx_pm.c | 86 ++++++++++++++++++++++++++++++++++++
3 files changed, 93 insertions(+)
create mode 100644 drivers/firmware/meson/meson_gx_pm.c
diff --git a/drivers/firmware/meson/Kconfig b/drivers/firmware/meson/Kconfig
index 170d7e8..5b3fea3 100644
--- a/drivers/firmware/meson/Kconfig
+++ b/drivers/firmware/meson/Kconfig
@@ -7,3 +7,9 @@ config MESON_SM
depends on ARM64_4K_PAGES
help
Say y here to enable the Amlogic secure monitor driver
+
+config MESON_GX_PM
+ bool
+ default ARCH_MESON if ARM64
+ help
+ Say y here to enable the Amlogic GX SoC Power Management
diff --git a/drivers/firmware/meson/Makefile b/drivers/firmware/meson/Makefile
index 9ab3884..b6e285d 100644
--- a/drivers/firmware/meson/Makefile
+++ b/drivers/firmware/meson/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_MESON_SM) += meson_sm.o
+obj-$(CONFIG_MESON_GX_PM) += meson_gx_pm.o
diff --git a/drivers/firmware/meson/meson_gx_pm.c b/drivers/firmware/meson/meson_gx_pm.c
new file mode 100644
index 0000000..c104c2e
--- /dev/null
+++ b/drivers/firmware/meson/meson_gx_pm.c
@@ -0,0 +1,86 @@
+/*
+ * Amlogic Meson GX Power Management
+ *
+ * Copyright (c) 2016 Baylibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <linux/arm-smccc.h>
+
+#include <uapi/linux/psci.h>
+
+#include <asm/suspend.h>
+
+/*
+ * The Amlogic GX SoCs uses a special argument value to the
+ * PSCI CPU_SUSPEND method to enter SUSPEND_MEM.
+ */
+
+#define MESON_SUSPEND_PARAM 0x0010000
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
+
+static int meson_gx_suspend_finish(unsigned long arg)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(PSCI_FN_NATIVE(0_2, CPU_SUSPEND), arg,
+ virt_to_phys(cpu_resume), 0, 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static int meson_gx_suspend_enter(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_MEM:
+ return cpu_suspend(MESON_SUSPEND_PARAM,
+ meson_gx_suspend_finish);
+ }
+
+ return -EINVAL;
+}
+
+static const struct platform_suspend_ops meson_gx_pm_ops = {
+ .enter = meson_gx_suspend_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+static const struct of_device_id meson_gx_pm_match[] = {
+ { .compatible = "amlogic,meson-gx-pm", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, meson_gx_pm_match);
+
+static int meson_gx_pm_probe(struct platform_device *pdev)
+{
+ suspend_set_ops(&meson_gx_pm_ops);
+
+ return 0;
+}
+
+static struct platform_driver meson_gx_pm_driver = {
+ .probe = meson_gx_pm_probe,
+ .driver = {
+ .name = "meson-gx-pm",
+ .of_match_table = meson_gx_pm_match,
+ },
+};
+
+module_platform_driver(meson_gx_pm_driver);
+
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Amlogic Meson GX PM driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 0/3] ARM64: meson-gxbb: Add support for system suspend
From: Neil Armstrong @ 2016-11-03 14:29 UTC (permalink / raw)
To: linux-arm-kernel
Thie patchset is a very experiment patchset to support the System Suspend
feature of the Amlogic Meson GX SoCs.
These SoCs implements system suspend using a non-standard PSCI CPU_SUSPEND
parameter to enter system suspend.
A small driver is added to properly fill the platform_suspend_ops and make
to correct SMC call.
In order to wake up from an alarm, these SoCs have a special memory mapped
register where an alarm time delay in seconds is stored.
In order to reuse the RTC wakealarm feature, implement a fake RTC device
that uses the system time to calculate a delay to write to the register.
Note that this RFC is here to seek a better way to handle these platform
specific features.
Neil Armstrong (3):
ARM64: meson: Add Amlogic Meson GX PM Suspend
rtc: Add Amlogic Virtual Wake RTC
ARM64: dts: meson-gxbb: Add support for PM and Virtual RTC
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 ++
drivers/firmware/meson/Kconfig | 6 +
drivers/firmware/meson/Makefile | 1 +
drivers/firmware/meson/meson_gx_pm.c | 86 +++++++++++++++
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-meson-vrtc.c | 164 ++++++++++++++++++++++++++++
7 files changed, 277 insertions(+)
create mode 100644 drivers/firmware/meson/meson_gx_pm.c
create mode 100644 drivers/rtc/rtc-meson-vrtc.c
--
1.9.1
^ permalink raw reply
* Use of GICv3/ITS with PCIe host-generic driver - resizing ITS MAPD?
From: Alan Douglas @ 2016-11-03 14:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8637j9iomo.fsf@arm.com>
Hi Marc,
> >> > When setting up bus 0, the ITS device is created, and
> >> > its_build_map_cmd() sets the size of the ITS MAPD based on the
> >> > number of interrupts claimed by bus 0. When subsequent buses are
> >> > enumerated, the ITS device will be reused, however we do not
> >> > increase the number of supported interrupts to allow for the
> >> > additional interrupts claimed by the additional devices being
> >> > enumerated. (This can be seen in its_msi_prepare(), which is
> >> > called for each device which has MSI/MSI-X enabled, and will reuse
> >> > an existing ITS. )
> >>
> >> Am I right in understanding that all the PCIe devices in your system
> >> end-up aliasing to the same RequesterID? If so, that's a major issue.
> >> The ITS is designed so that each device exposes its *own* RID, and
> >> have its own Interrupt Translation Table (ITT).
> >>
> >> In your case, you seem to first discover the root port, which is not
> >> upstream of anything, so it doesn't alias with anything at that
> >> point. We allocate the corresponding ITT, and it's all fine. Until we
> >> start probing the rest, and ugly things happen.
> >>
> > Yes, your understanding is correct. I will dig into this a bit
> > further to see what is wrong then send an update. I suspect my DTS
> > msi mapping.
>
> Right. That would explain a lot of what you're seeing. In general, and unless
> you have some funky remapping going on, you're better off having a very
> straightforward msi-map property in your RC node (such as example
> #1 in Documentation/devicetree/bindings/pci/pci-msi.txt).
The problem was that I had an msi-map-mask specified such that all
requester IDs were seen as zero. Now fixed that and checked that the
requester ID for each device is being correctly provided by HW to the GIC,
and all is now working correctly with without any patches required.
Thanks for your help.
Alan
^ permalink raw reply
* [PATCH v2] iio: adc: at91: add suspend and resume callback
From: Ludovic Desroches @ 2016-11-03 14:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478078508-24541-1-git-send-email-wenyou.yang@atmel.com>
On Wed, Nov 02, 2016 at 05:21:48PM +0800, Wenyou Yang wrote:
> Add suspend/resume callback, support the pinctrl sleep state when
> the system suspend as well.
>
> Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Thanks
> ---
>
> Changes in v2:
> - Use CONFIG_PM_SLEEP.
> - Use SIMPLE_DEV_PM_OPS macro.
>
> drivers/iio/adc/at91_adc.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index bbdac07..34b928c 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -30,6 +30,7 @@
> #include <linux/iio/trigger.h>
> #include <linux/iio/trigger_consumer.h>
> #include <linux/iio/triggered_buffer.h>
> +#include <linux/pinctrl/consumer.h>
>
> /* Registers */
> #define AT91_ADC_CR 0x00 /* Control Register */
> @@ -1347,6 +1348,32 @@ static int at91_adc_remove(struct platform_device *pdev)
> return 0;
> }
>
> +#ifdef CONFIG_PM_SLEEP
> +static int at91_adc_suspend(struct device *dev)
> +{
> + struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev));
> + struct at91_adc_state *st = iio_priv(idev);
> +
> + pinctrl_pm_select_sleep_state(dev);
> + clk_disable_unprepare(st->clk);
> +
> + return 0;
> +}
> +
> +static int at91_adc_resume(struct device *dev)
> +{
> + struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev));
> + struct at91_adc_state *st = iio_priv(idev);
> +
> + clk_prepare_enable(st->clk);
> + pinctrl_pm_select_default_state(dev);
> +
> + return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
> +
> static struct at91_adc_caps at91sam9260_caps = {
> .calc_startup_ticks = calc_startup_ticks_9260,
> .num_channels = 4,
> @@ -1441,6 +1468,7 @@ static struct platform_driver at91_adc_driver = {
> .driver = {
> .name = DRIVER_NAME,
> .of_match_table = of_match_ptr(at91_adc_dt_ids),
> + .pm = &at91_adc_pm_ops,
> },
> };
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH] arm64: errata: Check for --fix-cortex-a53-843419 and --fix-cortex-a53
From: Will Deacon @ 2016-11-03 14:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2d72cbbb-df03-267c-53b0-e3083a746175@gmail.com>
On Wed, Nov 02, 2016 at 02:57:26PM -0700, Florian Fainelli wrote:
> On 11/02/2016 02:41 PM, Markus Mayer wrote:
> > On 2 November 2016 at 14:27, Will Deacon <will.deacon@arm.com> wrote:
> >> On Wed, Nov 02, 2016 at 02:07:17PM -0700, Markus Mayer wrote:
> >>> The question I am asking is: What do we have to lose by supporting both options?
> >>
> >> We end up passing "--fix-cortex-a53" to the linker, without knowing what it
> >> might do in the future.
> >
> > It seems highly unlikely that such a generic option would be added in
> > the future, both, because the precedent has been set for topic
> > specific options, and because they know it has been used in the past,
> > so they wouldn't add a previously used option to do something
> > completely different. (And if they really did, then that would be a
> > huge binutils bug.)
> >
> > So, we have a trade-off between a real world problem that does
> > currently exist and avoiding a theoretical issue that may never
> > materialize.
>
> Agreed, also the way Markus' patch is designed makes it such that we
> first try the full and current option name, and if not supported, try
> the second (and earlier, now obsolete) option name, so I really don't
> see a lot of room for things to go wrong here...
It's not beyond the realms of possibility that ld will grow a
"fix-cortex-a53" option in the future, that enables all of the a53
workarounds. Since ld is the linker supported by the kernel and gold isn't,
I don't want to pass this option down.
If you can't change toolchain and you want this worked around, why can't you
either build gold with it enabled by default, or pass the extra flag on the
command line to the kernel build system?
Will
^ permalink raw reply
* [PATCH v14 14/16] vfio/type1: Check doorbell safety
From: Auger Eric @ 2016-11-03 14:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <HE1PR04MB1321EAD1CE91D2B6FC04BB55FFA30@HE1PR04MB1321.eurprd04.prod.outlook.com>
Hi Diana,
On 03/11/2016 14:45, Diana Madalina Craciun wrote:
> Hi Eric,
>
> On 10/12/2016 04:23 PM, Eric Auger wrote:
>> On x86 IRQ remapping is abstracted by the IOMMU. On ARM this is abstracted
>> by the msi controller.
>>
>> Since we currently have no way to detect whether the MSI controller is
>> upstream or downstream to the IOMMU we rely on the MSI doorbell information
>> registered by the interrupt controllers. In case at least one doorbell
>> does not implement proper isolation, we state the assignment is unsafe
>> with regard to interrupts. This is a coarse assessment but should allow to
>> wait for a better system description.
>>
>> At this point ARM sMMU still advertises IOMMU_CAP_INTR_REMAP. This is
>> removed in next patch.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v13 -> v15:
>> - check vfio_msi_resv before checking whether msi doorbell is safe
>>
>> v9 -> v10:
>> - coarse safety assessment based on MSI doorbell info
>>
>> v3 -> v4:
>> - rename vfio_msi_parent_irq_remapping_capable into vfio_safe_irq_domain
>> and irq_remapping into safe_irq_domains
>>
>> v2 -> v3:
>> - protect vfio_msi_parent_irq_remapping_capable with
>> CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> ---
>> drivers/vfio/vfio_iommu_type1.c | 30 +++++++++++++++++++++++++++++-
>> 1 file changed, 29 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
>> index e0c97ef..c18ba9d 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -442,6 +442,29 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
>> }
>>
>> /**
>> + * vfio_msi_resv - Return whether any VFIO iommu domain requires
>> + * MSI mapping
>> + *
>> + * @iommu: vfio iommu handle
>> + *
>> + * Return: true of MSI mapping is needed, false otherwise
>> + */
>> +static bool vfio_msi_resv(struct vfio_iommu *iommu)
>> +{
>> + struct iommu_domain_msi_resv msi_resv;
>> + struct vfio_domain *d;
>> + int ret;
>> +
>> + list_for_each_entry(d, &iommu->domain_list, next) {
>> + ret = iommu_domain_get_attr(d->domain, DOMAIN_ATTR_MSI_RESV,
>> + &msi_resv);
>> + if (!ret)
>> + return true;
>> + }
>> + return false;
>> +}
>> +
>> +/**
>> * vfio_set_msi_aperture - Sets the msi aperture on all domains
>> * requesting MSI mapping
>> *
>> @@ -945,8 +968,13 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
>> INIT_LIST_HEAD(&domain->group_list);
>> list_add(&group->next, &domain->group_list);
>>
>> + /*
>> + * to advertise safe interrupts either the IOMMU or the MSI controllers
>> + * must support IRQ remapping (aka. interrupt translation)
>> + */
>> if (!allow_unsafe_interrupts &&
>> - !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) {
>> + (!iommu_capable(bus, IOMMU_CAP_INTR_REMAP) &&
>> + !(vfio_msi_resv(iommu) && iommu_msi_doorbell_safe()))) {
>> pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
>> __func__);
>> ret = -EPERM;
>
> I understand from the other discussions that you will respin these
> series, but anyway I have tested this version with GICV3 + ITS and it
> stops here. As I have a GICv3 I am not supposed to enable allow unsafe
> interrupts. What I see is that vfio_msi_resv returns false just because
> the iommu->domain_list list is empty. The newly created domain is
> actually added to the domain_list at the end of this function, so it
> seems normal for the list to be empty at this point.
Thanks for reporting the issue. You are fully right. I must have missed
that test. I should just check the current iommu_domain attribute I think.
waiting for a fix, please probe the vfio_iommu_type1 module with
allow_unsafe_interrupts=1
Thanks
Eric
>
> Thanks,
>
> Diana
>
>
^ permalink raw reply
* [PATCHv2] PCI: QDF2432 32 bit config space accessors
From: Bjorn Helgaas @ 2016-11-03 14:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3fd26a0d-a5c2-c385-866e-b957dffb7dda@codeaurora.org>
On Wed, Nov 02, 2016 at 12:36:16PM -0400, Sinan Kaya wrote:
> Hi Bjorn,
>
> On 11/2/2016 12:08 PM, Bjorn Helgaas wrote:
> > On Tue, Nov 01, 2016 at 07:06:31AM -0600, cov at codeaurora.org wrote:
> >> Hi Bjorn,
> >>
> >> On 2016-10-31 15:48, Bjorn Helgaas wrote:
> >>> On Wed, Sep 21, 2016 at 06:38:05PM -0400, Christopher Covington wrote:
> >>>> The Qualcomm Technologies QDF2432 SoC does not support accesses
> >>>> smaller
> >>>> than 32 bits to the PCI configuration space. Register the appropriate
> >>>> quirk.
> >>>>
> >>>> Signed-off-by: Christopher Covington <cov@codeaurora.org>
> >>>
> >>> Hi Christopher,
> >>>
> >>> Can you rebase this against v4.9-rc1? It no longer applies to my tree.
> >>
> >> I apologize for not being clearer. This patch depends on:
> >>
> >> PCI/ACPI: Extend pci_mcfg_lookup() responsibilities
> >> PCI/ACPI: Check platform-specific ECAM quirks
> >>
> >> These patches from Tomasz Nowicki were previously in your pci/ecam-v6
> >> branch, but that seems to have come and gone. How would you like to
> >> proceed?
> >
> > Oh yes, that's right, I forgot that connection. I'm afraid I kind of
> > dropped the ball on that thread, so I went back and read through it
> > again.
> >
> > I *think* the current state is:
> >
> > - I'm OK with the first two patches that add the quirk
> > infrastructure.
> >
> > - My issue with the last three patches that add ThunderX quirks is
> > that there's no generic description of the ECAM address space.
> >
> > So if I understand correctly, your Qualcomm patch depends only on the
> > first two patches.
> >
> > Then the question is how the Qualcomm ECAM address space is described.
> > Your quirk overrides the default pci_generic_ecam_ops with the
> > &pci_32b_ops, but it doesn't touch the address space part, so I assume
> > the bus ranges and corresponding address space in your MCFG is
> > correct. So far, so good.
>
> Qualcomm ECAM space includes both the root port and the endpoint address
> space with a single contiguous 256 MB address space described in MCFG table.
> There is no need to describe additional resources like PNP0C02.
This is the crucial point I have failed to communicate clearly: the
PNP0C02 resource is *always* required, even if the MCFG is correct.
The reason is that MCFG is a PCI-specific table, and it should be
possible to boot a kernel with no PCI support. That kernel will not
look at the MCFG. The PCI hardware will still be present and will
still consume the ECAM space, so the OS must be able to discover that
the ECAM space is not available for other devices.
The usual way to for the OS to discover that would be via the _CRS of
a PNP0A03 or PNP0A08 host bridge device. _CRS is what I mean by a
"generic" way to describe this address space, because the ACPI core
can interpret _CRS for all ACPI devices, even if the kernel doesn't
contain drivers for all of those devices.
It turns out that we can't use the _CRS of host bridges because of the
Producer/Consumer bit screwup [1]. So the fallback is to include the
ECAM space in the _CRS of a PNP0C02 device. This is what the PCI
Firmware spec r3.0, Table 4-2, footnote 2 is talking about.
Bjorn
[1] The original ACPI spec intent was that Consumer resources would be
space like ECAM that is consumed directly by the bridge, and Producer
resources would be the windows forwarded down to PCI. But BIOSes
didn't use the Producer/Consumer bit consistently, so we have to
assume that all resources in host bridge _CRS are windows, which
leaves us no way to describe the Consumer resources.
^ permalink raw reply
* [PATCH 0/3] fix ohci phy name
From: Axel Haslam @ 2016-11-03 13:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d72af1ff-52f1-09ea-ee22-110c163d52f8@ti.com>
On Thu, Nov 3, 2016 at 1:00 PM, Sekhar Nori <nsekhar@ti.com> wrote:
> On Thursday 03 November 2016 01:54 PM, Axel Haslam wrote:
>> Hi Sekhar, David,
>>
>> It might make sense to have this patch series,
>> squashed into a single patch, would you agree,
>> or do you prefer it as is: one-per-subsystem?
>
> Patches in the current form are okay. Some coordination is required in
> getting them merged though. I am happy to take the driver patches
> through ARM-SoC with ack from respective maintainers.
>
> I will need to carry the platform patch through my tree because it
> conflicts with other changes I have already queued.
>
> That said, I am unable to review 3/3 since I am unable to find its baseline.
>
ok, ill send v2 fixing Davids comments on the commit messages
and referencing the missing patch that is queued on usb-next.
-Axel
> Thanks,
> Sekhar
^ permalink raw reply
* [crypto] [marvell-cesa] Possible regression after Linux 4.7
From: Romain Perier @ 2016-11-03 13:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58174e5d.233ac20a.a4335.5656@mx.google.com>
Hello,
Le 31/10/2016 ? 14:59, radioconfusion at gmail.com a ?crit :
> Do you have any improvement for the issue?
> Please let me know if you need any help to resolve it.
>
> Best Regards,
> Jussi
>
Sorry for the delay.
Could you try to revert locally commit
2786cee8e50bb4b4303dc22665f391b72318fa84 (crypto: marvell - Move SRAM
I/O operations to step functions) ?
It seems to fix most of the issues I had with curl.
I will continue to investigate, that's just to confirm if it fixes the
issues for you.
Thanks,
Romain
--
Romain Perier, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH V3 6/6] bus: Add support for Tegra Generic Memory Interface
From: Jon Hunter @ 2016-11-03 13:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CALw8SCVu+-h_yhOa7uDuyFBPVvhwjD64S+-MDeYN8EZsGHpXyw@mail.gmail.com>
On 03/11/16 13:08, Mirza Krak wrote:
> 2016-11-03 11:51 GMT+01:00 Jon Hunter <jonathanh@nvidia.com>:
>>
>> On 27/10/16 15:01, Mirza Krak wrote:
>>>
>>> From: Mirza Krak <mirza.krak@gmail.com>
>>>
>>> The Generic Memory Interface bus can be used to connect high-speed
>>> devices such as NOR flash, FPGAs, DSPs...
>>>
>>> Signed-off-by: Mirza Krak <mirza.krak@gmail.com>
>>> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
>>> Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board
>>> ---
>>>
>>> Changes in v2:
>>> - Fixed some checkpatch errors
>>> - Re-ordered probe to get rid of local variables
>>> - Moved of_platform_default_populate call to the end of probe
>>> - Use the timing and configuration properties from the child device
>>> - Added warning if more then 1 child device exist
>>>
>>> Changes in v3:
>>> - added helper function to disable the controller which is used in remove
>>> and
>>> on error.
>>> - Added logic to parse CS# from "ranges" property with fallback to "reg"
>>> property
>>>
>>> drivers/bus/Kconfig | 8 ++
>>> drivers/bus/Makefile | 1 +
>>> drivers/bus/tegra-gmi.c | 267
>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 276 insertions(+)
>>> create mode 100644 drivers/bus/tegra-gmi.c
>>>
>>> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
>>> index 4ed7d26..2e75a7f 100644
>>> --- a/drivers/bus/Kconfig
>>> +++ b/drivers/bus/Kconfig
>>> @@ -141,6 +141,14 @@ config TEGRA_ACONNECT
>>> Driver for the Tegra ACONNECT bus which is used to interface
>>> with
>>> the devices inside the Audio Processing Engine (APE) for
>>> Tegra210.
>>>
>>> +config TEGRA_GMI
>>> + tristate "Tegra Generic Memory Interface bus driver"
>>> + depends on ARCH_TEGRA
>>> + help
>>> + Driver for the Tegra Generic Memory Interface bus which can be
>>> used
>>> + to attach devices such as NOR, UART, FPGA and more.
>>> +
>>> +
>>
>>
>> Nit-pick ... only one additional line above is needed to be consistent with
>> the rest of the file.
>
> Will fix that.
>
>>
>>
>>> config UNIPHIER_SYSTEM_BUS
>>> tristate "UniPhier System Bus driver"
>>> depends on ARCH_UNIPHIER && OF
>>> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
>>> index ac84cc4..34e2bab 100644
>>> --- a/drivers/bus/Makefile
>>> +++ b/drivers/bus/Makefile
>>> @@ -18,5 +18,6 @@ obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
>>> obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
>>> obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
>>> obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
>>> +obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o
>>> obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
>>> obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
>>> diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c
>>> new file mode 100644
>>> index 0000000..dd9623e
>>> --- /dev/null
>>> +++ b/drivers/bus/tegra-gmi.c
>>> @@ -0,0 +1,267 @@
>>> +/*
>>> + * Driver for NVIDIA Generic Memory Interface
>>> + *
>>> + * Copyright (C) 2016 Host Mobility AB. All rights reserved.
>>> + *
>>> + * This file is licensed under the terms of the GNU General Public
>>> + * License version 2. This program is licensed "as is" without any
>>> + * warranty of any kind, whether express or implied.
>>> + */
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/io.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/reset.h>
>>> +
>>> +#define TEGRA_GMI_CONFIG 0x00
>>> +#define TEGRA_GMI_CONFIG_GO BIT(31)
>>> +#define TEGRA_GMI_BUS_WIDTH_32BIT BIT(30)
>>> +#define TEGRA_GMI_MUX_MODE BIT(28)
>>> +#define TEGRA_GMI_RDY_BEFORE_DATA BIT(24)
>>> +#define TEGRA_GMI_RDY_ACTIVE_HIGH BIT(23)
>>> +#define TEGRA_GMI_ADV_ACTIVE_HIGH BIT(22)
>>> +#define TEGRA_GMI_OE_ACTIVE_HIGH BIT(21)
>>> +#define TEGRA_GMI_CS_ACTIVE_HIGH BIT(20)
>>> +#define TEGRA_GMI_CS_SELECT(x) ((x & 0x7) << 4)
>>> +
>>> +#define TEGRA_GMI_TIMING0 0x10
>>> +#define TEGRA_GMI_MUXED_WIDTH(x) ((x & 0xf) << 12)
>>> +#define TEGRA_GMI_HOLD_WIDTH(x) ((x & 0xf) << 8)
>>> +#define TEGRA_GMI_ADV_WIDTH(x) ((x & 0xf) << 4)
>>> +#define TEGRA_GMI_CE_WIDTH(x) (x & 0xf)
>>> +
>>> +#define TEGRA_GMI_TIMING1 0x14
>>> +#define TEGRA_GMI_WE_WIDTH(x) ((x & 0xff) << 16)
>>> +#define TEGRA_GMI_OE_WIDTH(x) ((x & 0xff) << 8)
>>> +#define TEGRA_GMI_WAIT_WIDTH(x) (x & 0xff)
>>> +
>>> +struct tegra_gmi_priv {
>>> + void __iomem *base;
>>> + struct reset_control *rst;
>>> + struct clk *clk;
>>> +
>>> + u32 snor_config;
>>> + u32 snor_timing0;
>>> + u32 snor_timing1;
>>> +};
>>> +
>>> +static void tegra_gmi_disable(struct tegra_gmi_priv *priv)
>>> +{
>>> + u32 config;
>>> +
>>> + /* stop GMI operation */
>>> + config = readl(priv->base + TEGRA_GMI_CONFIG);
>>> + config &= ~TEGRA_GMI_CONFIG_GO;
>>> + writel(config, priv->base + TEGRA_GMI_CONFIG);
>>> +
>>> + reset_control_assert(priv->rst);
>>> + clk_disable_unprepare(priv->clk);
>>> +}
>>> +
>>> +static void tegra_gmi_init(struct device *dev, struct tegra_gmi_priv
>>> *priv)
>>> +{
>>> + writel(priv->snor_timing0, priv->base + TEGRA_GMI_TIMING0);
>>> + writel(priv->snor_timing1, priv->base + TEGRA_GMI_TIMING1);
>>> +
>>> + priv->snor_config |= TEGRA_GMI_CONFIG_GO;
>>> + writel(priv->snor_config, priv->base + TEGRA_GMI_CONFIG);
>>> +}
>>> +
>>> +static int tegra_gmi_parse_dt(struct device *dev, struct tegra_gmi_priv
>>> *priv)
>>> +{
>>> + struct device_node *child =
>>> of_get_next_available_child(dev->of_node,
>>> + NULL);
>>> + u32 property, ranges[4];
>>> + int ret;
>>> +
>>> + if (!child) {
>>> + dev_warn(dev, "no child nodes found\n");
>>> + return 0;
>>
>>
>> Don't we want to return an error here? Otherwise, we will call
>> tegra_gmi_init() with an invalid configuration.
>
> True, we probably want that. My thought was that we might accept a
> tegra-gmi node without any child nodes and just print a warning. But
> since it is the child node that holds the bus configuration it makes
> sense to fail probe due to no child nodes.
I was wondering that too, but given that we then program and enable the
GMI I think it is best to just fail for now.
>>
>>
>>> + }
>>> +
>>> + /*
>>> + * We currently only support one child device due to lack of
>>> + * chip-select address decoding. Which means that we only have one
>>> + * chip-select line from the GMI controller.
>>> + */
>>> + if (of_get_child_count(dev->of_node) > 1)
>>> + dev_warn(dev, "only one child device is supported.");
>>> +
>>> + if (of_property_read_bool(child, "nvidia,snor-data-width-32bit"))
>>> + priv->snor_config |= TEGRA_GMI_BUS_WIDTH_32BIT;
>>> +
>>> + if (of_property_read_bool(child, "nvidia,snor-mux-mode"))
>>> + priv->snor_config |= TEGRA_GMI_MUX_MODE;
>>> +
>>> + if (of_property_read_bool(child,
>>> "nvidia,snor-rdy-active-before-data"))
>>> + priv->snor_config |= TEGRA_GMI_RDY_BEFORE_DATA;
>>> +
>>> + if (of_property_read_bool(child, "nvidia,snor-rdy-inv"))
>>> + priv->snor_config |= TEGRA_GMI_RDY_ACTIVE_HIGH;
>>> +
>>> + if (of_property_read_bool(child, "nvidia,snor-adv-inv"))
>>> + priv->snor_config |= TEGRA_GMI_ADV_ACTIVE_HIGH;
>>> +
>>> + if (of_property_read_bool(child, "nvidia,snor-oe-inv"))
>>> + priv->snor_config |= TEGRA_GMI_OE_ACTIVE_HIGH;
>>> +
>>> + if (of_property_read_bool(child, "nvidia,snor-cs-inv"))
>>> + priv->snor_config |= TEGRA_GMI_CS_ACTIVE_HIGH;
>>> +
>>> + /* Decode the CS# */
>>> + ret = of_property_read_u32_array(child, "ranges", ranges, 4);
>>> + if (ret < 0) {
>>> + /* Invalid binding */
>>> + if (ret == -EOVERFLOW) {
>>> + dev_err(dev, "invalid ranges length\n");
>>> + goto error_cs_decode;
>>> + }
>>> +
>>> + /*
>>> + * If we reach here it means that the child node has an
>>> empty
>>> + * ranges or it does not exist at all. Attempt to decode
>>> the
>>> + * CS# from the reg property instead.
>>> + */
>>> + ret = of_property_read_u32(child, "reg", &property);
>>> + if (ret < 0) {
>>> + dev_err(dev, "no reg property found\n");
>>> + goto error_cs_decode;
>>> + }
>>> + } else {
>>> + property = ranges[1];
>>> + }
>>> +
>>> + priv->snor_config |= TEGRA_GMI_CS_SELECT(property);
>>
>>
>> Should we make sure the CS is a valid value before setting?
>
> The TEGRA_GMI_CS_SELECT(x) macro will truncate any erroneous CS value.
> But yeah we could do a sanity check instead and return an error if it
> is invalid.
>
>>
>>
>>> +
>>> + /* The default values that are provided below are reset values */
>>> + if (!of_property_read_u32(child, "nvidia,snor-muxed-width",
>>> &property))
>>> + priv->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(property);
>>> + else
>>> + priv->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(1);
>>> +
>>> + if (!of_property_read_u32(child, "nvidia,snor-hold-width",
>>> &property))
>>> + priv->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(property);
>>> + else
>>> + priv->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(1);
>>> +
>>> + if (!of_property_read_u32(child, "nvidia,snor-adv-width",
>>> &property))
>>> + priv->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(property);
>>> + else
>>> + priv->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(1);
>>> +
>>> + if (!of_property_read_u32(child, "nvidia,snor-ce-width",
>>> &property))
>>> + priv->snor_timing0 |= TEGRA_GMI_CE_WIDTH(property);
>>> + else
>>> + priv->snor_timing0 |= TEGRA_GMI_CE_WIDTH(4);
>>> +
>>> + if (!of_property_read_u32(child, "nvidia,snor-we-width",
>>> &property))
>>> + priv->snor_timing1 |= TEGRA_GMI_WE_WIDTH(property);
>>> + else
>>> + priv->snor_timing1 |= TEGRA_GMI_WE_WIDTH(1);
>>> +
>>> + if (!of_property_read_u32(child, "nvidia,snor-oe-width",
>>> &property))
>>> + priv->snor_timing1 |= TEGRA_GMI_OE_WIDTH(property);
>>> + else
>>> + priv->snor_timing1 |= TEGRA_GMI_OE_WIDTH(1);
>>> +
>>> + if (!of_property_read_u32(child, "nvidia,snor-wait-width",
>>> &property))
>>> + priv->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(property);
>>> + else
>>> + priv->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(3);
>>> +
>>> +error_cs_decode:
>>> + if (ret < 0)
>>> + dev_err(dev, "failed to decode chip-select number\n");
>>
>>
>> Nit do we need another error message here? Can we add the "failed to decode
>> CS" part the earlier message?
>
> Does it make sense to drop the two earlier messages instead and keep this one?
I think it is nice to have specific errors so we know where it failed.
You could just drop the above and when you add the test for making sure
the CS is valid add another error message for that. Not a big deal
either way. So I will leave to you to decide.
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [PATCH V3 2/6] clk: tegra: add TEGRA30_CLK_NOR to init table
From: Jon Hunter @ 2016-11-03 13:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477576872-2665-3-git-send-email-mirza.krak@gmail.com>
On 27/10/16 15:01, Mirza Krak wrote:
> From: Mirza Krak <mirza.krak@gmail.com>
>
> Add TEGRA30_CLK_NOR to init table and set default rate to 127 MHz which
> is max rate.
>
> The maximum rate value of 127 MHz is pulled from the downstream L4T
> kernel.
>
> Signed-off-by: Mirza Krak <mirza.krak@gmail.com>
> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
> Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Cheers
Jon
--
nvpublic
^ 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