* [PATCH 1/2] Added dts defintion for Lenovo ix4-300d nas
From: benoitm974 @ 2014-07-23 12:07 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: benoitm974 <yahoo@perenite.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts | 267 +++++++++++++++++++++++++
2 files changed, 268 insertions(+)
create mode 100644 arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index adb5ed9..f759dd2 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -438,6 +438,7 @@ dtb-$(CONFIG_MACH_ARMADA_XP) += \
armada-xp-db.dtb \
armada-xp-gp.dtb \
armada-xp-netgear-rn2120.dtb \
+ armada-xp-lenovo-ix4300d.dtb \
armada-xp-matrix.dtb \
armada-xp-openblocks-ax3-4.dtb
dtb-$(CONFIG_MACH_DOVE) += dove-cm-a510.dtb \
diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts
new file mode 100644
index 0000000..e04e7a6
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts
@@ -0,0 +1,267 @@
+/*
+ * Device Tree file for LENOVO IX4-300d
+ *
+ * Copyright (C) 2014, Benoit Masson <yahoo@perenite.com>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "armada-xp-mv78230.dtsi"
+
+/ {
+ model = "LENOVO IX4-300d";
+ compatible = "lenovo,ix4-300d", "marvell,armadaxp-mv78230", "marvell,armadaxp", "marvell,armada-370-xp";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x00000000 0 0x20000000>; /* 512MB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+
+ pcie-controller {
+ status = "okay";
+
+ pcie at 1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+ pcie at 5,0 {
+ /* Port 1, Lane 0 */
+ status = "okay";
+ };
+
+ };
+
+ internal-regs {
+ pinctrl {
+ poweroff: poweroff {
+ marvell,pins = "mpp24";
+ marvell,function = "gpio";
+ };
+
+ power_button_pin: power-button-pin {
+ marvell,pins = "mpp44";
+ marvell,function = "gpio";
+ };
+
+ reset_button_pin: reset-button-pin {
+ marvell,pins = "mpp45";
+ marvell,function = "gpio";
+ };
+ select_button_pin: select-button-pin {
+ marvell,pins = "mpp41";
+ marvell,function = "gpio";
+ };
+
+ scroll_button_pin: scroll-button-pin {
+ marvell,pins = "mpp42";
+ marvell,function = "gpio";
+ };
+ hdd_led_pin: hdd-led-pin {
+ marvell,pins = "mpp26";
+ marvell,function = "gpio";
+ };
+ };
+
+ serial at 12000 {
+ clocks = <&coreclk 0>;
+ status = "okay";
+ };
+
+ mdio {
+ phy0: ethernet-phy at 0 { /* Marvell 88E1318 */
+ reg = <0>;
+ };
+
+ phy1: ethernet-phy at 1 { /* Marvell 88E1318 */
+ reg = <1>;
+ };
+ };
+
+ ethernet at 70000 {
+ status = "okay";
+ phy = <&phy0>;
+ phy-mode = "rgmii-id";
+ };
+
+ ethernet at 74000 {
+ status = "okay";
+ phy = <&phy1>;
+ phy-mode = "rgmii-id";
+ };
+
+ usb at 50000 {
+ status = "okay";
+ };
+
+ usb at 51000 {
+ status = "okay";
+ };
+
+ i2c at 11000 {
+ compatible = "marvell,mv78230-a0-i2c", "marvell,mv64xxx-i2c";
+ clock-frequency = <400000>;
+ status = "okay";
+
+ adt7473 at 2e {
+ compatible = "adt7473";
+ reg = <0x2e>;
+ };
+
+ pcf8563 at 51 {
+ compatible = "pcf8563";
+ reg = <0x51>;
+ };
+
+ };
+ nand at d0000 {
+ status = "okay";
+ num-cs = <1>;
+ marvell,nand-keep-config;
+ marvell,nand-enable-arbiter;
+ nand-on-flash-bbt;
+
+ partition at 0 {
+ label = "u-boot";
+ reg = <0x0000000 0xe0000>;
+ read-only;
+ };
+
+ partition at e0000 {
+ label = "u-boot-env";
+ reg = <0xe0000 0x20000>;
+ read-only;
+ };
+
+ partition at 100000 {
+ label = "u-boot-env2";
+ reg = <0x100000 0x20000>;
+ read-only;
+ };
+
+ partition at 120000 {
+ label = "zImage";
+ reg = <0x120000 0x400000>;
+ };
+
+ partition at 520000 {
+ label = "initrd";
+ reg = <0x520000 0x400000>;
+ };
+ partition at xE00000 {
+ label = "boot";
+ reg = <0xE00000 0x3F200000>;
+ };
+ partition at flash {
+ label = "flash";
+ reg = <0x0 0x40000000>;
+ };
+ };
+
+ };
+ };
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&power_button_pin &reset_button_pin &select_button_pin &scroll_button_pin>;
+ pinctrl-names = "default";
+
+ power-button {
+ label = "Power Button";
+ linux,code = <KEY_POWER>;
+ gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+ };
+ reset-button {
+ label = "Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+ };
+ select-button {
+ label = "Select Button";
+ linux,code = <BTN_SELECT>;
+ gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+ };
+ scroll-button {
+ label = "Scroll Button";
+ linux,code = <KEY_SCROLLDOWN>;
+ gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ spi3 {
+ compatible = "spi-gpio";
+ status = "okay";
+ gpio-sck = <&gpio0 25 0>;
+ gpio-mosi = <&gpio1 15 0>; /*gpio 47*/
+ cs-gpios = <&gpio0 27 0 >;
+ num-chipselects = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio2: gpio2 at 0 {
+ compatible = "fairchild,74hc595";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0>;
+ registers-number = <2>;
+ spi-max-frequency = <100000>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&hdd_led_pin>;
+ pinctrl-names = "default";
+
+ hdd-led {
+ label = "ix4300d:blue:hdd";
+ gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ power-led {
+ label = "ix4300d:power";
+ gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "timer"; /* init blinking while booting */
+ default-state = "on";
+ };
+
+ sysfail-led {
+ label = "ix4300d:sysfail:red";
+ gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ sys-led {
+ label = "ix4300d:sys:blue";
+ gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ hddfail-led {
+ label = "ix4300d:hddfail:red";
+ gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ };
+ /* warning: you need both eth1 & 0 to be initialize for poweroff to shutdown otherwise it reboots */
+ gpio-poweroff {
+ compatible = "gpio-poweroff";
+ pinctrl-0 = <&poweroff>;
+ pinctrl-names = "default";
+ gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+ };
+
+};
--
1.9.1
^ permalink raw reply related
* [PATCH V2 1/2] power: twl4030_charger: detect battery presence prior to enabling charger
From: Sebastian Reichel @ 2014-07-23 12:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723092420.GE22006@atomide.com>
On Wed, Jul 23, 2014 at 02:24:20AM -0700, Tony Lindgren wrote:
> * Nishanth Menon <nm@ti.com> [140528 14:48]:
> > TWL4030's Battery Charger seems to be designed for non-hotpluggable
> > batteries.
> >
> > If battery is not present in the system, BATSTS is always set with the
> > expectation that software will take actions to move to a required safe
> > state (could be power down or disable various charger paths).
> >
> > It does not seem possible even by manipulating the edge detection
> > of the event (using BCIEDR2 register) to have a consistent hotplug
> > handling. This seems to be the result of BATSTS interrupt generated
> > when the thermistor of the battery pack is disconnected from the
> > dedicated ADIN1 pin. Clearing the status just results in the status
> > being regenerated by the monitoring ADC(MADC) and disabling the
> > edges of event just makes hotplug no longer function. The only
> > other option is to disable the detection of the MADC by disabling
> > BCIMFEN4::BATSTSMCHGEN (battery presence detector) - but then, we can
> > never again detect battery reconnection.
> >
> > So, detect battery presence based on precharge(which is hardware
> > automatic state) or default main charger configuration at the time of
> > probe and enable charger logic only if battery was present.
> >
> > Reported-by: Russell King <linux@arm.linux.org.uk>
> > Tested-by: Tony Lindgren <tony@atomide.com>
> > Signed-off-by: Nishanth Menon <nm@ti.com>
>
> Dmitry, can we please get this first patch merged? This is needed
> on some omap3 platforms for DT based booting when no battery is
> present.
>
> Only the second patch in this series is still being discussed AFAIK.
applied to battery-2.6.git:
http://git.infradead.org/battery-2.6.git/commit/61a7784efd3c89ffb6242f29bcee170dd7f55e6b
-- Sebastian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140723/66e293c7/attachment.sig>
^ permalink raw reply
* [PATCH v2] cpufreq: tests: Providing cpufreq regression test
From: Rafael J. Wysocki @ 2014-07-23 11:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKohpok++gPcNk9-E4MsFdNBy8qL7oLYvatk1EvcW1OHwroZXQ@mail.gmail.com>
On Wednesday, July 23, 2014 02:19:54 PM Viresh Kumar wrote:
> On 23 July 2014 13:08, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > Do you want to say that we have enough tests and we don't need more ?
>
> No. We don't have any tests at all :)
>
> > I always thought that we shall have as much regression tests as
> > possible.
>
> Yeah, tests are welcomed but the question is where should they get added.
> Don't know if its common to add tests directly to kernel.
Yes, it is.
> And also if the test is really good, not discouraging your work.
>
> >> On 21 July 2014 12:32, Lukasz Majewski <l.majewski@samsung.com> wrote:
> >> > This commit adds first regression test "cpufreq_freq_test.sh" for
> >> > the cpufreq subsystem.
> >>
> >> That's not enough, Tell us why we should continue reading this mail..
> >
> > Hmm... If "regression" and "test" don't catch the attention of a
> > diligent maintainer, then I cannot do much more to encourage him to
> > read the whole e-mail :-)
>
> What I meant to say was, your subject and body must be good enough
> to answer most of the things. You don't have to tell much about the
> implementation but other things should be pretty clear from logs.
>
> Your current logs are quite short for something that's not a normal practice.
>
> > I can imagine that maintainers are very busy, therefore I've prepared
> > README file with detailed description of the script operation.
>
> Yeah, a README is welcomed and would be useful for users as well..
>
> >> I couldn't make out the purpose of this test and why we need it. How
> >> do we ensure that "cpufreq attributes exported by sysfs are exposing
> >> correct values"?
> >
> > First of all the cpufreq attributes are part of the subsystem API.
> > There are systems which actually depend on them, so we would be better
> > off to test if they work as intended.
> >
> > Secondly, the test takes those values and then with use of other
> > attribute enforce the value, which is then read via cat'ing
> > cpufreq_cur_freq. If any of the attributes is wrong then we will spot
> > the error immediately.
>
> Shouldn't you use userspace governor then instead of performance?
> And then we don't need the gzip stuff at all. We can just set it to the
> right freq and get current freq to see if it matches?
>
> And now that we are starting to get tests added into the kernel (will still
> wait to see what Rafael has to advice), we better think of the way these
> are going to get added. Probably a single script with parameters like
> what to test?
I've had a look at the Lukasz' patch in the first iteration and I'm going to
look at it again shortly.
At this point I can only say that it should be clear to the user of the
script what is tested, as well as what "success" and what "failure" mean.
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply
* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: Tuomas Tynkkynen @ 2014-07-23 11:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKohpomQthJ_XE-HhzW07Q4aVtxQVy97iaL0Vy6Q4Lhw22A=VA@mail.gmail.com>
On 23/07/14 07:44, Viresh Kumar wrote:
> On 21 July 2014 21:09, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
>
>> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
>> index 7364a53..df3c73e 100644
>> --- a/drivers/cpufreq/Kconfig.arm
>> +++ b/drivers/cpufreq/Kconfig.arm
>> @@ -244,6 +244,7 @@ config ARM_SPEAR_CPUFREQ
>> config ARM_TEGRA_CPUFREQ
>> bool "TEGRA CPUFreq support"
>> depends on ARCH_TEGRA
>> + depends on GENERIC_CPUFREQ_CPU0
>
> Wouldn't this also disturb the existing cpufreq driver for earlier
> tegra platforms? i.e. we don't need cpufreq-cpu0 for them
> atleast as of now.
>
>> default y
>> help
>> This adds the CPUFreq driver support for TEGRA SOCs.
>> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
>> index db6d9a2..3437d24 100644
>> --- a/drivers/cpufreq/Makefile
>> +++ b/drivers/cpufreq/Makefile
>> @@ -76,6 +76,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
>> obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
>> obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
>> obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
>> +obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra124-cpufreq.o
>
> Maybe, you can update the same line if you want.
Oh, right.
>
>> obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
>>
>> ##################################################################################
>> diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
>
>> +static struct cpufreq_frequency_table *freq_table;
>> +
>> +static struct device *cpu_dev;
>> +static struct clk *cpu_clk;
>> +static struct clk *pllp_clk;
>> +static struct clk *pllx_clk;
>> +static struct clk *dfll_clk;
>
> The routines in this file are going to be called just once at boot, right?
> In that case we are actually wasting some memory by creating globals.
> Probably just move all these in a struct and allocate it at runtime.
>
Sure.
[...]
>> +
>> + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
>> + if (ret)
>> + goto out_put_pllp_clk;
>
> Why do you need this? cpufreq-cpu0 also does it and this freq_table is
> just not getting used at all then.
>
Oops, yes I forgot to remove that part when making the conversion.
>> +
>> + pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
>> + if (IS_ERR(pdev)) {
>> + platform_driver_unregister(&tegra124_cpufreq_platdrv);
>> + return PTR_ERR(pdev);
>> + }
>
> Why create another unnecessary platform-device/driver here? If
> of_find_matching_node() passes and you really need to probe cpufreq-cpu0
> here, then just remove the other two calls and move probe's implementation
> here only.
>
The platform device is required for the deferred probe that can happen if the
DFLL driver hasn't initialized yet, and module_init() callbacks don't seem to
respect -EPROBE_DEFER.
[...]
--
nvpublic
^ permalink raw reply
* [PATCHv3 0/7] cpufreq support for Marvell Armada XP
From: Thomas Petazzoni @ 2014-07-23 11:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723113945.GB23220@titan.lakedaemon.net>
Dear Jason Cooper,
On Wed, 23 Jul 2014 07:39:45 -0400, Jason Cooper wrote:
> > What do you think?
>
> Let's wait and see what -rc1 looks like and take action based on that.
Sure. Thanks a lot for your summary. I agree with your proposal.
I'm working on respining the cpuidle series based on the discussion
with Daniel Lezcano and Arnd Bergmann. If all goes well, you can expect
a new version today.
Thanks,
Thomas
--
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply
* [PATCHv3 0/7] cpufreq support for Marvell Armada XP
From: Jason Cooper @ 2014-07-23 11:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723131930.46dcbc2e@free-electrons.com>
Thomas,
On Wed, Jul 23, 2014 at 01:19:30PM +0200, Thomas Petazzoni wrote:
> Viresh, Jason,
>
> So, what do we do with this patch series, which depends on the
> cpufreq-generic driver? Has there been any solution found for 3.17 ?
>
> Jason, in any case, I'd like the following patches to be merged for
> 3.17, regardless of what happens with the cpufreq driver:
>
> ARM: mvebu: ensure CPU clocks are enabled
> ARM: mvebu: extend PMSU code to support dynamic frequency scaling
> clk: mvebu: extend clk-cpu for dynamic frequency scaling
I just sent the pull for these three yesterday.
> One patch should be split:
>
> ARM: mvebu: update Armada XP DT for dynamic frequency scaling
>
> -> In this patch, the addition of clock-latency is related to the
> cpufreq generic DT binding, so I think we shouldn't merge that. But
> on the other hand, this patch also adds the new registers for the
> Armada XP CPU clock, which is used by "clk: mvebu: extend clk-cpu
> for dynamic frequency scaling".
This was a part of one of the previous DT pull requests and is already
in arm-soc.
> The patch:
>
> ARM: mvebu: allow enabling of cpufreq on Armada XP
>
> can be dropped, since ARCH_HAS_CPUFREQ has been removed.
Yup, did that when Paul raised the issue.
> The other patches are defconfig changes, which are meaningless without
> the cpufreq-generic driver.
Already pushed to arm-soc.
> Jason, what do you think about me sending a new version of the patch
> series, which will have two clearly separated set of patches:
>
> 1/ A first set of patches that can be applied regardless of what
> happens on the cpufreq driver side. Getting it merged will not
> bring cpufreq support, but it will add the foundations needed to
> support it.
>
> 2/ A second set of patches that use the cpufreq-generic driver, which
> might get applied of the cpufreq maintainers find a solution in
> time for 3.17. If not, then I'll re-adapt them for 3.18.
It sounds like the only patch in group 2 would be the DT change, which
has already been taken.
> What do you think?
Let's wait and see what -rc1 looks like and take action based on that.
thx,
Jason.
^ permalink raw reply
* [PATCHv3 0/7] cpufreq support for Marvell Armada XP
From: Thomas Petazzoni @ 2014-07-23 11:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1404920715-19834-1-git-send-email-thomas.petazzoni@free-electrons.com>
Viresh, Jason,
So, what do we do with this patch series, which depends on the
cpufreq-generic driver? Has there been any solution found for 3.17 ?
Jason, in any case, I'd like the following patches to be merged for
3.17, regardless of what happens with the cpufreq driver:
ARM: mvebu: ensure CPU clocks are enabled
ARM: mvebu: extend PMSU code to support dynamic frequency scaling
clk: mvebu: extend clk-cpu for dynamic frequency scaling
One patch should be split:
ARM: mvebu: update Armada XP DT for dynamic frequency scaling
-> In this patch, the addition of clock-latency is related to the
cpufreq generic DT binding, so I think we shouldn't merge that. But
on the other hand, this patch also adds the new registers for the
Armada XP CPU clock, which is used by "clk: mvebu: extend clk-cpu
for dynamic frequency scaling".
The patch:
ARM: mvebu: allow enabling of cpufreq on Armada XP
can be dropped, since ARCH_HAS_CPUFREQ has been removed.
The other patches are defconfig changes, which are meaningless without
the cpufreq-generic driver.
Jason, what do you think about me sending a new version of the patch
series, which will have two clearly separated set of patches:
1/ A first set of patches that can be applied regardless of what
happens on the cpufreq driver side. Getting it merged will not
bring cpufreq support, but it will add the foundations needed to
support it.
2/ A second set of patches that use the cpufreq-generic driver, which
might get applied of the cpufreq maintainers find a solution in
time for 3.17. If not, then I'll re-adapt them for 3.18.
What do you think?
Thomas
On Wed, 9 Jul 2014 17:45:08 +0200, Thomas Petazzoni wrote:
> Mike, Viresh, Rafael, Jason, Gregory, Andrew, Sebastian,
>
> Here is the third version of the patches adding cpufreq support for
> the Marvell Armada XP processor.
>
> Changes since v2
> ================
>
> - As suggested by Stephen Boyd, instead of using a new clock notifier
> that somewhat "hides" the dependency of the clk-cpu clock driver on
> the PMSU, use a direct call from the clk-cpu driver to the PMSU
> driver.
>
> - Add a comment that explains why the OPP are not removed on failure
> in the PMSU code initializing the cpufreq logic, in answer to the
> review from Ezequiel Garcia.
>
> Changes since v1
> ================
>
> - Rework the patch series to use the generalized cpufreq-cpu0
> (renamed cpufreq-generic) driver instead of having an Armada XP
> specific cpufreq driver. This was suggested by Viresh
> Kumar. Basically, it only involved adding a "clock-latency"
> property in the DT, and changing the PMSU code to register the two
> OPPs supported by each CPU, and registering the "cpufreq-generic"
> platform device instead of the "armadaxp-cpufreq" one.
>
> Jason, this patch series is based on 3.16-rc3, but it applies fine
> even with mvebu/fixes and mvebu/soc merged (which contain some PMSU
> changes), so I haven't based the patch series on those branches. To
> _work_, the code needs the new cpufreq-generic driver which is pending
> in Viresh Kumar's tree for 3.17, but there is no build dependency.
>
> Thanks,
>
> Thomas
>
> Thomas Petazzoni (7):
> ARM: mvebu: ensure CPU clocks are enabled
> ARM: mvebu: extend PMSU code to support dynamic frequency scaling
> clk: mvebu: extend clk-cpu for dynamic frequency scaling
> ARM: mvebu: update Armada XP DT for dynamic frequency scaling
> ARM: mvebu: allow enabling of cpufreq on Armada XP
> ARM: mvebu: update mvebu_v7_defconfig with cpufreq support
> ARM: configs: add cpufreq-generic in multi_v7_defconfig
>
> .../devicetree/bindings/clock/mvebu-cpu-clock.txt | 5 +-
> arch/arm/boot/dts/armada-xp-mv78230.dtsi | 2 +
> arch/arm/boot/dts/armada-xp-mv78260.dtsi | 2 +
> arch/arm/boot/dts/armada-xp-mv78460.dtsi | 4 +
> arch/arm/boot/dts/armada-xp.dtsi | 2 +-
> arch/arm/configs/multi_v7_defconfig | 1 +
> arch/arm/configs/mvebu_v7_defconfig | 2 +
> arch/arm/mach-mvebu/Kconfig | 1 +
> arch/arm/mach-mvebu/platsmp.c | 1 +
> arch/arm/mach-mvebu/pmsu.c | 162 +++++++++++++++++++++
> drivers/clk/mvebu/clk-cpu.c | 80 +++++++++-
> include/linux/mvebu-pmsu.h | 20 +++
> 12 files changed, 274 insertions(+), 8 deletions(-)
> create mode 100644 include/linux/mvebu-pmsu.h
>
--
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply
* [PATCHv4 3/5] common: dma-mapping: Introduce common remapping functions
From: Catalin Marinas @ 2014-07-23 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1406079308-5232-4-git-send-email-lauraa@codeaurora.org>
On Wed, Jul 23, 2014 at 02:35:06AM +0100, Laura Abbott wrote:
> +void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
> +{
> + struct vm_struct *area = find_vm_area(cpu_addr);
> +
> + if (!area || (area->flags & vm_flags) != vm_flags) {
> + WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
> + return;
> + }
> +
> + unmap_kernel_range((unsigned long)cpu_addr, size);
> + vunmap(cpu_addr);
> +}
One more thing - is unmap_kernel_range() needed here? vunmap() ends up
calling vunmap_page_range(), same as unmap_kernel_range(). I think one
difference is that in the vunmap case, TLB flushing is done lazily.
--
Catalin
^ permalink raw reply
* [PATCH v5 1/2] i2c: add DMA support for freescale i2c driver
From: Varka Bhadram @ 2014-07-23 11:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <b1778af62e7b42b39381fb2699b34eb1@BL2PR03MB338.namprd03.prod.outlook.com>
On 07/23/2014 04:41 PM, Yao Yuan wrote:
> Hi,
>
> Thanks for your review.
>
> Lothar Wa?mann wrote:
>> Yuan Yao wrote:
>>> Add dma support for i2c. This function depend on DMA driver.
>>> You can turn on it by write both the dmas and dma-name properties in dts node.
>>>
>>> Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
>>> ---
>>> drivers/i2c/busses/i2c-imx.c | 377
> [...]
>>> +
>>> +fail_rx:
>>> + dma_release_channel(dma->chan_rx);
>>> +fail_tx:
>>> + dma_release_channel(dma->chan_tx);
>>> +fail_al:
>>> + devm_kfree(dev, dma);
>>>
>> No need for this one (that's the whole point of using devm_kzalloc())!
>>
> When DMA request failed, I2C will switch to PIO mode. So if the failed reason is just like DMA channel request failed. At this time the DMA should free by devm_kfree(). Is it?
If probe failed the memory will be freed automatically because
we are using devm_kzalloc()...
If we use devm_kzalloc() ,no need to free manually on fail...
--
Regards,
Varka Bhadram.
^ permalink raw reply
* [PATCHv4 5/5] arm64: Add atomic pool for non-coherent and CMA allocations.
From: Arnd Bergmann @ 2014-07-23 11:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140722210352.GA10604@arm.com>
On Tuesday 22 July 2014 22:03:52 Catalin Marinas wrote:
> On Tue, Jul 22, 2014 at 07:06:44PM +0100, Arnd Bergmann wrote:
> > On Wednesday 02 July 2014, Laura Abbott wrote:
> > > + pgprot_t prot = __pgprot(PROT_NORMAL_NC);
> > > + unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT;
> > > + struct page *page;
> > > + void *addr;
> > > +
> > > +
> > > + if (dev_get_cma_area(NULL))
> > > + page = dma_alloc_from_contiguous(NULL, nr_pages,
> > > + get_order(atomic_pool_size));
> > > + else
> > > + page = alloc_pages(GFP_KERNEL, get_order(atomic_pool_size));
> > > +
> > > +
> > > + if (page) {
> > > + int ret;
> > > +
> > > + atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
> > > + if (!atomic_pool)
> > > + goto free_page;
> > > +
> > > + addr = dma_common_contiguous_remap(page, atomic_pool_size,
> > > + VM_USERMAP, prot, atomic_pool_init);
> > > +
> >
> > I just stumbled over this thread and noticed the code here: When you do
> > alloc_pages() above, you actually get pages that are already mapped into
> > the linear kernel mapping as cacheable pages. Your new
> > dma_common_contiguous_remap tries to map them as noncacheable. This
> > seems broken because it allows the CPU to treat both mappings as
> > cacheable, and that won't be coherent with device DMA.
>
> It does *not* allow the CPU to treat both as cacheable. It treats the
> non-cacheable mapping as non-cacheable (and the cacheable one as
> cacheable). The only requirements the ARM ARM makes in this situation
> (B2.9 point 5 in the ARMv8 ARM):
>
> - Before writing to a location not using the Write-Back attribute,
> software must invalidate, or clean, a location from the caches if any
> agent might have written to the location with the Write-Back
> attribute. This avoids the possibility of overwriting the location
> with stale data.
> - After writing to a location with the Write-Back attribute, software
> must clean the location from the caches, to make the write visible to
> external memory.
> - Before reading the location with a cacheable attribute, software must
> invalidate the location from the caches, to ensure that any value held
> in the caches reflects the last value made visible in external memory.
>
> So we as long as the CPU accesses such memory only via the non-cacheable
> mapping, the only requirement is to flush the cache so that there are no
> dirty lines that could be evicted.
Ok, thanks for the explanation.
> (if the mismatched attributes were for example Normal vs Device, the
> Device guarantees would be lost but in the cacheable vs non-cacheable
> it's not too bad; same for ARMv7).
Right, that's probabably what I misremembered.
> > > + if (!addr)
> > > + goto destroy_genpool;
> > > +
> > > + memset(addr, 0, atomic_pool_size);
> > > + __dma_flush_range(addr, addr + atomic_pool_size);
> >
> > It also seems weird to flush the cache on a virtual address of
> > an uncacheable mapping. Is that well-defined?
>
> Yes. According to D5.8.1 (Data and unified caches), "if cache
> maintenance is performed on a memory location, the effect of that cache
> maintenance is visible to all aliases of that physical memory location.
> These properties are consistent with implementing all caches that can
> handle data accesses as Physically-indexed, physically-tagged (PIPT)
> caches".
interesting.
> > In the CMA case, the
> > original mapping should already be uncached here, so you don't need
> > to flush it.
>
> I don't think it is non-cacheable already, at least not for arm64 (CMA
> can be used on coherent architectures as well).
Ok, I see it now.
Sorry for all the confusion on my part.
Arnd
^ permalink raw reply
* [PATCH v5 1/2] i2c: add DMA support for freescale i2c driver
From: Yao Yuan @ 2014-07-23 11:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723114834.411f6bb4@ipc1.ka-ro>
Hi,
Thanks for your review.
Lothar Wa?mann wrote:
> Yuan Yao wrote:
> > Add dma support for i2c. This function depend on DMA driver.
> > You can turn on it by write both the dmas and dma-name properties in dts node.
> >
> > Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
> > ---
> > drivers/i2c/busses/i2c-imx.c | 377
[...]
> > +
> > +fail_rx:
> > + dma_release_channel(dma->chan_rx);
> > +fail_tx:
> > + dma_release_channel(dma->chan_tx);
> > +fail_al:
> > + devm_kfree(dev, dma);
> >
> No need for this one (that's the whole point of using devm_kzalloc())!
>
When DMA request failed, I2C will switch to PIO mode. So if the failed reason is just like DMA channel request failed. At this time the DMA should free by devm_kfree(). Is it?
[...]
Thanks.
Yuan Yao
^ permalink raw reply
* DMA engine API issue (was: [PATCH/RFC 0/5] R-Car Gen2 DMAC hardware descriptor list support)
From: Laurent Pinchart @ 2014-07-23 11:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3361994.F0HgAeJkR9@avalon>
(Expanding the CC list)
On Wednesday 23 July 2014 12:28:47 Laurent Pinchart wrote:
> On Tuesday 22 July 2014 19:17:23 Kuninori Morimoto wrote:
> > Hi Laurent
> >
> > > The code has been tested by artificially lowering the maximum chunk size
> > > to 4096 bytes and running dmatest, which completed sucessfully.
> > > Morimoto- san, is there an easy way to test cyclic transfers with your
> > > audio driver ?
> >
> > Thank you for your offer.
> > I tested this patchset with audio DMAC (= cyclic transfer)
> > but, it doesn't work for me.
> >
> > First of all, this sound driver which is using cyclic transfer
> > was worked well in shdma-base driver.
> > I had sent audio DMA support plafrom side patches before.
> > But, of course I'm happy to update sound driver side.
> >
> > I will re-send my audio DMAC support patches after this email.
> >
> > My troubles are...
>
> [snip]
>
> > 2. cyclic transfer doesn't work
> >
> > I got attached error.
>
> [snip]
>
> I can reproduce that, but I have this error coming up before.
>
> [ 16.207027] BUG: sleeping function called from invalid context at
> kernel/locking/mutex.c:103 [ 16.215795] in_atomic(): 1, irqs_disabled():
> 128, pid: 1319, name: aplay [ 16.222636] CPU: 0 PID: 1319 Comm: aplay Not
> tainted 3.16.0-rc5-02821-g12a72a3 #2501 [ 16.230536] Backtrace:
> [ 16.233056] [<c00121e4>] (dump_backtrace) from [<c0012598>]
> (show_stack+0x18/0x1c) [ 16.240778] r6:ffffffff r5:c04aa7c0 r4:00000000
> r3:00000000
> [ 16.246593] [<c0012580>] (show_stack) from [<c032ea84>]
> (dump_stack+0x8c/0xc0) [ 16.253967] [<c032e9f8>] (dump_stack) from
> [<c0049e98>] (__might_sleep+0xcc/0x108) [ 16.261689] r4:e8dd2000
> r3:00000093
> [ 16.265357] [<c0049dcc>] (__might_sleep) from [<c0332134>]
> (mutex_lock+0x20/0x70) [ 16.272990] r5:00000000 r4:e900fe00
> [ 16.276657] [<c0332114>] (mutex_lock) from [<c01fa4dc>]
> (regmap_lock_mutex+0x10/0x14) [ 16.284644] r4:e900fe00 r3:00000000
> [ 16.288309] [<c01fa4cc>] (regmap_lock_mutex) from [<c01fb9dc>]
> (regmap_update_bits+0x2c/0x64) [ 16.297009] [<c01fb9b0>]
> (regmap_update_bits) from [<c01fba90>] (regmap_fields_write+0x38/0x44) [
> 16.305883] r7:e8d9d990 r6:00000004 r5:00000040 r4:f0368200
> [ 16.311701] [<c01fba58>] (regmap_fields_write) from [<bf0ec280>]
> (rsnd_write+0x30/0x4c [snd_soc_rcar]) [ 16.321195] r5:e93a4c00
> r4:e8d1f898
> [ 16.324866] [<bf0ec250>] (rsnd_write [snd_soc_rcar]) from [<bf0ec884>]
> (rsnd_src_set_convert_rate.isra.6+0xf8/0x144 [snd_soc_rcar]) [ 16.336940]
> [<bf0ec78c>] (rsnd_src_set_convert_rate.isra.6 [snd_soc_rcar]) from
> [<bf0ec8fc>] (rsnd_src_init_gen2+0x2c/0xc4 [snd_soc_rcar]) [ 16.349624]
> r6:00000004 r5:e8d9d810 r4:e8d1f898 r3:bf0ec8d0
> [ 16.355438] [<bf0ec8d0>] (rsnd_src_init_gen2 [snd_soc_rcar]) from
> [<bf0ea640>] (rsnd_soc_dai_trigger+0x1cc/0x22c [snd_soc_rcar]) [
> 16.367236] r5:e8d9d810 r4:e8d9d824
> [ 16.370916] [<bf0ea474>] (rsnd_soc_dai_trigger [snd_soc_rcar]) from
> [<bf0c51ec>] (soc_pcm_trigger+0xa8/0xf8 [snd_soc_core]) [ 16.382271]
> r10:00002000 r9:00002000 r8:e9290d00 r7:e8d9d700 r6:00000001 r5:e99fb500 [
> 16.390301] r4:e8ef3810
> [ 16.392910] [<bf0c5144>] (soc_pcm_trigger [snd_soc_core]) from
> [<bf094704>] (snd_pcm_do_start+0x34/0x38 [snd_pcm]) [ 16.403467]
> r8:bf09e050 r7:00000000 r6:00000003 r5:e99fb500 r4:bf09e050 r3:bf0c5144 [
> 16.411421] [<bf0946d0>] (snd_pcm_do_start [snd_pcm]) from [<bf0941f8>]
> (snd_pcm_action_single+0x40/0x80 [snd_pcm]) [ 16.422079] [<bf0941b8>]
> (snd_pcm_action_single [snd_pcm]) from [<bf09443c>]
> (snd_pcm_action+0xcc/0xd0 [snd_pcm]) [ 16.432547] r7:00000003
> r6:e99fb5c8 r5:bf09e4c0 r4:e99fb500
> [ 16.438366] [<bf094370>] (snd_pcm_action [snd_pcm]) from [<bf097098>]
> (snd_pcm_start+0x1c/0x24 [snd_pcm]) [ 16.448125] r8:00000000 r7:e8dd2000
> r6:e93a4c00 r5:bf09e4c0 r4:e99fb500 r3:00002000 [ 16.456083] [<bf09707c>]
> (snd_pcm_start [snd_pcm]) from [<bf09b094>] (snd_pcm_lib_write1+0x40c/0x4f0
> [snd_pcm]) [ 16.466391] [<bf09ac88>] (snd_pcm_lib_write1 [snd_pcm]) from
> [<bf09b244>] (snd_pcm_lib_write+0x64/0x78 [snd_pcm]) [ 16.476860]
> r10:be91ea4c r9:e8dd2000 r8:e8d66488 r7:00000000 r6:0002c780 r5:00000800 [
> 16.484889] r4:e99fb500
> [ 16.487494] [<bf09b1e0>] (snd_pcm_lib_write [snd_pcm]) from [<bf096c38>]
> (snd_pcm_playback_ioctl1+0x134/0x4c8 [snd_pcm]) [ 16.498583] r6:00000000
> r5:be91ea4c r4:e99fb500
> [ 16.503330] [<bf096b04>] (snd_pcm_playback_ioctl1 [snd_pcm]) from
> [<bf096ffc>] (snd_pcm_playback_ioctl+0x30/0x3c [snd_pcm]) [ 16.514685]
> r8:e8d66488 r7:be91ea4c r6:00000004 r5:e93d3880 r4:e93d3880 [ 16.521575]
> [<bf096fcc>] (snd_pcm_playback_ioctl [snd_pcm]) from [<c00d7c10>]
> (do_vfs_ioctl+0x80/0x5c8) [ 16.531163] [<c00d7b90>] (do_vfs_ioctl) from
> [<c00d8194>] (SyS_ioctl+0x3c/0x60) [ 16.538618] r10:00000000 r9:e8dd2000
> r8:00000004 r7:be91ea4c r6:400c4150 r5:e93d3880 [ 16.546648] r4:e93d3880
> [ 16.549243] [<c00d8158>] (SyS_ioctl) from [<c000f8a0>]
> (ret_fast_syscall+0x0/0x30) [ 16.556964] r8:c000fa24 r7:00000036
> r6:00000000 r5:0002c498 r4:0002c448 r3:be91ea4c
>
> The rsnd_soc_dai_trigger() function takes a spinlock, making the context
> atomic, which regmap doesn't like as it locks a mutex.
>
> It might be possible to fix this by setting the fast_io field in both the
> regmap_config and regmap_bus structures in sound/soc/sh/rcar/gen.c. regmap
> will then use a spinlock instead of a mutex. However, even if I believe that
> change makes sense and should be done, another atomic context issue will
> come from the rcar-dmac driver which allocates memory in the
> prep_dma_cyclic function, called by rsnd_dma_start() from
> rsnd_soc_dai_trigger() with the spinlock help.
>
> What context is the rsnd_soc_dai_trigger() function called in by the alsa
> core ? If it's guaranteed to be a sleepable context, would it make sense to
> replace the rsnd_priv spinlock with a mutex ?
Answering myself here, that's not an option, as the trigger function is called
in atomic context (replacing the spinlock with a mutex produced a clear BUG)
due to snd_pcm_lib_write1() taking a spinlock.
Now we have a core issue. On one side there's rsnd_soc_dai_trigger() being
called in atomic context, and on the other side the function ends up calling
dmaengine_prep_dma_cyclic() which needs to allocate memory. To make this more
func the DMA engine API is undocumented and completely silent on whether the
prep functions are allowed to sleep. The question is, who's wrong ?
Now, if you're tempted to say that I'm wrong by allocating memory with
GFP_KERNEL in the DMA engine driver, please read on first :-) I've tried
replacing GFP_KERNEL with GFP_ATOMIC allocations, and then ran into a problem
more complex to solve.
The rcar-dmac DMA engine driver uses runtime PM. When not used, the device is
suspended. The driver calls pm_runtime_get_sync() to resume the device, and
needs to do so when a descriptor is submitted. This operation, currently
performed in the tx_submit handler, could be moved to the prep_dma_cyclic or
issue_pending handler, but the three operations are called in a row from
rsnd_dma_start(), itself ultimately called from snd_pcm_lib_write1() with the
spinlock held. This means I have no place in my DMA engine driver where I can
resume the device.
One could argue that the rcar-dmac driver could use a work queue to handle
power management. That's correct, but the additional complexity, which would
be required in *all* DMA engine drivers, seem too high to me. If we need to go
that way, this is really a task that the DMA engine core should handle.
Let's start by answering the background question and updating the DMA engine
API documentation once and for good : in which context are drivers allowed to
call the prep, tx_submit and issue_pending functions ?
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian
From: Ard Biesheuvel @ 2014-07-23 10:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723093409.GB2714@leverpostej>
On 23 July 2014 11:34, Mark Rutland <mark.rutland@arm.com> wrote:
> Hi Ard,
>
> This is certainly a neat feature, and I definitely want to be able to
> boot BE kernels via UEFI.
>
Good!
> However, I'm wary of calling EFI in a physical (i.e. idmap with dcaches
> off) context. I'm not sure anyone else does that, and I'm not sure
> whether that's going to work (both because of the cache maintenance
> requirements and the expectations of a given UEFI implementation w.r.t.
> memory cacheability).
>
I have developed an alternate version in the mean time that switches
to a LE idmap (so with D-cache enabled), but this is an imperfect
solution as well, as (like in the MMU off case), the vector base
virtual address cannot be resolved when the EE bit is cleared (as
TTBR1 points to a BE page table) so any exception taken locks the
machine hard. I am not sure if this can be solved in any way other
than changing exception levels. Or install an alternate vector table
for the duration of the runtime services call that flips the EE bit
back, restores VBAR to its original address, and jumps into it. None
of this is very sexy, though ...
> I'd hoped we'd be able to use a LE EL0 context to call the runtime
> services in, but I'm not sure that's possible by the spec :(
>
Nope, they should be called at the exception level UEFI was started in
(as Leif tells me)
> As I understand it, we shouldn't need these runtime services to simply
> boot a BE kernel.
>
Well, the significance of the variable store related Runtime Services
is that they are used by an installer (through efibootmgr) to program
the kernel command line. Hence the choice for just these services in
the minimal implementation.
--
Ard.
> On Mon, Jul 21, 2014 at 04:16:24PM +0100, Ard Biesheuvel wrote:
>> This enables the UEFI Runtime Services needed to manipulate the
>> non-volatile variable store when running under a BE kernel.
>>
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>> arch/arm64/include/asm/efi.h | 2 +
>> arch/arm64/kernel/efi-be-call.S | 55 ++++++++++++++++++++
>> arch/arm64/kernel/efi-be-runtime.c | 104 +++++++++++++++++++++++++++++++++++++
>> arch/arm64/kernel/efi.c | 15 ++++++
>> 4 files changed, 176 insertions(+)
>> create mode 100644 arch/arm64/kernel/efi-be-call.S
>> create mode 100644 arch/arm64/kernel/efi-be-runtime.c
>>
>> diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
>> index a34fd3b12e2b..44e642b6ab61 100644
>> --- a/arch/arm64/include/asm/efi.h
>> +++ b/arch/arm64/include/asm/efi.h
>> @@ -44,4 +44,6 @@ extern void efi_idmap_init(void);
>>
>> #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
>>
>> +extern void efi_be_runtime_setup(void);
>> +
>> #endif /* _ASM_EFI_H */
>> diff --git a/arch/arm64/kernel/efi-be-call.S b/arch/arm64/kernel/efi-be-call.S
>> new file mode 100644
>> index 000000000000..24c92a4c352b
>> --- /dev/null
>> +++ b/arch/arm64/kernel/efi-be-call.S
>> @@ -0,0 +1,55 @@
>> +
>> +#include <linux/linkage.h>
>> +
>> + .text
>> + .align 3
>> +ENTRY(efi_be_phys_call)
>> + /*
>> + * Entered at physical address with 1:1 mapping enabled.
>> + */
>> + stp x29, x30, [sp, #-96]!
>> + mov x29, sp
>> + str x27, [sp, #16]
>> +
>> + ldr x8, =efi_be_phys_call // virt address of this function
>> + adr x9, efi_be_phys_call // phys address of this function
>> + sub x9, x8, x9 // calculate virt to phys offset in x9
>> +
>> + /* preserve all inputs */
>> + stp x0, x1, [sp, #32]
>> + stp x2, x3, [sp, #48]
>> + stp x4, x5, [sp, #64]
>> + stp x6, x7, [sp, #80]
>> +
>> + /* get phys address of stack */
>> + sub sp, sp, x9
>> +
>> + /* switch to LE, disable MMU and D-cache but leave I-cache enabled */
>> + mrs x27, sctlr_el1
>> + bic x8, x27, #1 << 2 // clear SCTLR.C
>> + msr sctlr_el1, x8
>> +
>> + bl flush_cache_all
>
> What is the cache flush for?
>
> The only thing that flush_cache_all can do is empty the local
> architected caches, and it can only do that when said caches are
> disabled. Any other use is unsafe; we have no guarantee that the cache
> is empty (or even clean), and we have no guarantee that prior writes
> have made it to the PoC.
>
> Even when the caches are disabled, flush_cache_all can only guarantee
> that the local architected caches are empty. There is no guarantee that
> the dirty data made it to the PoC.
>
>> +
>> + /* restore inputs but rotated by 1 register */
>> + ldp x7, x0, [sp, #32]
>> + ldp x1, x2, [sp, #48]
>> + ldp x3, x4, [sp, #64]
>> + ldp x5, x6, [sp, #80]
>> +
>> + bic x8, x27, #1 << 2 // clear SCTLR.C
>> + bic x8, x8, #1 << 0 // clear SCTLR.M
>> + bic x8, x8, #1 << 25 // clear SCTLR.EE
>> + msr sctlr_el1, x8
>> + isb
>> +
>> + blr x7
>
> Is it safe to call EFI functions with the D-cache disabled?
>
> Do the functions not care about the memory attributes for their own sue
> (e.g. for exclusives)?
>
> Do they not care about IO? If IO to/from storage for variables is
> cache-coherent EFI and the device won't have a coherent view of memory.
>
>> +
>> + /* switch back to BE and reenable MMU and D-cache */
>> + msr sctlr_el1, x27
>> +
>
> Missing ISB?
>
>> + mov sp, x29
>> + ldr x27, [sp, #16]
>> + ldp x29, x30, [sp], #96
>> + ret
>> +ENDPROC(efi_be_phys_call)
>> diff --git a/arch/arm64/kernel/efi-be-runtime.c b/arch/arm64/kernel/efi-be-runtime.c
>> new file mode 100644
>> index 000000000000..62e6c441b77b
>> --- /dev/null
>> +++ b/arch/arm64/kernel/efi-be-runtime.c
>> @@ -0,0 +1,104 @@
>> +
>> +#include <linux/efi.h>
>> +#include <linux/spinlock.h>
>> +#include <asm/efi.h>
>> +#include <asm/neon.h>
>> +#include <asm/tlbflush.h>
>> +
>> +static efi_runtime_services_t *runtime;
>> +static efi_status_t (*efi_be_call)(phys_addr_t func, ...);
>> +
>> +static DEFINE_SPINLOCK(efi_be_rt_lock);
>> +
>> +static unsigned long efi_be_call_pre(void)
>> +{
>> + unsigned long flags;
>> +
>> + kernel_neon_begin();
>> + spin_lock_irqsave(&efi_be_rt_lock, flags);
>
> At this point we might still have DA_F unmasked, and I don't think we
> expect to be able to handle any of those when the CPU is in the wrong
> endianness for the kernel.
>
>> + cpu_switch_mm(idmap_pg_dir, &init_mm);
>> + flush_tlb_all();
>> + return flags;
>> +}
>> +
>> +static void efi_be_call_post(unsigned long flags)
>> +{
>> + cpu_switch_mm(current, current->active_mm);
>> + flush_tlb_all();
>> + spin_unlock_irqrestore(&efi_be_rt_lock, flags);
>> + kernel_neon_end();
>> +}
>> +
>> +static efi_status_t efi_be_get_variable(efi_char16_t *name,
>> + efi_guid_t *vendor,
>> + u32 *attr,
>> + unsigned long *data_size,
>> + void *data)
>> +{
>> + unsigned long flags;
>> + efi_status_t status;
>> +
>> + *data_size = cpu_to_le64(*data_size);
>> + flags = efi_be_call_pre();
>> + status = efi_be_call(le64_to_cpu(runtime->get_variable),
>> + virt_to_phys(name), virt_to_phys(vendor),
>> + virt_to_phys(attr), virt_to_phys(data_size),
>> + virt_to_phys(data));
>> + efi_be_call_post(flags);
>> + *attr = le32_to_cpu(*attr);
>> + *data_size = le64_to_cpu(*data_size);
>> + return status;
>
> No cache maintenance? EFI Could have written to a physical mapping which
> could be shadowed by old cache entries. Similarly any buffers that we
> pass to UEFI aren't guaranteed to have been hit the PoC, so UEFI might
> read stale data.
>
> I think that's true for all of the efi_be_* calls below.
>
>> +}
>> +
>> +static efi_status_t efi_be_get_next_variable(unsigned long *name_size,
>> + efi_char16_t *name,
>> + efi_guid_t *vendor)
>> +{
>> + unsigned long flags;
>> + efi_status_t status;
>> +
>> + *name_size = cpu_to_le64(*name_size);
>> + flags = efi_be_call_pre();
>> + status = efi_be_call(le64_to_cpu(runtime->get_next_variable),
>> + virt_to_phys(name_size), virt_to_phys(name),
>> + virt_to_phys(vendor));
>> + efi_be_call_post(flags);
>> + *name_size = le64_to_cpu(*name_size);
>> + return status;
>> +}
>> +
>> +static efi_status_t efi_be_set_variable(efi_char16_t *name,
>> + efi_guid_t *vendor,
>> + u32 attr,
>> + unsigned long data_size,
>> + void *data)
>> +{
>> + unsigned long flags;
>> + efi_status_t status;
>> +
>> + flags = efi_be_call_pre();
>> + status = efi_be_call(le64_to_cpu(runtime->set_variable),
>> + virt_to_phys(name), virt_to_phys(vendor),
>> + cpu_to_le32(attr), cpu_to_le64(data_size),
>> + virt_to_phys(data));
>> + efi_be_call_post(flags);
>> + return status;
>> +}
>> +
>> +void efi_be_runtime_setup(void)
>> +{
>> + extern u8 efi_be_phys_call[];
>> +
>> + runtime = ioremap_cache(le64_to_cpu(efi.systab->runtime),
>> + sizeof(efi_runtime_services_t));
>> + if (!runtime) {
>> + pr_err("Failed to set up BE wrappers for UEFI Runtime Services!\n");
>> + return;
>> + }
>
> Might it be worth propagating the error code?
>
>> +
>> + efi_be_call = (void *)virt_to_phys(efi_be_phys_call);
>> +
>> + efi.get_variable = efi_be_get_variable;
>> + efi.get_next_variable = efi_be_get_next_variable;
>> + efi.set_variable = efi_be_set_variable;
>> +}
>> diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
>> index 96df58824189..21e98810c5dd 100644
>> --- a/arch/arm64/kernel/efi.c
>> +++ b/arch/arm64/kernel/efi.c
>> @@ -406,6 +406,21 @@ static int __init arm64_enter_virtual_mode(void)
>>
>> efi.memmap = &memmap;
>>
>> + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
>> + efi.systab = ioremap_cache(efi_system_table,
>> + sizeof(efi_system_table_t));
>> + if (!efi.systab) {
>> + pr_err("Failed to remap EFI system table!\n");
>> + return -1;
>> + }
>> + free_boot_services();
>> + efi_be_runtime_setup();
>
> We can fail here, but we'll still set the bits below, which doesn't seem
> right.
>
>> +
>> + set_bit(EFI_SYSTEM_TABLES, &efi.flags);
>> + set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
>> + return 0;
>> + }
>> +
>> /* Map the runtime regions */
>> virtmap = kmalloc(mapsize, GFP_KERNEL);
>> if (!virtmap) {
>> --
>> 1.8.3.2
>
> Cheers,
> Mark.
^ permalink raw reply
* [PATCH 0/6] net: mvpp2: Assorted fixes
From: Ezequiel Garcia @ 2014-07-23 10:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140722.195222.775371949777233094.davem@davemloft.net>
On 22 Jul 07:52 PM, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Tue, 22 Jul 2014 17:41:53 -0700 (PDT)
>
> > From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> > Date: Tue, 22 Jul 2014 20:20:04 -0300
> >
> >> On 23 Jul 12:29 AM, Thomas Petazzoni wrote:
> >>> On Tue, 22 Jul 2014 13:16:39 -0700 (PDT), David Miller wrote:
> >>>
> >>> > >> This series does not apply to the 'net' tree at all, please respin
> >>> > >> and resubmit.
> >>> > >
> >>> > > This series applies on net-next.
> >>> > >
> >>> > > Sorry for not mentioning it,
> >>> >
> >>> > They are bonafide bug fixes, therefore should be targetted at 'net'.
> >>>
> >>> Except that I believe they are fixes for a driver which itself is in
> >>> net-next, i.e scheduled for 3.17.
> >>>
> >>
> >> That's right. These are fixes for the new mvpp2 driver, which is only
> >> in net-next.
> >
> > Ok, I queued them back up, thanks for the clarification.
>
> I've applied the 4 driver patches to net-next. But, since the ARM
> device tree file changes did not go into net-next, I can't apply the
> last two patches to my tree. You'll need to sort that out yourself.
>
> It's a bit unfortunate that things are now out of sync like this, but
> that's what you asked me to do.
Thanks for applying this. We'll queue the devicetree changes as fixes
for v3.17-rc1 through the arm-soc tree.
--
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH v2] cpufreq: tests: Providing cpufreq regression test
From: Viresh Kumar @ 2014-07-23 10:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723121042.5b6f49e3@amdc2363>
On 23 July 2014 15:40, Lukasz Majewski <l.majewski@samsung.com> wrote:
>> Shouldn't you use userspace governor then instead of performance?
>
> Performance assures that we will have the right frequency set.
Why wouldn't userspace assure that?
> However, there can be a similar patch to use userspace governor and
> various load to fail if ondemand's frequency flipping is detected.
That's why I want to get to the motive behind this patch.
AFAIU, we are checking if its fine to switch to available frequencies
or not and if yes, do we actually switch to those. Right?
For, this testcase we just need a single test and I still don't see why
performance is better than userspace?
>> And then we don't need the gzip stuff at all. We can just set it to
>> the right freq and get current freq to see if it matches?
>
> Sometimes "interresting" things show up when you have 100% CPU load and
> you try to switch frequency.
That's a different test then. And that's how it should be presented.
So, probably another option to the script, which isn't forced on people.
^ permalink raw reply
* [PATCHv4 3/5] common: dma-mapping: Introduce common remapping functions
From: Catalin Marinas @ 2014-07-23 10:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1406079308-5232-4-git-send-email-lauraa@codeaurora.org>
On Wed, Jul 23, 2014 at 02:35:06AM +0100, Laura Abbott wrote:
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -298,37 +298,19 @@ static void *
> __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
> const void *caller)
> {
> - struct vm_struct *area;
> - unsigned long addr;
> -
> /*
> * DMA allocation can be mapped to user space, so lets
> * set VM_USERMAP flags too.
> */
> - area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
> - caller);
> - if (!area)
> - return NULL;
> - addr = (unsigned long)area->addr;
> - area->phys_addr = __pfn_to_phys(page_to_pfn(page));
> -
> - if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
> - vunmap((void *)addr);
> - return NULL;
> - }
> - return (void *)addr;
> + return dma_common_contiguous_remap(page, size,
> + VM_ARM_DMA_CONSISTENT | VM_USERMAP,
> + prot, caller);
I think we still need at least a comment in the commit log since the arm
code is moving from ioremap_page_range() to map_vm_area(). There is a
slight performance penalty with the addition of a kmalloc() on this
path.
Or even better (IMO), see below.
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
[...]
> +void *dma_common_contiguous_remap(struct page *page, size_t size,
> + unsigned long vm_flags,
> + pgprot_t prot, const void *caller)
> +{
> + int i;
> + struct page **pages;
> + void *ptr;
> +
> + pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
> + if (!pages)
> + return NULL;
> +
> + for (i = 0; i < (size >> PAGE_SHIFT); i++)
> + pages[i] = page + i;
> +
> + ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller);
> +
> + kfree(pages);
> +
> + return ptr;
> +}
You could avoid the dma_common_page_remap() here (and kmalloc) and
simply use ioremap_page_range(). We know that
dma_common_contiguous_remap() is only called with contiguous physical
range, so ioremap_page_range() is suitable. It also makes it a
non-functional change for arch/arm.
--
Catalin
^ permalink raw reply
* [PATCH] ARM: OMAP2+: clock: allow omap2_dpll_round_rate() to round to next-lowest rate
From: Paul Walmsley @ 2014-07-23 10:44 UTC (permalink / raw)
To: linux-arm-kernel
Change the behavior of omap2_dpll_round_rate() to round to either the
exact rate requested, or the next lowest rate that the clock is able to
provide.
This is not an ideal fix, but is intended to provide a relatively safe
way for drivers to set PLL rates, until a better solution can be
implemented.
For the time being, omap3_noncore_dpll_set_rate() is still allowed to
set its rate to something other than what the caller requested; but will
warn when this occurs.
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/clkt_dpll.c | 28 +++++++++++++++++++++-------
arch/arm/mach-omap2/dpll3xxx.c | 12 ++++++++++--
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index 332af927f4d3..85701142c5fc 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -293,10 +293,13 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
int m, n, r, scaled_max_m;
+ int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
unsigned long scaled_rt_rp;
unsigned long new_rate = 0;
struct dpll_data *dd;
unsigned long ref_rate;
+ long delta;
+ long prev_min_delta = LONG_MAX;
const char *clk_name;
if (!clk || !clk->dpll_data)
@@ -342,23 +345,34 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
if (r == DPLL_MULT_UNDERFLOW)
continue;
+ /* skip rates above our target rate */
+ delta = target_rate - new_rate;
+ if (delta < 0)
+ continue;
+
+ if (delta < prev_min_delta) {
+ prev_min_delta = delta;
+ min_delta_m = m;
+ min_delta_n = n;
+ }
+
pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
clk_name, m, n, new_rate);
- if (target_rate == new_rate) {
- dd->last_rounded_m = m;
- dd->last_rounded_n = n;
- dd->last_rounded_rate = target_rate;
+ if (delta == 0)
break;
- }
}
- if (target_rate != new_rate) {
+ if (prev_min_delta == LONG_MAX) {
pr_debug("clock: %s: cannot round to rate %lu\n",
clk_name, target_rate);
return ~0;
}
- return target_rate;
+ dd->last_rounded_m = min_delta_m;
+ dd->last_rounded_n = min_delta_n;
+ dd->last_rounded_rate = target_rate - prev_min_delta;
+
+ return dd->last_rounded_rate;
}
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index fcd8036af910..839a13e1208b 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -469,6 +469,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct clk *new_parent = NULL;
+ unsigned long rrate;
u16 freqsel = 0;
struct dpll_data *dd;
int ret;
@@ -496,8 +497,15 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
__clk_prepare(dd->clk_ref);
clk_enable(dd->clk_ref);
- if (dd->last_rounded_rate != rate)
- rate = __clk_round_rate(hw->clk, rate);
+ if (dd->last_rounded_rate != rate) {
+ rrate = __clk_round_rate(hw->clk, rate);
+ if (rrate != rate) {
+ pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
+ __func__, __clk_get_name(hw->clk),
+ rrate, rate);
+ rate = rrate;
+ }
+ }
if (dd->last_rounded_rate == 0)
return -EINVAL;
--
2.0.1
^ permalink raw reply related
* [PATCH 00/14] arm64: eBPF JIT compiler
From: Catalin Marinas @ 2014-07-23 10:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMEtUuyC+MykPDO0ghTc=oex7KPLEy=BLRgWBdW+qJY7JXQmDQ@mail.gmail.com>
On Mon, Jul 21, 2014 at 04:49:29PM +0100, Alexei Starovoitov wrote:
> On Mon, Jul 21, 2014 at 2:16 AM, Will Deacon <will.deacon@arm.com> wrote:
> > On Fri, Jul 18, 2014 at 07:28:06PM +0100, Zi Shen Lim wrote:
> >> This series implements eBPF JIT compiler for arm64.
> >> Please see [14/14] for change log.
> >>
> >> Patches [1-13/14] implement code generation functions.
> >> Patch [14/14] implements the actual eBPF JIT compiler.
> >>
> >> Many thanks to everyone who's reviewed the code from
> >> RFCv1->RFCv3, especially Alexei for BPF bits, and Will
> >> for ARM64 codegen bits :)
> >>
> >> BTW, I'm happy to maintain arch/arm64/net (i.e. arm64 BPF bits).
> >> Should I add a patch updating MAINTAINERS as Patch 15?
> >
> > I don't think that's necessary at the moment, but if we start seeing an
> > influx of patches to arch/arm64/net, then that could make sense in the
> > future.
> >
> >> This series requires a patch that exports a function
> >> from net/core (resulting from RFCv1 discussion). This patch
> >> has been merged into net-next @ 9f12fbe603f7
> >> ("net: filter: move load_pointer() into filter.h").
> >>
> >> This series applies against net-next and is tested working
> >> with lib/test_bpf on ARMv8 Foundation Model.
> >
> > Looks like it works on my Juno board too, so:
> >
> > Acked-by: Will Deacon <will.deacon@arm.com>
> >
> > for the series.
> >
> > It's a bit late for 3.17 now, so I guess we'll queue this for 3.18 (which
> > also means the dependency on -next isn't an issue). Perhaps you could repost
> > around -rc3?
>
> Thanks for testing! Nice to see it working on real hw.
> I'm not sure why you're proposing a 4+ week delay. The patches
> will rot instead of getting used and tested. Imo it makes sense to
> get them into net-next now for 3.17.
> JIT is disabled by sysctl by default anyway.
We normally like some patches (especially new functionality) to sit in
linux-next for a while before the mering window (ideally starting with
-rc4 or -rc5). We are at -rc6 already, so getting close to the 3.17
merging window.
Another aspect is that the arm64/bpf branch depends on the net tree, so
it can't easily go in via the arm64 tree for 3.17 (3.18 would not be a
problem).
--
Catalin
^ permalink raw reply
* [PATCH v3] ASoC: tda998x: add a codec to the HDMI transmitter
From: Andrew Jackson @ 2014-07-23 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140708114057.5ef3cfd0@armhf>
On 07/08/14 10:40, Jean-Francois Moine wrote:
> This patch adds a CODEC function to the NXP TDA998x HDMI transmitter.
>
> The CODEC handles both I2S and S/PDIF input and does dynamic input
> switch in the TDA998x I2C driver on start/stop audio streaming.
>
> Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
> ---
Shouldn't the patch also capture the current audio rate in tda998x_codec.c:tda_hw_params? Otherwise, when tda998x_drv.c:tda998x_audio_start invokes tda998x_drv.c:tda998x_configure_audio, the value of 'N' will be calculated incorrectly.
So something similar to:
diff --git a/drivers/gpu/drm/i2c/tda998x_codec.c b/drivers/gpu/drm/i2c/tda998x_codec.c
index e7f223d..b6c4fb3 100755
--- a/drivers/gpu/drm/i2c/tda998x_codec.c
+++ b/drivers/gpu/drm/i2c/tda998x_codec.c
@@ -111,6 +111,7 @@ static int tda_hw_params(struct snd_pcm_substream *substream,
tda998x_audio_start(priv, 0);
return 0;
}
+ priv->params.audio_sample_rate = params_rate(params);
priv->params.audio_format = dai->id;
priv->audio_sample_format = params_format(params);
params.audio_cfg =
Andrew
^ permalink raw reply related
* [RFC V2] devicetree: Dialog Semiconductor consolidate existing vendor prefixes to standardise on 'dlg'
From: Lee Jones @ 2014-07-23 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6ED8E3B22081A4459DAC7699F3695FB7D0B2762A@SW-EX-MBX02.diasemi.com>
On Wed, 23 Jul 2014, Opensource [Steve Twiss] wrote:
>
> On 22 July 2014 08:09, Lee Jones wrote:
>
> >-----Original Message-----
> >From: Lee Jones [mailto:lee.jones at linaro.org]
> >> From: Opensource [Steve Twiss] <stwiss.opensource@diasemi.com>
> >>
> >> This patch series updates the device tree vendor prefix for
> >> Dialog Semiconductor.
> >>
> >> Various methods are currently used throughout the kernel: 'diasemi',
> >> 'dialog' and 'dlg'. Others have also been suggested.
> >>
> >> This patch set aims to consolidate the usage of the vendor prefix to
> >> use a common standard. The prefix 'dlg' is used.
> >>
> >> Here is my working for justifying this change:
> >>
> >> ./arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
> >> Has the following entry:
> >> compatible = "dialog,da9063";
> >> However the DA9063 driver does not support device tree yet so
> >> it would be safe to rename this.
> >>
> >> ./arch/arm/boot/dts/imx53-smd.dts
> >> Has the following entry:
> >> compatible = "dialog,da9053", "dialog,da9052";
> >> However, the existing driver files for DA9053 define a different
> >> compatible string with the "dlg" prefix. See the entries below.
> >> None of these would have allowed the "dialog" prefix.
> >> { .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] },
> >> { .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] },
> >> { .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] },
> >> { .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] },
> >> { .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] },
> >> In this particular case the change for DA9053 did not match up
> >> with the expected compatibility strings and therefore I have
> >> retained the more general "dlg,da9053" because I do not know
> >> which silicon variant (-aa, -ba, -bb, or -bc) is the correct
> >> one to use.
> >>
> >> ./devicetree/bindings/i2c/trivial-devices.txt
> >> Has the following entry:
> >> dialog,da9053 DA9053: flexible system level PMIC with multicore support
> >> Instead of depreciating this "dialog" line I am just replacing it
> >> with a "dlg" because the existing driver DA9053 does not support
> >> the dialog keyword.
> >>
> >> ./drivers/mfd/da9055-core.c
> >> Has the following entries for the mfd cells
> >> .of_compatible = "dialog,da9055-gpio", etc...
> >> In this case, the driver does not actually pass in any platform data
> >> to any of the mfd cells and so they are not actually used
> >> yet in the driver. Nobody else references this information.
> >>
> >> ./devicetree/bindings/regulator/da9210.txt
> >> Has the following two entries in the binding file:
> >> - compatible: must be "diasemi,da9210"
> >> compatible = "diasemi,da9210";
> >> However the DA9210 driver does not support device tree.
> >>
> >> ./arch/arm/boot/dts/r8a7790-lager.dts
> >> ./arch/arm/boot/dts/r8a7791-koelsch.dts
> >> These two files have the following entries:
> >> compatible = "diasemi,da9210";
> >> These both reference the "diasemi,da9210" but the device
> >> driver does not support device tree
> >>
> >> The remaining files in the kernel I have found correctly references
> >> the driver files compatibility information and so did not need to
> >> be changed.
> >>
> >> ./devicetree/bindings/mfd/da9052-i2c.txt
> >> - compatible : Should be "dlg,da9052", "dlg,da9053-aa",
> >> "dlg,da9053-ab", or "dlg,da9053-bb"
> >>
> >> ./devicetree/bindings/mfd/da9055.txt
> >> compatible = "dlg,da9055-pmic";
> >>
> >> ./arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi
> >> compatible = "dlg,da9053-aa", "dlg,da9052";
> >>
> >> ./arch/arm/boot/dts/imx53-qsb.dts
> >> compatible = "dlg,da9053-aa", "dlg,da9052";
> >>
> >> ./devicetree/bindings/sound/da9055.txt
> >> - compatible: "dlg,da9055-codec"
> >> compatible = "dlg,da9055-codec";
> >>
> >>
> >> Signed-off-by: Opensource [Steve Twiss] <stwiss.opensource@diasemi.com>
> >> ---
> >> Checks performed with linux-next/next-20140715/scripts/checkpatch.pl
> >> trivial-devices.txt total: 0 errors, 0 warnings, 89 lines checked
> >> da9210.txt total: 0 errors, 0 warnings, 21 lines checked
> >> vendor-prefixes.txt total: 0 errors, 0 warnings, 149 lines checked
> >> imx53-smd.dts total: 0 errors, 2 warnings, 279 lines checked
> >> imx6qdl-phytec-pfla02.dtsi total: 0 errors, 2 warnings, 357 lines checked
> >> r8a7790-lager.dts total: 0 errors, 3 warnings, 403 lines checked
> >> r8a7791-koelsch.dts total: 0 errors, 4 warnings, 461 lines checked
> >> da9055-core.c total: 0 errors, 0 warnings, 428 lines checked
> >>
> >> This e-mail is in response to the previous threads here:
> >> https://lkml.org/lkml/2014/6/11/262
> >> http://comments.gmane.org/gmane.linux.ports.arm.kernel/341358
> >>
> >> Changes since RFC V1
> >> - addition of changes to DTS files referencing "diasemi,da9210"
> >> arch/arm/boot/dts/r8a7790-lager.dts
> >> arch/arm/boot/dts/r8a7791-koelsch.dts
> >>
> >> This RFC V2 does not answer the response to RFC V1 from Mark Brown:
> >> http://www.spinics.net/lists/arm-kernel/msg347615.html
> >>
> >> This patch applies against linux-next and next-20140715
> >>
> >> Regards,
> >> Steve Twiss, Dialog Semiconductor Ltd.
> >>
> >>
> >>
> >> .../devicetree/bindings/i2c/trivial-devices.txt | 2 +-
> >> .../devicetree/bindings/regulator/da9210.txt | 4 ++--
> >> .../devicetree/bindings/vendor-prefixes.txt | 1 +
> >> arch/arm/boot/dts/imx53-smd.dts | 2 +-
> >> arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi | 2 +-
> >> arch/arm/boot/dts/r8a7790-lager.dts | 2 +-
> >> arch/arm/boot/dts/r8a7791-koelsch.dts | 2 +-
> >> drivers/mfd/da9055-core.c | 26 ++++++++++----------
> >
> >For the MFD changes:
> >
> > Acked-by: Lee Jones <lee.jones@linaro.org>
> >
> >Which tree is this patch going into? Do you want me to take it and
> >supply an IB for the other Maintainers to pull from?
>
> Hi Lee,
>
> I'm not sure if this question was for me directly, but I do not have any
> preference who takes this change or how it gets pulled. Thank you.
>
> There was a request from Rob Herring
> http://www.spinics.net/lists/arm-kernel/msg349289.html
> to reformat the original e-mail content and also to drop the annoying
> "Opensource" and square brackets from my Signed-off-by:
> signature.
... and Author:
So for me to take this, I need to see DT or Maintainer Acks for the
bindings and DTS(I) changes.
> So, the decision is to take the patch into an immutable branch
> and you need me to re-format the e-mail content -- I will resend
> with those changes.
>
> Regards,
> Steve
>
> >
> >> 8 files changed, 21 insertions(+), 20 deletions(-)
--
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] cpufreq: tests: Providing cpufreq regression test
From: Lukasz Majewski @ 2014-07-23 10:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKohpok++gPcNk9-E4MsFdNBy8qL7oLYvatk1EvcW1OHwroZXQ@mail.gmail.com>
Hi Viresh,
> On 23 July 2014 13:08, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > Do you want to say that we have enough tests and we don't need
> > more ?
>
> No. We don't have any tests at all :)
Then we should encourage as many developers as possible to share their
private tests with us.
>
> > I always thought that we shall have as much regression tests as
> > possible.
>
> Yeah, tests are welcomed but the question is where should they get
> added. Don't know if its common to add tests directly to kernel.
There was a similar discussion with device tree and finally it was
included in the mainline repository.
>
> And also if the test is really good, not discouraging your work.
>
> >> On 21 July 2014 12:32, Lukasz Majewski <l.majewski@samsung.com>
> >> wrote:
> >> > This commit adds first regression test "cpufreq_freq_test.sh" for
> >> > the cpufreq subsystem.
> >>
> >> That's not enough, Tell us why we should continue reading this
> >> mail..
> >
> > Hmm... If "regression" and "test" don't catch the attention of a
> > diligent maintainer, then I cannot do much more to encourage him to
> > read the whole e-mail :-)
>
> What I meant to say was, your subject and body must be good enough
> to answer most of the things. You don't have to tell much about the
> implementation but other things should be pretty clear from logs.
>
> Your current logs are quite short for something that's not a normal
> practice.
It is hard for me to agree on this issue.
>
> > I can imagine that maintainers are very busy, therefore I've
> > prepared README file with detailed description of the script
> > operation.
>
> Yeah, a README is welcomed and would be useful for users as well..
>
> >> I couldn't make out the purpose of this test and why we need it.
> >> How do we ensure that "cpufreq attributes exported by sysfs are
> >> exposing correct values"?
> >
> > First of all the cpufreq attributes are part of the subsystem API.
> > There are systems which actually depend on them, so we would be
> > better off to test if they work as intended.
> >
> > Secondly, the test takes those values and then with use of other
> > attribute enforce the value, which is then read via cat'ing
> > cpufreq_cur_freq. If any of the attributes is wrong then we will
> > spot the error immediately.
>
> Shouldn't you use userspace governor then instead of performance?
Performance assures that we will have the right frequency set.
However, there can be a similar patch to use userspace governor and
various load to fail if ondemand's frequency flipping is detected.
> And then we don't need the gzip stuff at all. We can just set it to
> the right freq and get current freq to see if it matches?
Sometimes "interresting" things show up when you have 100% CPU load and
you try to switch frequency.
In my opinion usage of gzip makes the test more difficult to pass.
>
> And now that we are starting to get tests added into the kernel (will
> still wait to see what Rafael has to advice),
Ok. Lets wait for Rafael's opinion.
> we better think of the
> way these are going to get added. Probably a single script with
> parameters like what to test?
It is one possible solution, where another one is to run the all scripts
in the directory.
I'm curious about Rafael's opinion.
>
> >> And actually what do we mean by this statement even? What kind of
> >> errors can be there in exposing these values.
> >
> > Errors with cpufreq and CCF cooperation - especially when some
> > parts of cpufreq code uses direct write to MUX, DIV or PLL SoC
> > registers.
> >
> > Also, one can check if permutations of changing all available
> > frequencies are working properly.
>
> Yeah, that would be fine. Probably need to think more about scripts
> name.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ permalink raw reply
* [PATCH 1/5] rtc: sun6i: Add sun6i RTC driver
From: Maxime Ripard @ 2014-07-23 9:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v64K0iZ9e+1bdtkFVv5=t6nmTCTmUKeXLP-GvMaxAxQi+g@mail.gmail.com>
Hi,
On Mon, Jul 21, 2014 at 10:46:06PM +0800, Chen-Yu Tsai wrote:
> Hi,
>
> On Fri, Jul 18, 2014 at 4:07 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi,
> >
> > On Mon, Jul 14, 2014 at 03:32:13PM +0800, Chen-Yu Tsai wrote:
> >> This patch introduces the driver for the RTC in the Allwinner A31 and
> >> A23 SoCs.
> >>
> >> Unlike the RTC found in A10/A20 SoCs, which was part of the timer, the
> >> RTC in A31/A23 are a separate hardware block, which also contain a few
> >> controls for the RTC block hardware (a regulator and RTC block GPIO pin
> >> latches), while also having separate interrupts for the alarms.
> >
> > Do you plan on supporting those at some point?
>
> I haven't seen any devices use the regulator (which has an output pin).
> I suppose we shouldn't add drivers for things we can't verify.
> As for the GPIO pin latches, I'll have to experiment some more to figure
> out what they do exactly.
Ok.
> > It's also worth noting that the first registers are supposed to
> > control the source of the low frequency oscillator in the SoC, which
> > will probably be the most troublesome, since we need these clocks very
> > early on.
>
> That's true. I suppose the bootloader configures this. IIRC I've seen
> code for this in boot0 or boot1 from Allwinner. I can't find the equivalent
> for our sun4i u-boot though.
Do you know what was the bootloader configuring it to?
I don't really know how we can deal with this in a nice way, but I
guess it's not so urgent.
> >>
> >> The hardware is different enough to make a different driver for it.
> >>
> >> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> >> ---
> >> .../devicetree/bindings/rtc/sun6i-rtc.txt | 17 +
> >> drivers/rtc/Kconfig | 7 +
> >> drivers/rtc/Makefile | 1 +
> >> drivers/rtc/rtc-sun6i.c | 466 +++++++++++++++++++++
> >> 4 files changed, 491 insertions(+)
> >> create mode 100644 Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
> >> create mode 100644 drivers/rtc/rtc-sun6i.c
> >>
> >> diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
> >> new file mode 100644
> >> index 0000000..b18927c
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
> >> @@ -0,0 +1,17 @@
> >> +* sun6i Real Time Clock
> >> +
> >> +RTC controller for the Allwinner A31
> >> +
> >> +Required properties:
> >> +- compatible : Should be "allwinner,sun6i-a31-rtc"
> >> +- reg: physical base address of the controller and length of memory mapped
> >> + region.
> >> +- interrupts: IRQ line for the RTC alarm 0.
> >> +
> >> +Example:
> >> +
> >> +rtc: rtc at 01f00000 {
> >> + compatible = "allwinner,sun6i-a31-rtc";
> >> + reg = <0x01f00000 0x54>;
> >> + interrupts = <0 40 4>;
> >> +};
> >> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> >> index 0754f5c..5b3910a 100644
> >> --- a/drivers/rtc/Kconfig
> >> +++ b/drivers/rtc/Kconfig
> >> @@ -1167,6 +1167,13 @@ config RTC_DRV_SUN4V
> >> If you say Y here you will get support for the Hypervisor
> >> based RTC on SUN4V systems.
> >>
> >> +config RTC_DRV_SUN6I
> >> + tristate "Allwinner sun6i/sun8i RTC"
> >
> > I'm half convinced about an exhaustive list here. That IP will also
> > probably be used by sun9i, and sun10i if it ever exists, etc. And you
> > exhaustive list won't be anymore.
> >
> > I'd rather just mention the A31, like we do for the DT.
>
> Fixed.
>
> >> + depends on MACH_SUN6I || MACH_SUN8I
> >> + help
> >> + If you say Y here you will get support for the RTC found on
> >> + Allwinner A31/A23.
> >> +
> >> config RTC_DRV_SUNXI
> >> tristate "Allwinner sun4i/sun7i RTC"
> >> depends on ARCH_SUNXI
> >> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> >> index 70347d0..a47df29 100644
> >> --- a/drivers/rtc/Makefile
> >> +++ b/drivers/rtc/Makefile
> >> @@ -123,6 +123,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
> >> obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
> >> obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
> >> obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
> >> +obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o
> >> obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
> >> obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
> >> obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
> >> diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
> >> new file mode 100644
> >> index 0000000..fabd019
> >> --- /dev/null
> >> +++ b/drivers/rtc/rtc-sun6i.c
> >> @@ -0,0 +1,466 @@
> >> +/*
> >> + * An RTC driver for Allwinner A31/A23
> >> + *
> >> + * Copyright (c) 2014, Chen-Yu Tsai <wens@csie.org>
> >> + *
> >> + * based on rtc-sunxi.c
> >> + *
> >> + * An RTC driver for Allwinner A10/A20
> >> + *
> >> + * Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.com>
> >> + *
> >> + * 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/delay.h>
> >> +#include <linux/err.h>
> >> +#include <linux/fs.h>
> >> +#include <linux/init.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/rtc.h>
> >> +#include <linux/types.h>
> >> +
> >> +/* Control register */
> >> +#define SUN6I_LOSC_CTRL 0x0000
> >> +#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
> >> +#define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
> >> +#define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
> >> +#define SUN6I_LOSC_CTRL_ACC_MASK (BIT(9) | BIT(8) | BIT(7))
> >
> > GENMASK maybe?
>
> Fixed
>
> >> +
> >> +/* RTC */
> >> +#define SUN6I_RTC_YMD 0x0010
> >> +#define SUN6I_RTC_HMS 0x0014
> >> +
> >> +/* Alarm 0 (counter) */
> >> +#define SUN6I_ALRM_COUNTER 0x0020
> >> +#define SUN6I_ALRM_CUR_VAL 0x0024
> >> +#define SUN6I_ALRM_EN 0x0028
> >> +#define SUN6I_ALRM_EN_CNT_EN BIT(0)
> >> +#define SUN6I_ALRM_IRQ_EN 0x002c
> >> +#define SUN6I_ALRM_IRQ_EN_CNT_IRQ_EN BIT(0)
> >> +#define SUN6I_ALRM_IRQ_STA 0x0030
> >> +#define SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND BIT(0)
> >> +
> >> +/* Alarm 1 (wall clock) */
> >> +#define SUN6I_ALRM1_EN 0x0044
> >> +#define SUN6I_ALRM1_IRQ_EN 0x0048
> >> +#define SUN6I_ALRM1_IRQ_STA 0x004c
> >> +#define SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND BIT(0)
> >> +
> >> +/* Alarm config */
> >> +#define SUN6I_ALARM_CONFIG 0x0050
> >> +#define SUN6I_ALARM_CONFIG_WAKEUP BIT(0)
> >> +
> >> +/* days / hours are 5 bit wide */
> >> +#define SUN6I_MASK_DH 0x0000001f
> >> +/* seconds / minutes / years are 6 bit wide */
> >> +#define SUN6I_MASK_SMY 0x0000003f
> >> +/* months are 4 bit wide */
> >> +#define SUN6I_MASK_M 0x0000000f
> >> +/* leap year is single bit */
> >> +#define SUN6I_MASK_LY 0x00000001
> >
> > Ditto
>
> See below.
>
> >> +
> >> +#define SUN6I_GET(x, mask, shift) (((x) & ((mask) << (shift))) \
> >> + >> (shift))
> >> +
> >> +#define SUN6I_SET(x, mask, shift) (((x) & (mask)) << (shift))
> >
> > Wouldn't it be easier to have the mask already shifted?
>
> I'll just get rid of these 2 and the masks above, and inline them
> (in hex format) in the GET/SET macros below. How does that sound?
Sounds good to me.
>
> >> +
> >> +/*
> >> + * Get date values
> >> + */
> >> +#define SUN6I_DATE_GET_DAY_VALUE(x) SUN6I_GET(x, SUN6I_MASK_DH, 0)
> >> +#define SUN6I_DATE_GET_MON_VALUE(x) SUN6I_GET(x, SUN6I_MASK_M, 8)
> >> +#define SUN6I_DATE_GET_YEAR_VALUE(x) SUN6I_GET(x, SUN6I_MASK_SMY, 16)
> >> +
> >> +/*
> >> + * Get time values
> >> + */
> >> +#define SUN6I_TIME_GET_SEC_VALUE(x) SUN6I_GET(x, SUN6I_MASK_SMY, 0)
> >> +#define SUN6I_TIME_GET_MIN_VALUE(x) SUN6I_GET(x, SUN6I_MASK_SMY, 8)
> >> +#define SUN6I_TIME_GET_HOUR_VALUE(x) SUN6I_GET(x, SUN6I_MASK_DH, 16)
> >> +
> >> +/*
> >> + * Set date values
> >> + */
> >> +#define SUN6I_DATE_SET_DAY_VALUE(x) SUN6I_DATE_GET_DAY_VALUE(x)
> >> +#define SUN6I_DATE_SET_MON_VALUE(x) SUN6I_SET(x, SUN6I_MASK_M, 8)
> >> +#define SUN6I_DATE_SET_YEAR_VALUE(x) SUN6I_SET(x, SUN6I_MASK_SMY, 16)
> >> +#define SUN6I_LEAP_SET_VALUE(x) SUN6I_SET(x, SUN6I_MASK_LY, 22)
> >> +
> >> +/*
> >> + * Set time values
> >> + */
> >> +#define SUN6I_TIME_SET_SEC_VALUE(x) SUN6I_TIME_GET_SEC_VALUE(x)
> >> +#define SUN6I_TIME_SET_MIN_VALUE(x) SUN6I_SET(x, SUN6I_MASK_SMY, 8)
> >> +#define SUN6I_TIME_SET_HOUR_VALUE(x) SUN6I_SET(x, SUN6I_MASK_DH, 16)
> >> +
> >> +/*
> >> + * The year parameter passed to the driver is usually an offset relative to
> >> + * the year 1900. This macro is used to convert this offset to another one
> >> + * relative to the minimum year allowed by the hardware.
> >> + *
> >> + * The year range is 1970 - 2033. This range is selected to match Allwinner's
> >> + * driver, even though it is somewhat limited.
> >> + */
> >> +#define SUN6I_YEAR_MIN 1970
> >> +#define SUN6I_YEAR_MAX 2033
> >> +#define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900)
> >> +
> >> +struct sun6i_rtc_dev {
> >> + struct rtc_device *rtc;
> >> + struct device *dev;
> >> + void __iomem *base;
> >> + int irq;
> >> + unsigned long alarm;
> >> +};
> >> +
> >> +static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
> >> +{
> >> + struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
> >> + u32 val;
> >> +
> >> + val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
> >> +
> >> + if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
> >> + val |= SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND;
> >> + writel(val, chip->base + SUN6I_ALRM_IRQ_STA);
> >> +
> >> + rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
> >> +
> >> + return IRQ_HANDLED;
> >> + }
> >> +
> >> + return IRQ_NONE;
> >> +}
> >> +
> >> +static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
> >> +{
> >> + u32 alrm_val = 0;
> >> + u32 alrm_irq_val = 0;
> >> + u32 alrm_wake_val = 0;
> >> +
> >> + if (to) {
> >> + alrm_val = SUN6I_ALRM_EN_CNT_EN;
> >> + alrm_irq_val = SUN6I_ALRM_IRQ_EN_CNT_IRQ_EN;
> >> + alrm_wake_val = SUN6I_ALARM_CONFIG_WAKEUP;
> >> + } else {
> >> + writel(SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND,
> >> + chip->base + SUN6I_ALRM_IRQ_STA);
> >> + }
> >> +
> >> + writel(alrm_val, chip->base + SUN6I_ALRM_EN);
> >> + writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
> >> + writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
> >> +}
> >> +
> >> +static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
> >> +{
> >> + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
> >> + u32 date, time;
> >> +
> >> + /*
> >> + * read again in case it changes
> >> + */
> >> + do {
> >> + date = readl(chip->base + SUN6I_RTC_YMD);
> >> + time = readl(chip->base + SUN6I_RTC_HMS);
> >> + } while ((date != readl(chip->base + SUN6I_RTC_YMD)) ||
> >> + (time != readl(chip->base + SUN6I_RTC_HMS)));
> >> +
> >> + rtc_tm->tm_sec = SUN6I_TIME_GET_SEC_VALUE(time);
> >> + rtc_tm->tm_min = SUN6I_TIME_GET_MIN_VALUE(time);
> >> + rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time);
> >> +
> >> + rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date);
> >> + rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date);
> >> + rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date);
> >> +
> >> + rtc_tm->tm_mon -= 1;
> >> +
> >> + /*
> >> + * switch from (data_year->min)-relative offset to
> >> + * a (1900)-relative one
> >> + */
> >
> > I guess the reference to the structure field is not relevant anymore
>
> Removed.
>
> >> + rtc_tm->tm_year += SUN6I_YEAR_OFF;
> >> +
> >> + return rtc_valid_tm(rtc_tm);
> >> +}
> >> +
> >> +static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> >> +{
> >> + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
> >> + u32 alrm_st;
> >> + u32 alrm_en;
> >> +
> >> + alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
> >> + alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
> >> + wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
> >> + wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
> >> + rtc_time_to_tm(chip->alarm, &wkalrm->time);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> >> +{
> >> + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
> >> + struct rtc_time *alrm_tm = &wkalrm->time;
> >> + struct rtc_time tm_now;
> >> + unsigned long time_now = 0;
> >> + unsigned long time_set = 0;
> >> + unsigned long time_gap = 0;
> >> + int ret = 0;
> >> +
> >> + ret = sun6i_rtc_gettime(dev, &tm_now);
> >> + if (ret < 0) {
> >> + dev_err(dev, "Error in getting time\n");
> >> + return -EINVAL;
> >> + }
> >> +
> >> + rtc_tm_to_time(alrm_tm, &time_set);
> >> + rtc_tm_to_time(&tm_now, &time_now);
> >> + if (time_set <= time_now) {
> >> + dev_err(dev, "Date to set in the past\n");
> >> + return -EINVAL;
> >> + }
> >> +
> >> + time_gap = time_set - time_now;
> >> +
> >> + if (time_gap > U32_MAX) {
> >> + dev_err(dev, "Date too far in the future\n");
> >> + return -EINVAL;
> >> + }
> >> +
> >> + sun6i_rtc_setaie(0, chip);
> >> + writel(0, chip->base + SUN6I_ALRM_COUNTER);
> >> + usleep_range(100, 300);
> >> +
> >> + writel(time_gap, chip->base + SUN6I_ALRM_COUNTER);
> >> + chip->alarm = time_set;
> >> +
> >> + sun6i_rtc_setaie(wkalrm->enabled, chip);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int sun6i_rtc_wait(struct sun6i_rtc_dev *chip, int offset,
> >> + unsigned int mask, unsigned int ms_timeout)
> >> +{
> >> + const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout);
> >> + u32 reg;
> >> +
> >> + do {
> >> + reg = readl(chip->base + offset);
> >> + reg &= mask;
> >> +
> >> + if (!reg)
> >> + return 0;
> >> +
> >> + } while (time_before(jiffies, timeout));
> >> +
> >> + return -ETIMEDOUT;
> >> +}
> >> +
> >> +static int sun6i_rtc_settime(struct device *dev, struct rtc_time *rtc_tm)
> >> +{
> >> + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
> >> + u32 date = 0;
> >> + u32 time = 0;
> >> + int year;
> >> +
> >> + /*
> >> + * the input rtc_tm->tm_year is the offset relative to 1900. We use
> >> + * the SUN6I_YEAR_OFF macro to rebase it with respect to the min year
> >> + * allowed by the hardware
> >> + */
> >> +
> >> + year = rtc_tm->tm_year + 1900;
> >> + if (year < SUN6I_YEAR_MIN || year > SUN6I_YEAR_MAX) {
> >> + dev_err(dev, "rtc only supports year in range %d - %d\n",
> >> + SUN6I_YEAR_MIN, SUN6I_YEAR_MAX);
> >> + return -EINVAL;
> >> + }
> >> +
> >> + rtc_tm->tm_year -= SUN6I_YEAR_OFF;
> >> + rtc_tm->tm_mon += 1;
> >> +
> >> + date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) |
> >> + SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) |
> >> + SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year);
> >> +
> >> + if (is_leap_year(year))
> >> + date |= SUN6I_LEAP_SET_VALUE(1);
> >> +
> >> + time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) |
> >> + SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min) |
> >> + SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour);
> >> +
> >> + /* Check whether registers are writable */
> >> + if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL,
> >> + SUN6I_LOSC_CTRL_ACC_MASK, 50)) {
> >> + dev_err(dev, "rtc is still busy.\n");
> >> + return -EBUSY;
> >> + }
> >> +
> >> + writel(time, chip->base + SUN6I_RTC_HMS);
> >> +
> >> + /*
> >> + * After writing the RTC HH-MM-SS register, the
> >> + * SUN6I_LOSC_CTRL_RTC_HMS_ACC bit is set and it will not
> >> + * be cleared until the real writing operation is finished
> >> + */
> >> +
> >> + if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL,
> >> + SUN6I_LOSC_CTRL_RTC_HMS_ACC, 50)) {
> >> + dev_err(dev, "Failed to set rtc time.\n");
> >> + return -ETIMEDOUT;
> >> + }
> >> +
> >> + writel(date, chip->base + SUN6I_RTC_YMD);
> >> +
> >> + /*
> >> + * After writing the RTC YY-MM-DD register, the
> >> + * SUN6I_LOSC_CTRL_RTC_YMD_ACC bit is set and it will not
> >> + * be cleared until the real writing operation is finished
> >> + */
> >> +
> >> + if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL,
> >> + SUN6I_LOSC_CTRL_RTC_YMD_ACC, 50)) {
> >> + dev_err(dev, "Failed to set rtc time.\n");
> >> + return -ETIMEDOUT;
> >> + }
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int sun6i_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> >> +{
> >> + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
> >> +
> >> + if (!enabled)
> >> + sun6i_rtc_setaie(enabled, chip);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static const struct rtc_class_ops sun6i_rtc_ops = {
> >> + .read_time = sun6i_rtc_gettime,
> >> + .set_time = sun6i_rtc_settime,
> >> + .read_alarm = sun6i_rtc_getalarm,
> >> + .set_alarm = sun6i_rtc_setalarm,
> >> + .alarm_irq_enable = sun6i_rtc_alarm_irq_enable
> >> +};
> >> +
> >> +static const struct of_device_id sun6i_rtc_dt_ids[] = {
> >> + { .compatible = "allwinner,sun6i-a31-rtc" },
> >> + { /* sentinel */ },
> >> +};
> >> +MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
> >
> > I guess you can move this down just before the platform_driver
> > declaration if you don't need it in probe.
>
> Moved.
>
> >> +
> >> +static int sun6i_rtc_probe(struct platform_device *pdev)
> >> +{
> >> + struct sun6i_rtc_dev *chip;
> >> + struct resource *res;
> >> + int ret;
> >> +
> >> + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> >> + if (!chip)
> >> + return -ENOMEM;
> >> +
> >> + platform_set_drvdata(pdev, chip);
> >> + chip->dev = &pdev->dev;
> >> +
> >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> + chip->base = devm_ioremap_resource(&pdev->dev, res);
> >> + if (IS_ERR(chip->base))
> >> + return PTR_ERR(chip->base);
> >> +
> >> + chip->irq = platform_get_irq(pdev, 0);
> >> + if (chip->irq < 0) {
> >> + dev_err(&pdev->dev, "No IRQ resource\n");
> >> + return chip->irq;
> >> + }
> >
> > Newline
>
> Added.
>
> >> + ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
> >> + 0, dev_name(&pdev->dev), chip);
> >> + if (ret) {
> >> + dev_err(&pdev->dev, "Could not request IRQ\n");
> >> + return ret;
> >> + }
> >> +
> >> + /* clear the alarm counter value */
> >> + writel(0, chip->base + SUN6I_ALRM_COUNTER);
> >> +
> >> + /* disable counter alarm */
> >> + writel(0, chip->base + SUN6I_ALRM_EN);
> >> +
> >> + /* disable counter alarm interrupt */
> >> + writel(0, chip->base + SUN6I_ALRM_IRQ_EN);
> >> +
> >> + /* disable week alarm */
> >> + writel(0, chip->base + SUN6I_ALRM1_EN);
> >> +
> >> + /* disable week alarm interrupt */
> >> + writel(0, chip->base + SUN6I_ALRM1_IRQ_EN);
> >> +
> >> + /* clear counter alarm pending interrupts */
> >> + writel(SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base +
> >> + SUN6I_ALRM_IRQ_STA);
> >> +
> >> + /* clear week alarm pending interrupts */
> >> + writel(SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND, chip->base +
> >> + SUN6I_ALRM1_IRQ_STA);
> >> +
> >> + /* disable alarm wakeup */
> >> + writel(0, chip->base + SUN6I_ALARM_CONFIG);
> >> +
> >> + chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
> >> + &sun6i_rtc_ops, THIS_MODULE);
> >> + if (IS_ERR(chip->rtc)) {
> >> + dev_err(&pdev->dev, "unable to register device\n");
> >> + return PTR_ERR(chip->rtc);
> >> + }
> >> +
> >> + dev_info(&pdev->dev, "RTC enabled\n");
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int sun6i_rtc_remove(struct platform_device *pdev)
> >> +{
> >> + struct sun6i_rtc_dev *chip = platform_get_drvdata(pdev);
> >> +
> >> + rtc_device_unregister(chip->rtc);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static struct platform_driver sun6i_rtc_driver = {
> >> + .probe = sun6i_rtc_probe,
> >> + .remove = sun6i_rtc_remove,
> >> + .driver = {
> >> + .name = "sun6i-rtc",
> >> + .owner = THIS_MODULE,
> >> + .of_match_table = sun6i_rtc_dt_ids,
> >> + },
> >> +};
> >> +
> >> +module_platform_driver(sun6i_rtc_driver);
> >> +
> >> +MODULE_DESCRIPTION("sun6i RTC driver");
> >> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
> >> +MODULE_LICENSE("GPL");
> >> --
> >> 2.0.1
> >>
> >
> > Thanks!
> > Maxime
>
> Thanks for the review!
> ChenYu
Thanks for your efforts on this,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140723/136b332c/attachment.sig>
^ permalink raw reply
* [PATCH v14 01/11] irq: gic: support hip04 gic
From: Haojian Zhuang @ 2014-07-23 9:55 UTC (permalink / raw)
To: linux-arm-kernel
There's some difference between ARM GICv2 and HiP04 GIC.
* HiP04 GIC could support 16 cores at most, and ARM GIC could support
8 cores at most. So the defination on GIC_DIST_TARGET registers are
different since CPU interfaces are increased from 8-bit to 16-bit.
* HiP04 GIC could support 510 interrupts at most, and ARM GIC could
support 1020 interrupts at most.
Changelog:
v14:
* Mount function pointers to different implementation on standard
GICv2 and Hisilicon HiP04 GIC.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
Documentation/devicetree/bindings/arm/gic.txt | 1 +
drivers/irqchip/irq-gic.c | 436 +++++++++++++++++++++-----
2 files changed, 350 insertions(+), 87 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 5573c08..150f7d6 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -16,6 +16,7 @@ Main node required properties:
"arm,cortex-a9-gic"
"arm,cortex-a7-gic"
"arm,arm11mp-gic"
+ "hisilicon,hip04-gic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The type shall be a <u32> and the value shall be 3.
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 508b815..b47243f 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -69,19 +69,23 @@ struct gic_chip_data {
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
#endif
+ void (*init_cpu_map)(void);
+ u32 (*get_cpu_map)(u32);
+ void (*set_cpu_map)(u32, u32);
+ bool (*cpu_invalid)(u32);
+ u32 (*get_cpumask)(struct gic_chip_data *);
+ void (*set_dist_target)(struct gic_chip_data *, u32, u32);
+ void (*set_dist_softint)(struct gic_chip_data *, u32, u32);
+ void (*dist_init)(struct gic_chip_data *);
+ void (*dist_save)(unsigned int);
+ void (*dist_restore)(unsigned int);
+ u32 nr_cpu_if;
+ u32 max_nr_irq;
};
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
/*
- * The GIC mapping of CPU interfaces does not necessarily match
- * the logical CPU numbering. Let's use a mapping as returned
- * by the GIC itself.
- */
-#define NR_GIC_CPU_IF 8
-static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
-
-/*
* Supported arch specific GIC irq extension.
* Default make them NULL.
*/
@@ -222,23 +226,21 @@ static int gic_retrigger(struct irq_data *d)
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force)
{
- void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
- unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
- u32 val, mask, bit;
+ struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+ unsigned int cpu;
+ u32 bit;
if (!force)
cpu = cpumask_any_and(mask_val, cpu_online_mask);
else
cpu = cpumask_first(mask_val);
- if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
+ if (gic_data->cpu_invalid(cpu) || cpu >= nr_cpu_ids)
return -EINVAL;
raw_spin_lock(&irq_controller_lock);
- mask = 0xff << shift;
- bit = gic_cpu_map[cpu] << shift;
- val = readl_relaxed(reg) & ~mask;
- writel_relaxed(val | bit, reg);
+ bit = gic_data->get_cpu_map(cpu);
+ gic_data->set_dist_target(gic_data, gic_irq(d), bit);
raw_spin_unlock(&irq_controller_lock);
return IRQ_SET_MASK_OK;
@@ -304,7 +306,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
goto out;
cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
- if (unlikely(gic_irq < 32 || gic_irq > 1020))
+ if (unlikely(gic_irq < 32 || gic_irq > chip_data->max_nr_irq))
handle_bad_irq(cascade_irq, desc);
else
generic_handle_irq(cascade_irq);
@@ -335,69 +337,31 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
-static u8 gic_get_cpumask(struct gic_chip_data *gic)
-{
- void __iomem *base = gic_data_dist_base(gic);
- u32 mask, i;
-
- for (i = mask = 0; i < 32; i += 4) {
- mask = readl_relaxed(base + GIC_DIST_TARGET + i);
- mask |= mask >> 16;
- mask |= mask >> 8;
- if (mask)
- break;
- }
-
- if (!mask)
- pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
-
- return mask;
-}
-
-static void __init gic_dist_init(struct gic_chip_data *gic)
-{
- unsigned int i;
- u32 cpumask;
- unsigned int gic_irqs = gic->gic_irqs;
- void __iomem *base = gic_data_dist_base(gic);
-
- writel_relaxed(0, base + GIC_DIST_CTRL);
-
- /*
- * Set all global interrupts to this CPU only.
- */
- cpumask = gic_get_cpumask(gic);
- cpumask |= cpumask << 8;
- cpumask |= cpumask << 16;
- for (i = 32; i < gic_irqs; i += 4)
- writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
-
- gic_dist_config(base, gic_irqs, NULL);
-
- writel_relaxed(1, base + GIC_DIST_CTRL);
-}
-
static void gic_cpu_init(struct gic_chip_data *gic)
{
void __iomem *dist_base = gic_data_dist_base(gic);
void __iomem *base = gic_data_cpu_base(gic);
unsigned int cpu_mask, cpu = smp_processor_id();
int i;
+ u32 data;
/*
* Get what the GIC says our CPU mask is.
*/
- BUG_ON(cpu >= NR_GIC_CPU_IF);
- cpu_mask = gic_get_cpumask(gic);
- gic_cpu_map[cpu] = cpu_mask;
+ BUG_ON(gic->cpu_invalid(cpu));
+ cpu_mask = gic->get_cpumask(gic);
+ gic->set_cpu_map(cpu, cpu_mask);
/*
* Clear our mask from the other map entries in case they're
* still undefined.
*/
- for (i = 0; i < NR_GIC_CPU_IF; i++)
- if (i != cpu)
- gic_cpu_map[i] &= ~cpu_mask;
+ for (i = 0; i < gic->nr_cpu_if; i++) {
+ if (i != cpu) {
+ data = gic->get_cpu_map(i);
+ gic->set_cpu_map(i, data & ~cpu_mask);
+ }
+ }
gic_cpu_config(dist_base, NULL);
@@ -489,6 +453,70 @@ static void gic_dist_restore(unsigned int gic_nr)
writel_relaxed(1, dist_base + GIC_DIST_CTRL);
}
+static void hip04_dist_save(unsigned int gic_nr)
+{
+ unsigned int gic_irqs;
+ void __iomem *dist_base;
+ int i;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_irqs = gic_data[gic_nr].gic_irqs;
+ dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+
+ if (!dist_base)
+ return;
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+ gic_data[gic_nr].saved_spi_conf[i] =
+ readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 2); i++)
+ gic_data[gic_nr].saved_spi_target[i] =
+ readl_relaxed(dist_base + GIC_DIST_TARGET + i * 2);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ gic_data[gic_nr].saved_spi_enable[i] =
+ readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+}
+
+static void hip04_dist_restore(unsigned int gic_nr)
+{
+ unsigned int gic_irqs;
+ unsigned int i;
+ void __iomem *dist_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_irqs = gic_data[gic_nr].gic_irqs;
+ dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+
+ if (!dist_base)
+ return;
+
+ writel_relaxed(0, dist_base + GIC_DIST_CTRL);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
+ dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ writel_relaxed(0xa0a0a0a0,
+ dist_base + GIC_DIST_PRI + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 2); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
+ dist_base + GIC_DIST_TARGET + i * 2);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
+ dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+}
+
static void gic_cpu_save(unsigned int gic_nr)
{
int i;
@@ -565,11 +593,11 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
gic_cpu_restore(i);
break;
case CPU_CLUSTER_PM_ENTER:
- gic_dist_save(i);
+ gic_data[i].dist_save(i);
break;
case CPU_CLUSTER_PM_ENTER_FAILED:
case CPU_CLUSTER_PM_EXIT:
- gic_dist_restore(i);
+ gic_data[i].dist_restore(i);
break;
}
}
@@ -610,7 +638,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
- map |= gic_cpu_map[cpu];
+ map |= gic_data[0].get_cpu_map(cpu);
/*
* Ensure that stores to Normal memory are visible to the
@@ -619,7 +647,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
dmb(ishst);
/* this always happens on GIC0 */
- writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+ gic_data[0].set_dist_softint(&gic_data[0], irq, map);
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
@@ -634,10 +662,9 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
*/
void gic_send_sgi(unsigned int cpu_id, unsigned int irq)
{
- BUG_ON(cpu_id >= NR_GIC_CPU_IF);
- cpu_id = 1 << cpu_id;
+ BUG_ON(gic_data[0].cpu_invalid(cpu_id));
/* this always happens on GIC0 */
- writel_relaxed((cpu_id << 16) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+ gic_data[0].set_dist_softint(&gic_data[0], irq, 1 << cpu_id);
}
/*
@@ -653,9 +680,9 @@ int gic_get_cpu_id(unsigned int cpu)
{
unsigned int cpu_bit;
- if (cpu >= NR_GIC_CPU_IF)
+ if (gic_data[0].cpu_invalid(cpu))
return -1;
- cpu_bit = gic_cpu_map[cpu];
+ cpu_bit = gic_data[0].get_cpu_map(cpu);
if (cpu_bit & (cpu_bit - 1))
return -1;
return __ffs(cpu_bit);
@@ -673,6 +700,7 @@ int gic_get_cpu_id(unsigned int cpu)
*/
void gic_migrate_target(unsigned int new_cpu_id)
{
+ struct gic_chip_data *gic = &gic_data[gic_nr];
unsigned int cur_cpu_id, gic_irqs, gic_nr = 0;
void __iomem *dist_base;
int i, ror_val, cpu = smp_processor_id();
@@ -681,19 +709,19 @@ void gic_migrate_target(unsigned int new_cpu_id)
if (gic_nr >= MAX_GIC_NR)
BUG();
- dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+ dist_base = gic_data_dist_base(gic);
if (!dist_base)
return;
- gic_irqs = gic_data[gic_nr].gic_irqs;
+ gic_irqs = gic->gic_irqs;
- cur_cpu_id = __ffs(gic_cpu_map[cpu]);
+ cur_cpu_id = __ffs(gic->get_cpu_map(cpu));
cur_target_mask = 0x01010101 << cur_cpu_id;
ror_val = (cur_cpu_id - new_cpu_id) & 31;
raw_spin_lock(&irq_controller_lock);
/* Update the target interface for this logical CPU */
- gic_cpu_map[cpu] = 1 << new_cpu_id;
+ gic_data->set_cpu_map(cpu, 1 << new_cpu_id);
/*
* Find all the peripheral interrupts targetting the current
@@ -730,8 +758,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i);
for (j = i; j < i + 4; j++) {
if (val & 0xff)
- writel_relaxed((1 << (new_cpu_id + 16)) | j,
- dist_base + GIC_DIST_SOFTINT);
+ gic->set_dist_softint(gic, j, 1 << new_cpu_id);
val >>= 8;
}
}
@@ -883,7 +910,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
{
irq_hw_number_t hwirq_base;
struct gic_chip_data *gic;
- int gic_irqs, irq_base, i;
+ int gic_irqs, irq_base;
int nr_routable_irqs;
BUG_ON(gic_nr >= MAX_GIC_NR);
@@ -924,8 +951,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
* Initialize the CPU interface map to all CPUs.
* It will be refined as each CPU probes its ID.
*/
- for (i = 0; i < NR_GIC_CPU_IF; i++)
- gic_cpu_map[i] = 0xff;
+ gic->init_cpu_map();
/*
* For primary GICs, skip over SGIs.
@@ -941,12 +967,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
/*
* Find out how many interrupts are supported.
- * The GIC only supports up to 1020 interrupt sources.
+ * The ARM/Qualcomm GIC only supports up to 1020 interrupt sources.
+ * The HiP04 GIC only supports up to 510 interrupt sources.
*/
gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
gic_irqs = (gic_irqs + 1) * 32;
- if (gic_irqs > 1020)
- gic_irqs = 1020;
+ if (gic_irqs > gic->max_nr_irq)
+ gic_irqs = gic->max_nr_irq;
gic->gic_irqs = gic_irqs;
gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
@@ -981,7 +1008,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
}
gic_chip.flags |= gic_arch_extn.flags;
- gic_dist_init(gic);
+ gic->dist_init(gic);
gic_cpu_init(gic);
gic_pm_init(gic);
}
@@ -989,6 +1016,98 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
#ifdef CONFIG_OF
static int gic_cnt __initdata;
+/*
+ * The GIC mapping of CPU interfaces does not necessarily match
+ * the logical CPU numbering. Let's use a mapping as returned
+ * by the GIC itself.
+ */
+#define NR_GIC_CPU_IF 8
+static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
+
+static void gic_init_cpu_map(void)
+{
+ int i;
+ for (i = 0; i < NR_GIC_CPU_IF; i++)
+ gic_cpu_map[i] = 0xff;
+}
+
+static u32 gic_get_cpu_map(u32 i)
+{
+ return gic_cpu_map[i];
+}
+
+static void gic_set_cpu_map(u32 i, u32 data)
+{
+ gic_cpu_map[i] = data & 0xff;
+}
+
+static bool gic_cpu_invalid(u32 cpu)
+{
+ return cpu >= NR_GIC_CPU_IF;
+}
+
+static u32 gic_get_cpumask(struct gic_chip_data *gic)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+ u32 mask, i;
+
+ for (i = mask = 0; i < 32; i += 4) {
+ mask = readl_relaxed(base + GIC_DIST_TARGET + i);
+ mask |= mask >> 16;
+ mask |= mask >> 8;
+ if (mask)
+ break;
+ }
+
+ if (!mask)
+ pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
+
+ return mask & 0xff;
+}
+
+static void gic_set_dist_target(struct gic_chip_data *gic, u32 irq, u32 data)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+ u32 val, mask, offset, shift = (irq % 4) * 8;
+
+ mask = 0xff << shift;
+ offset = irq & ~3U;
+ val = readl_relaxed(base + GIC_DIST_TARGET + offset) & ~mask;
+ val |= data << shift;
+ writel_relaxed(val, base + GIC_DIST_TARGET + offset);
+}
+
+static void gic_set_dist_softint(struct gic_chip_data *gic, u32 irq, u32 data)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+
+ data = data << 16;
+ writel_relaxed(data | irq, base + GIC_DIST_SOFTINT);
+}
+
+static void gic_dist_init(struct gic_chip_data *gic)
+{
+ unsigned int i;
+ u32 cpumask;
+ unsigned int gic_irqs = gic->gic_irqs;
+ void __iomem *base = gic_data_dist_base(gic);
+
+ writel_relaxed(0, base + GIC_DIST_CTRL);
+
+ /*
+ * Set all global interrupts to this CPU only.
+ */
+ cpumask = gic_get_cpumask(gic);
+ cpumask |= cpumask << 8;
+ cpumask |= cpumask << 16;
+ for (i = 32; i < gic_irqs; i += 4)
+ writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
+
+ gic_dist_config(base, gic_irqs, NULL);
+
+ writel_relaxed(1, base + GIC_DIST_CTRL);
+}
+
static int __init
gic_of_init(struct device_node *node, struct device_node *parent)
{
@@ -1009,6 +1128,148 @@ gic_of_init(struct device_node *node, struct device_node *parent)
if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
percpu_offset = 0;
+ gic_data[gic_cnt].nr_cpu_if = 8;
+ gic_data[gic_cnt].init_cpu_map = gic_init_cpu_map;
+ gic_data[gic_cnt].get_cpu_map = gic_get_cpu_map;
+ gic_data[gic_cnt].set_cpu_map = gic_set_cpu_map;
+ gic_data[gic_cnt].cpu_invalid = gic_cpu_invalid;
+ gic_data[gic_cnt].get_cpumask = gic_get_cpumask;
+ gic_data[gic_cnt].dist_init = gic_dist_init;
+ gic_data[gic_cnt].dist_save = gic_dist_save;
+ gic_data[gic_cnt].dist_restore = gic_dist_restore;
+ gic_data[gic_cnt].set_dist_target = gic_set_dist_target;
+ gic_data[gic_cnt].set_dist_softint = gic_set_dist_softint;
+ gic_data[gic_cnt].max_nr_irq = 1020;
+ gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
+ if (!gic_cnt)
+ gic_init_physaddr(node);
+
+ if (parent) {
+ irq = irq_of_parse_and_map(node, 0);
+ gic_cascade_irq(gic_cnt, irq);
+ }
+ gic_cnt++;
+ return 0;
+}
+
+/* HiP04 extends the number of CPU interface from 8 to 16 */
+#define NR_HIP04_CPU_IF 16
+static u16 hip04_cpu_map[NR_HIP04_CPU_IF] __read_mostly;
+
+static void hip04_init_cpu_map(void)
+{
+ int i;
+ for (i = 0; i < NR_HIP04_CPU_IF; i++)
+ hip04_cpu_map[i] = 0xffff;
+}
+
+static u32 hip04_get_cpu_map(u32 i)
+{
+ return hip04_cpu_map[i];
+}
+
+static void hip04_set_cpu_map(u32 i, u32 data)
+{
+ hip04_cpu_map[i] = data & 0xffff;
+}
+
+static bool hip04_cpu_invalid(u32 cpu)
+{
+ return cpu >= NR_HIP04_CPU_IF;
+}
+
+static u32 hip04_get_cpumask(struct gic_chip_data *gic)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+ u32 mask, i;
+
+ for (i = mask = 0; i < 32; i += 2) {
+ mask = readl_relaxed(base + GIC_DIST_TARGET + i * 2);
+ mask |= mask >> 16;
+ if (mask)
+ break;
+ }
+
+ if (!mask)
+ pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
+
+ return mask & 0xffff;
+}
+
+static void hip04_set_dist_target(struct gic_chip_data *gic, u32 irq, u32 data)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+ u32 val, mask, offset, shift = (irq % 2) * 16;
+
+ mask = 0xffff << shift;
+ offset = (irq * 2) & ~3U;
+ val = readl_relaxed(base + GIC_DIST_TARGET + offset) & ~mask;
+ val |= data << shift;
+ writel_relaxed(val, base + GIC_DIST_TARGET + offset);
+}
+
+static void hip04_set_dist_softint(struct gic_chip_data *gic, u32 irq, u32 data)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+
+ data = data << 8;
+ writel_relaxed(data | irq, base + GIC_DIST_SOFTINT);
+}
+
+static void hip04_dist_init(struct gic_chip_data *gic)
+{
+ unsigned int i;
+ u32 cpumask;
+ unsigned int gic_irqs = gic->gic_irqs;
+ void __iomem *base = gic_data_dist_base(gic);
+
+ writel_relaxed(0, base + GIC_DIST_CTRL);
+
+ /*
+ * Set all global interrupts to this CPU only.
+ */
+ cpumask = hip04_get_cpumask(gic);
+ cpumask |= cpumask << 16;
+ for (i = 32; i < gic_irqs; i += 2)
+ writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 2);
+
+ gic_dist_config(base, gic_irqs, NULL);
+
+ writel_relaxed(1, base + GIC_DIST_CTRL);
+}
+
+static int __init
+hip04_of_init(struct device_node *node, struct device_node *parent)
+{
+ void __iomem *cpu_base;
+ void __iomem *dist_base;
+ u32 percpu_offset;
+ int irq;
+
+ if (WARN_ON(!node))
+ return -ENODEV;
+
+ dist_base = of_iomap(node, 0);
+ WARN(!dist_base, "unable to map gic dist registers\n");
+
+ cpu_base = of_iomap(node, 1);
+ WARN(!cpu_base, "unable to map gic cpu registers\n");
+
+ if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
+ percpu_offset = 0;
+
+ gic_data[gic_cnt].nr_cpu_if = 16;
+ gic_data[gic_cnt].init_cpu_map = hip04_init_cpu_map;
+ gic_data[gic_cnt].get_cpu_map = hip04_get_cpu_map;
+ gic_data[gic_cnt].set_cpu_map = hip04_set_cpu_map;
+ gic_data[gic_cnt].cpu_invalid = hip04_cpu_invalid;
+ gic_data[gic_cnt].get_cpumask = hip04_get_cpumask;
+ gic_data[gic_cnt].dist_init = hip04_dist_init;
+ gic_data[gic_cnt].dist_save = hip04_dist_save;
+ gic_data[gic_cnt].dist_restore = hip04_dist_restore;
+ gic_data[gic_cnt].set_dist_target = hip04_set_dist_target;
+ gic_data[gic_cnt].set_dist_softint = hip04_set_dist_softint;
+ gic_data[gic_cnt].max_nr_irq = 510;
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
if (!gic_cnt)
gic_init_physaddr(node);
@@ -1022,6 +1283,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
}
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
+IRQCHIP_DECLARE(hip04_gic, "hisilicon,hip04-gic", hip04_of_init);
IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
--
1.9.1
^ permalink raw reply related
* [PATCH v5 1/2] i2c: add DMA support for freescale i2c driver
From: Lothar Waßmann @ 2014-07-23 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1406103883-3572-2-git-send-email-yao.yuan@freescale.com>
Hi,
Yuan Yao wrote:
> Add dma support for i2c. This function depend on DMA driver.
> You can turn on it by write both the dmas and dma-name properties in dts node.
>
> Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
> ---
> drivers/i2c/busses/i2c-imx.c | 377 +++++++++++++++++++++++++++++++++++++------
> 1 file changed, 324 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
> index 1d7efa3..a9893c3 100644
> --- a/drivers/i2c/busses/i2c-imx.c
> +++ b/drivers/i2c/busses/i2c-imx.c
> @@ -37,22 +37,27 @@
> /** Includes *******************************************************************
> *******************************************************************************/
>
> -#include <linux/init.h>
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dmapool.h>
> #include <linux/errno.h>
> #include <linux/err.h>
> #include <linux/interrupt.h>
> -#include <linux/delay.h>
> #include <linux/i2c.h>
> +#include <linux/init.h>
> #include <linux/io.h>
> -#include <linux/sched.h>
> -#include <linux/platform_device.h>
> -#include <linux/clk.h>
> -#include <linux/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> #include <linux/of.h>
> #include <linux/of_device.h>
> +#include <linux/of_dma.h>
> #include <linux/platform_data/i2c-imx.h>
> +#include <linux/platform_device.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
>
> /** Defines ********************************************************************
> *******************************************************************************/
> @@ -63,6 +68,10 @@
> /* Default value */
> #define IMX_I2C_BIT_RATE 100000 /* 100kHz */
>
> +/* enable DMA if transfer byte size is bigger than this threshold */
> +#define IMX_I2C_DMA_THRESHOLD 16
> +#define IMX_I2C_DMA_TIMEOUT 1000
> +
> /* IMX I2C registers:
> * the I2C register offset is different between SoCs,
> * to provid support for all these chips, split the
> @@ -88,6 +97,7 @@
> #define I2SR_IBB 0x20
> #define I2SR_IAAS 0x40
> #define I2SR_ICF 0x80
> +#define I2CR_DMAEN 0x02
> #define I2CR_RSTA 0x04
> #define I2CR_TXAK 0x08
> #define I2CR_MTX 0x10
> @@ -174,6 +184,17 @@ struct imx_i2c_hwdata {
> unsigned i2cr_ien_opcode;
> };
>
> +struct imx_i2c_dma {
> + struct dma_chan *chan_tx;
> + struct dma_chan *chan_rx;
> + struct dma_chan *chan_using;
> + struct completion cmd_complete;
> + dma_addr_t dma_buf;
> + unsigned int dma_len;
> + unsigned int dma_transfer_dir;
> + unsigned int dma_data_dir;
> +};
> +
> struct imx_i2c_struct {
> struct i2c_adapter adapter;
> struct clk *clk;
> @@ -184,6 +205,8 @@ struct imx_i2c_struct {
> int stopped;
> unsigned int ifdr; /* IMX_I2C_IFDR */
> const struct imx_i2c_hwdata *hwdata;
> +
> + struct imx_i2c_dma *dma;
> };
>
> static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
> @@ -254,6 +277,133 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
> return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
> }
>
> +/* Functions for DMA support */
> +static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
> + dma_addr_t phy_addr)
> +{
> + struct imx_i2c_dma *dma;
> + struct dma_slave_config dma_sconfig;
> + struct device *dev = &i2c_imx->adapter.dev;
> + int ret;
> +
> + dma = devm_kzalloc(dev, sizeof(struct imx_i2c_dma), GFP_KERNEL);
> + if (!dma) {
> + dev_info(dev, "can't allocate DMA struct\n");
>
dev_err() is designated to print ERROR messages, though this message
could well be eliminated as the memory subsystem will be noisy enough
if the allocation failed.
> + return -ENOMEM;
> + }
> +
> + dma->chan_tx = dma_request_slave_channel(dev, "tx");
> +
> + if (!dma->chan_tx) {
> + dev_info(dev, "DMA tx channel request failed\n");
>
dev_err()
> + ret = -ENODEV;
> + goto fail_al;
> + }
> +
> + dma_sconfig.dst_addr = phy_addr +
> + (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
> + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> + dma_sconfig.dst_maxburst = 1;
> + dma_sconfig.direction = DMA_MEM_TO_DEV;
> + ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
> + if (ret < 0) {
> + dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>
dev_err()
> + goto fail_tx;
> + }
> +
> + dma->chan_rx = dma_request_slave_channel(dev, "rx");
> + if (!dma->chan_rx) {
> + dev_info(dev, "DMA rx channel request failed\n");
>
dev_err()
> + ret = -ENODEV;
> + goto fail_tx;
> + }
> +
> + dma_sconfig.src_addr = phy_addr +
> + (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
> + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> + dma_sconfig.src_maxburst = 1;
> + dma_sconfig.direction = DMA_DEV_TO_MEM;
> + ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
> + if (ret < 0) {
> + dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>
dev_err()
> + goto fail_rx;
> + }
> +
> + i2c_imx->dma = dma;
> +
> + init_completion(&dma->cmd_complete);
> +
> + return 0;
> +
> +fail_rx:
> + dma_release_channel(dma->chan_rx);
> +fail_tx:
> + dma_release_channel(dma->chan_tx);
> +fail_al:
> + devm_kfree(dev, dma);
>
No need for this one (that's the whole point of using devm_kzalloc())!
> + return ret;
> +}
> +
> +static void i2c_imx_dma_callback(void *arg)
> +{
> + struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg;
> + struct imx_i2c_dma *dma = i2c_imx->dma;
> +
> + dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
> + dma->dma_len, dma->dma_data_dir);
> + complete(&dma->cmd_complete);
> +}
> +
> +static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
> + struct i2c_msg *msgs)
> +{
> + struct imx_i2c_dma *dma = i2c_imx->dma;
> + struct dma_async_tx_descriptor *txdesc;
> + struct device *dev = &i2c_imx->adapter.dev;
> + struct device *chan_dev = dma->chan_using->device->dev;
> +
> + dma->dma_buf = dma_map_single(chan_dev, msgs->buf,
> + dma->dma_len, dma->dma_data_dir);
> + if (dma_mapping_error(chan_dev, dma->dma_buf)) {
> + dev_err(dev, "DMA mapping failed\n");
> + return -EINVAL;
> + }
> +
> + txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
> + dma->dma_len, dma->dma_transfer_dir,
> + DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> + if (!txdesc) {
> + dev_err(dev, "Not able to get desc for DMA xfer\n");
>
s/Not able/Unable/
> + dma_unmap_single(chan_dev, dma->dma_buf,
> + dma->dma_len, dma->dma_data_dir);
> + return -EINVAL;
> + }
> +
> + txdesc->callback = i2c_imx_dma_callback;
> + txdesc->callback_param = i2c_imx;
> + dmaengine_submit(txdesc);
> + dma_async_issue_pending(dma->chan_using);
> +
> + return 0;
> +}
> +
> +static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
> +{
> + struct imx_i2c_dma *dma = i2c_imx->dma;
> +
> + dma->dma_buf = 0;
> + dma->dma_len = 0;
> +
> + dma_release_channel(dma->chan_tx);
> + dma->chan_tx = NULL;
> +
> + dma_release_channel(dma->chan_rx);
> + dma->chan_rx = NULL;
> +
> + dma->chan_using = NULL;
> +}
> +
> /** Functions for IMX I2C adapter driver ***************************************
> *******************************************************************************/
>
> @@ -332,6 +482,11 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
>
> temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
> imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>
Why reread the register you have written just before?
> + temp &= ~I2CR_DMAEN;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +
> return result;
> }
>
> @@ -425,44 +580,104 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
>
> static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
> {
> - int i, result;
> + int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
> + unsigned int temp = 0;
> + struct imx_i2c_dma *dma = i2c_imx->dma;
> + struct device *dev = &i2c_imx->adapter.dev;
>
> - dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
> + dev_dbg(dev, "<%s> write slave address: addr=0x%x\n",
> __func__, msgs->addr << 1);
> + if (dma && msgs->len >= IMX_I2C_DMA_THRESHOLD) {
> + reinit_completion(&i2c_imx->dma->cmd_complete);
> + dma->chan_using = dma->chan_tx;
> + dma->dma_transfer_dir = DMA_MEM_TO_DEV;
> + dma->dma_data_dir = DMA_TO_DEVICE;
> + dma->dma_len = msgs->len - 1;
> + result = i2c_imx_dma_xfer(i2c_imx, msgs);
> + if (result)
> + return result;
>
> - /* write slave address */
> - imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
> - result = i2c_imx_trx_complete(i2c_imx);
> - if (result)
> - return result;
> - result = i2c_imx_acked(i2c_imx);
> - if (result)
> - return result;
> - dev_dbg(&i2c_imx->adapter.dev, "<%s> write data\n", __func__);
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + temp |= I2CR_DMAEN;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>
> - /* write data */
> - for (i = 0; i < msgs->len; i++) {
> - dev_dbg(&i2c_imx->adapter.dev,
> - "<%s> write byte: B%d=0x%X\n",
> - __func__, i, msgs->buf[i]);
> - imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
> + /*
> + * Write slave address.
> + * The first byte muse be transmitted by the CPU.
> + */
> + imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
> + result = wait_for_completion_interruptible_timeout(
> + &i2c_imx->dma->cmd_complete,
> + msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
> + if (result <= 0) {
> + dmaengine_terminate_all(dma->chan_using);
> + if (result)
> + return result;
> + else
> + return -ETIMEDOUT;
> + }
> +
> + /* Waiting for Transfer complete. */
> + while (timeout--) {
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
> + if (temp & I2SR_ICF)
> + break;
> + udelay(10);
> + }
> +
> + if (!timeout)
> + return -ETIMEDOUT;
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + temp &= ~I2CR_DMAEN;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +
> + /* The last data byte must be transferred by the CPU. */
> + imx_i2c_write_reg(msgs->buf[msgs->len-1],
> + i2c_imx, IMX_I2C_I2DR);
> result = i2c_imx_trx_complete(i2c_imx);
> if (result)
> return result;
> +
> result = i2c_imx_acked(i2c_imx);
> if (result)
> return result;
> + } else {
> + /* write slave address */
> + imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
> + result = i2c_imx_trx_complete(i2c_imx);
> + if (result)
> + return result;
> +
> + result = i2c_imx_acked(i2c_imx);
> + if (result)
> + return result;
> +
> + dev_dbg(dev, "<%s> write data\n", __func__);
> +
> + /* write data */
> + for (i = 0; i < msgs->len; i++) {
> + dev_dbg(dev, "<%s> write byte: B%d=0x%X\n",
> + __func__, i, msgs->buf[i]);
> + imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
> + result = i2c_imx_trx_complete(i2c_imx);
> + if (result)
> + return result;
> + result = i2c_imx_acked(i2c_imx);
> + if (result)
> + return result;
> + }
> }
> return 0;
> }
>
> static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
> {
> - int i, result;
> + int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
> unsigned int temp;
> + struct imx_i2c_dma *dma = i2c_imx->dma;
> + struct device *dev = &i2c_imx->adapter.dev;
>
> - dev_dbg(&i2c_imx->adapter.dev,
> - "<%s> write slave address: addr=0x%x\n",
> + dev_dbg(dev, "<%s> write slave address: addr=0x%x\n",
> __func__, (msgs->addr << 1) | 0x01);
>
> /* write slave address */
> @@ -474,7 +689,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
> if (result)
> return result;
>
> - dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
> + dev_dbg(dev, "<%s> setup bus\n", __func__);
>
> /* setup bus to read data */
> temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> @@ -484,35 +699,82 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
> imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
>
> - dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
> + dev_dbg(dev, "<%s> read data\n", __func__);
>
> - /* read data */
> - for (i = 0; i < msgs->len; i++) {
> - result = i2c_imx_trx_complete(i2c_imx);
> + if (dma && msgs->len >= IMX_I2C_DMA_THRESHOLD) {
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + temp |= I2CR_DMAEN;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +
> + reinit_completion(&i2c_imx->dma->cmd_complete);
> + dma->chan_using = dma->chan_rx;
> + dma->dma_transfer_dir = DMA_DEV_TO_MEM;
> + dma->dma_data_dir = DMA_FROM_DEVICE;
> + /* The last two data bytes must be transferred by the CPU. */
> + dma->dma_len = msgs->len - 2;
> + result = i2c_imx_dma_xfer(i2c_imx, msgs);
> if (result)
> return result;
> - if (i == (msgs->len - 1)) {
> - /* It must generate STOP before read I2DR to prevent
> - controller from generating another clock cycle */
> - dev_dbg(&i2c_imx->adapter.dev,
> - "<%s> clear MSTA\n", __func__);
> - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> - temp &= ~(I2CR_MSTA | I2CR_MTX);
> - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> - i2c_imx_bus_busy(i2c_imx, 0);
> - i2c_imx->stopped = 1;
> - } else if (i == (msgs->len - 2)) {
> - dev_dbg(&i2c_imx->adapter.dev,
> - "<%s> set TXAK\n", __func__);
> - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> - temp |= I2CR_TXAK;
> - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +
> + result = wait_for_completion_interruptible_timeout(
> + &i2c_imx->dma->cmd_complete,
> + msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
> + if (result <= 0) {
> + dmaengine_terminate_all(dma->chan_using);
> + if (result)
> + return result;
> + else
> + return -ETIMEDOUT;
> }
> - msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
> - dev_dbg(&i2c_imx->adapter.dev,
> - "<%s> read byte: B%d=0x%X\n",
> - __func__, i, msgs->buf[i]);
> +
> + /* waiting for Transfer complete. */
> + while (timeout--) {
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
> + if (temp & I2SR_ICF)
> + break;
> + udelay(10);
> + }
> +
> + if (!timeout)
> + return -ETIMEDOUT;
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + temp &= ~I2CR_DMAEN;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> + } else {
> + /* read data */
> + for (i = 0; i < msgs->len - 2; i++) {
> + result = i2c_imx_trx_complete(i2c_imx);
> + if (result)
> + return result;
> + msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
> + dev_dbg(dev, "<%s> read byte: B%d=0x%X\n",
> + __func__, i, msgs->buf[i]);
> + }
> + result = i2c_imx_trx_complete(i2c_imx);
> }
> +
> + /* read n-1 byte data */
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + temp |= I2CR_TXAK;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +
> + msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
> + /* read n byte data */
> + result = i2c_imx_trx_complete(i2c_imx);
> + if (result)
> + return result;
> +
> + /*
> + * It must generate STOP before read I2DR to prevent
> + * controller from generating another clock cycle
> + */
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + temp &= ~(I2CR_MSTA | I2CR_MTX);
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> + i2c_imx_bus_busy(i2c_imx, 0);
> + i2c_imx->stopped = 1;
> + msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
> +
> return 0;
> }
>
> @@ -599,6 +861,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
> void __iomem *base;
> int irq, ret;
> u32 bitrate;
> + u32 phy_addr;
>
> dev_dbg(&pdev->dev, "<%s>\n", __func__);
>
> @@ -609,6 +872,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
> }
>
> res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + phy_addr = res->start;
>
res->start is NOT a u32 type!
> base = devm_ioremap_resource(&pdev->dev, res);
> if (IS_ERR(base))
> return PTR_ERR(base);
> @@ -694,6 +958,10 @@ static int i2c_imx_probe(struct platform_device *pdev)
> i2c_imx->adapter.name);
> dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
>
> + /* Init DMA config if support*/
> + if (i2c_imx_dma_request(i2c_imx, (dma_addr_t)phy_addr))
>
If you want a dma_addr_t variable, why do you declare it with a
different type?
Lothar Wa?mann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstra?e 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Gesch?ftsf?hrer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
^ permalink raw reply
* [PATCH CFT] arm: netx: Migrate DEBUG_LL macros to shared directory
From: Daniel Thompson @ 2014-07-23 9:41 UTC (permalink / raw)
To: linux-arm-kernel
As part of the migration we introduce DEBUG_UART_PHYS/DEBUG_UART_VIRT
which default to UART1 but allow a user to configure UART2 or UART3.
We also introduce symbolic names for the registers and flags.
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Arnd Bergmann <arnd.bergmann@linaro.org>
Cc: linux-arm-kernel at lists.infradead.org
---
arch/arm/Kconfig.debug | 17 +++++++++++++++--
.../mach/debug-macro.S => include/debug/netx.S} | 22 +++++++++++-----------
2 files changed, 26 insertions(+), 13 deletions(-)
rename arch/arm/{mach-netx/include/mach/debug-macro.S => include/debug/netx.S} (62%)
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 762b3ed..c7e05b7 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -439,6 +439,14 @@ choice
Say Y here if you want kernel low-level debugging support
on Vybrid based platforms.
+ config DEBUG_NETX_UART
+ bool "Kernel low-level debugging messages via NetX UART"
+ depends on ARCH_NETX
+ select DEBUG_UART_NETX
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Hilscher NetX based platforms.
+
config DEBUG_NOMADIK_UART
bool "Kernel low-level debugging messages via NOMADIK UART"
depends on ARCH_NOMADIK
@@ -1063,6 +1071,7 @@ config DEBUG_LL_INCLUDE
DEBUG_IMX6SX_UART
default "debug/ks8695.S" if DEBUG_KS8695_UART
default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM
+ default "debug/netx.S" if DEBUG_NETX_UART
default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART
default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
@@ -1094,6 +1103,7 @@ config DEBUG_UART_8250
config DEBUG_UART_PHYS
hex "Physical base address of debug UART"
+ default 0x00100a00 if DEBUG_NETX_UART
default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0
default 0x01c28000 if DEBUG_SUNXI_UART0
default 0x01c28400 if DEBUG_SUNXI_UART1
@@ -1162,10 +1172,12 @@ config DEBUG_UART_PHYS
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_LL_UART_EFM32 || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || \
- DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART
+ DEBUG_MSM_UART || DEBUG_NETX_UART || DEBUG_QCOM_UARTDM || \
+ DEBUG_S3C24XX_UART
config DEBUG_UART_VIRT
hex "Virtual base address of debug UART"
+ default 0xe0000a00 if DEBUG_NETX_UART
default 0xe0010fe0 if ARCH_RPC
default 0xe1000000 if DEBUG_MSM_UART
default 0xf0000be0 if ARCH_EBSA110
@@ -1232,7 +1244,8 @@ config DEBUG_UART_VIRT
default DEBUG_UART_PHYS if !MMU
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || \
- DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART
+ DEBUG_MSM_UART || DEBUG_NETX_UART || DEBUG_QCOM_UARTDM || \
+ DEBUG_S3C24XX_UART
config DEBUG_UART_8250_SHIFT
int "Register offset shift for the 8250 debug UART"
diff --git a/arch/arm/mach-netx/include/mach/debug-macro.S b/arch/arm/include/debug/netx.S
similarity index 62%
rename from arch/arm/mach-netx/include/mach/debug-macro.S
rename to arch/arm/include/debug/netx.S
index 247781e..cf7522a 100644
--- a/arch/arm/mach-netx/include/mach/debug-macro.S
+++ b/arch/arm/include/debug/netx.S
@@ -1,5 +1,4 @@
-/* arch/arm/mach-netx/include/mach/debug-macro.S
- *
+/*
* Debugging macro include header
*
* Copyright (C) 1994-1999 Russell King
@@ -11,26 +10,27 @@
*
*/
-#include "hardware.h"
+#define UART_DATA 0
+#define UART_FLAG 0x18
+#define UART_FLAG_BUSY (1 << 3)
.macro addruart, rp, rv, tmp
- mov \rp, #0x00000a00
- orr \rv, \rp, #io_p2v(0x00100000) @ virtual
- orr \rp, \rp, #0x00100000 @ physical
+ ldr \rp, =CONFIG_DEBUG_UART_PHYS
+ ldr \rp, =CONFIG_DEBUG_UART_VIRT
.endm
.macro senduart,rd,rx
- str \rd, [\rx, #0]
+ str \rd, [\rx, #UART_DATA]
.endm
.macro busyuart,rd,rx
-1002: ldr \rd, [\rx, #0x18]
- tst \rd, #(1 << 3)
+1002: ldr \rd, [\rx, #UART_FLAG]
+ tst \rd, #UART_FLAG_BUSY
bne 1002b
.endm
.macro waituart,rd,rx
-1001: ldr \rd, [\rx, #0x18]
- tst \rd, #(1 << 3)
+1001: ldr \rd, [\rx, #UART_FLAG]
+ tst \rd, #UART_FLAG_BUSY
bne 1001b
.endm
--
1.9.3
^ permalink raw reply related
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