* [PATCH v6] soc: qcom: add l2 cache perf events driver
From: Mark Rutland @ 2016-10-04 15:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474492374-12140-1-git-send-email-nleeder@codeaurora.org>
Hi Neil,
On Wed, Sep 21, 2016 at 05:12:54PM -0400, Neil Leeder wrote:
> Adds perf events support for L2 cache PMU.
>
> The L2 cache PMU driver is named 'l2cache_0' and can be used
> with perf events to profile L2 events such as cache hits
> and misses.
>
> Signed-off-by: Neil Leeder <nleeder@codeaurora.org>
> ---
> drivers/soc/qcom/Kconfig | 9 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/perf_event_l2.c | 948 +++++++++++++++++++++++++++++++++++++++
> include/linux/cpuhotplug.h | 1 +
> 4 files changed, 959 insertions(+)
> create mode 100644 drivers/soc/qcom/perf_event_l2.c
Apologies for the delay; this has been on my todo list, but I've been a
little distracted and haven't had the time necessary to devote to this.
It's somewhat unusual given the constraint logic and the percpu uncore
component, so there's more to consider than usual.
At a high level, this will need to be moved to drivers/perf/, per [1].
Can you move the driver there, and post the result atop of v4.8-rc1 at
the end of the merge window? Until then, I can't guarantee that I'll
have the time to look at this.
Can you also give Vince's perf fuzzer [2] a spin against the driver? I
can't recall if we covered that previously, and in practice it's found a
number of issues in drivers that have otherwise looked fine. If you've
done so, it'd be worth noting in the cover.
Thanks,
Mark.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-September/457188.html
[2] https://github.com/deater/perf_event_tests
^ permalink raw reply
* [PATCH 1/3] pinctrl: sunxi: Add support for fetching pinconf settings from hardware
From: Chen-Yu Tsai @ 2016-10-04 15:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161004080245.GK5228@lukather>
On Tue, Oct 4, 2016 at 4:02 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Tue, Oct 04, 2016 at 09:51:10AM +0800, Chen-Yu Tsai wrote:
>> The sunxi pinctrl driver only caches whatever pinconf setting was last
>> set on a given pingroup. This is not particularly helpful, nor is it
>> correct.
>>
>> Fix this by actually reading the hardware registers and returning
>> the correct results or error codes. Also filter out unsupported
>> pinconf settings. Since this driver has a peculiar setup of 1 pin
>> per group, we can support both pin and pingroup pinconf setting
>> read back with the same code. The sunxi_pconf_reg helper and code
>> structure is inspired by pinctrl-msm.
>>
>> With this done we can also claim to support generic pinconf, by
>> setting .is_generic = true in pinconf_ops.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 85 +++++++++++++++++++++++++++++++++--
>> 1 file changed, 82 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> index 54455af566ec..609843c9a65c 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> @@ -10,6 +10,7 @@
>> * warranty of any kind, whether express or implied.
>> */
>>
>> +#include <dt-bindings/pinctrl/sun4i-a10.h>
>> #include <linux/io.h>
>> #include <linux/clk.h>
>> #include <linux/gpio/driver.h>
>> @@ -269,15 +270,91 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {
>> .get_group_pins = sunxi_pctrl_get_group_pins,
>> };
>>
>> +static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
>> + u32 *offset, u32 *shift, u32 *mask)
>> +{
>> + switch (param) {
>> + case PIN_CONFIG_DRIVE_STRENGTH:
>> + *offset = sunxi_dlevel_reg(pin);
>> + *shift = sunxi_dlevel_offset(pin);
>> + *mask = DLEVEL_PINS_MASK;
>> + break;
>> +
>> + case PIN_CONFIG_BIAS_PULL_UP:
>> + case PIN_CONFIG_BIAS_PULL_DOWN:
>> + case PIN_CONFIG_BIAS_DISABLE:
>> + *offset = sunxi_pull_reg(pin);
>> + *shift = sunxi_pull_offset(pin);
>> + *mask = PULL_PINS_MASK;
>> + break;
>> +
>> + default:
>> + return -ENOTSUPP;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
>> + unsigned long *config)
>> +{
>> + struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
>> + enum pin_config_param param = pinconf_to_config_param(*config);
>> + u32 offset, shift, mask, val;
>> + u16 arg;
>> + int ret;
>> +
>> + pin -= pctl->desc->pin_base;
>> +
>> + ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
>> + if (ret < 0)
>> + return ret;
>> +
>> + val = (readl(pctl->membase + offset) >> shift) & mask;
>> +
>> + switch (pinconf_to_config_param(*config)) {
>> + case PIN_CONFIG_DRIVE_STRENGTH:
>> + arg = (val + 1) * 10;
>> + break;
>> +
>> + case PIN_CONFIG_BIAS_PULL_UP:
>> + if (val != SUN4I_PINCTRL_PULL_UP)
>> + return -EINVAL;
>> + arg = 1; /* hardware is weak pull-up */
>> + break;
>> +
>> + case PIN_CONFIG_BIAS_PULL_DOWN:
>> + if (val != SUN4I_PINCTRL_PULL_DOWN)
>> + return -EINVAL;
>> + arg = 1; /* hardware is weak pull-down */
>> + break;
>> +
>> + case PIN_CONFIG_BIAS_DISABLE:
>> + if (val != SUN4I_PINCTRL_NO_PULL)
>> + return -EINVAL;
>> + arg = 0;
>> + break;
>> +
>> + default:
>> + /* sunxi_pconf_reg should catch anything unsupported */
>> + WARN_ON(1);
>> + return -ENOTSUPP;
>
> This should be EINVAL. The operation is supported, but one of the
> argument is not valid.
According to include/linux/pinctrl/pinconf.h
* @pin_config_get: get the config of a certain pin, if the requested config
* is not available on this controller this should return -ENOTSUPP
* and if it is available but disabled it should return -EINVAL
So I think it is correct to return -ENOTSUPP here.
ChenYu
^ permalink raw reply
* [PATCH 03/14] ASoC: sun4i-i2s: Add apb reset
From: Maxime Ripard @ 2016-10-04 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161004141516.53c6fa8c@free-electrons.com>
Hi,
On Tue, Oct 04, 2016 at 02:15:16PM +0200, Thomas Petazzoni wrote:
> Hello,
>
> On Tue, 4 Oct 2016 11:46:16 +0200, Myl?ne Josserand wrote:
>
> > #include <sound/dmaengine_pcm.h>
> > #include <sound/pcm_params.h>
> > @@ -589,6 +590,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
> > {
> > struct sun4i_i2s *i2s;
> > struct resource *res;
> > + struct reset_control *reset_apb;
> > void __iomem *regs;
> > int irq, ret;
> >
> > @@ -626,7 +628,19 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
> > dev_err(&pdev->dev, "Can't get our mod clock\n");
> > return PTR_ERR(i2s->mod_clk);
> > }
> > -
> > +
> > + reset_apb = devm_reset_control_get(&pdev->dev, "apb_reset");
>
> I believe this is a change in the Device Tree binding, since you're
> adding support for a new resource. Perhaps the Device Tree binding
> documentation should be updated accordingly?
Indeed.
You have two solutions to do that:
- Either mark it as optional and use reset_control_get_optional
(because here, you broke the other SoCs that have that controller
but no reset line)
- Or introduce a new compatible, and make the reset property
mandatory for that new compatible.
I prefer the latter, since you get a stricter error check, and you
cannot end up in a situation where your driver probes but is
useless. But you'll find both in our drivers.
> > + }
> > +
> > + ret = reset_control_deassert(reset_apb);
> > + if (ret < 0) {
> > + dev_err(&pdev->dev, "Can't deassert apb reset (%d)\n", ret);
> > + return ret;
> > + }
>
> Do you need to re-assert the reset line in the ->remove() hook?
Even better, you can add it to the runtime_pm hooks! :)
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161004/193777b3/attachment.sig>
^ permalink raw reply
* [PATCH 01/14] dma: sun6i-dma: Add burst case of 4
From: Vinod Koul @ 2016-10-04 15:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161004154651.3d0eb02badb6dc66758dd3aa@free.fr>
On Tue, Oct 04, 2016 at 03:46:51PM +0200, Jean-Francois Moine wrote:
> On Tue, 4 Oct 2016 14:12:21 +0200
> Thomas Petazzoni <thomas.petazzoni@free-electrons.com> wrote:
>
> > > > Add the case of a burst of 4 which is handled by the SoC.
> > > >
> > > > Signed-off-by: Myl?ne Josserand <mylene.josserand@free-electrons.com>
> > > > ---
> > > > drivers/dma/sun6i-dma.c | 2 ++
> > > > 1 file changed, 2 insertions(+)
> > > >
> > > > diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
> > > > index 8346199..0485204 100644
> > > > --- a/drivers/dma/sun6i-dma.c
> > > > +++ b/drivers/dma/sun6i-dma.c
> > > > @@ -240,6 +240,8 @@ static inline s8 convert_burst(u32 maxburst)
> > > > switch (maxburst) {
> > > > case 1:
> > > > return 0;
> > > > + case 4:
> > > > + return 1;
> > > > case 8:
> > > > return 2;
> > > > default:
> > > > --
> > > > 2.9.3
> > >
> > > This patch has already been rejected by Maxime in the threads
> > > http://www.spinics.net/lists/dmaengine/msg08610.html
> > > and
> > > http://www.spinics.net/lists/dmaengine/msg08719.html
> > >
> > > I hope you will find the way he wants for this maxburst to be added.
> >
> > I was about to reply to Mylene's e-mail, suggesting that she should add
> > a comment in the code (and maybe in the commit log) to explain why this
> > addition is needed, and also that even though the schematics say that
> > value "1" (max burst size of 4 bytes) is reserved, it is in fact
> > incorrect. The Allwinner BSP code is really using this value, and it's
> > the value that makes audio work, so we believe the datasheet is simply
> > incorrect.
> >
> > We already discussed it with Maxime, so I believe he should agree this
> > time. But I would suggest to have such details explained in the commit
> > log and in a comment in the code.
>
> Strange. Looking at the datasheets of the A23, A31, A33, A83T and H3
> (these are the SoCs using the DMA sun6i), only the H3 can have 4 as the
> burst size (the doc is unclear for the A31).
>
> Well, I was submitting for the H3, Myl?ne is submitting for the A33.
> So, what about the A23, A31 and A83T?
Since these are device properties, I feel we should move this to DT. That
way any new controller can have any variation based on the mood of hw
designer that day and we can hopefully cope with it :-)
But yes we would need to set the bursts supported in driver and allow above
for supported bursts only.
--
~Vinod
^ permalink raw reply
* [RESEND PATCH v2 -next 3/3] ARM64: dts: amlogic: Add basic support for Amlogic S905D
From: Neil Armstrong @ 2016-10-04 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475595430-30075-1-git-send-email-narmstrong@baylibre.com>
This patch introduces the basic support for the Amlogic S905D (MesonGXL)
and for the Amlogic evaluation boards P230 and P231.
No documentation has been released yet for this SoC, so for now only the
bare minimum has been added in the DT.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
Documentation/devicetree/bindings/arm/amlogic.txt | 4 ++
arch/arm64/boot/dts/amlogic/Makefile | 2 +
.../boot/dts/amlogic/meson-gxl-s905d-p230.dts | 51 ++++++++++++++++++
.../boot/dts/amlogic/meson-gxl-s905d-p231.dts | 51 ++++++++++++++++++
.../boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi | 63 ++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi | 48 +++++++++++++++++
6 files changed, 219 insertions(+)
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p231.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi
diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
index 7edb635..fffc179 100644
--- a/Documentation/devicetree/bindings/arm/amlogic.txt
+++ b/Documentation/devicetree/bindings/arm/amlogic.txt
@@ -21,6 +21,10 @@ Boards with the Amlogic Meson GXL S905X SoC shall have the following properties:
Required root node property:
compatible: "amlogic,s905x", "amlogic,meson-gxl";
+Boards with the Amlogic Meson GXL S905D SoC shall have the following properties:
+ Required root node property:
+ compatible: "amlogic,s905d", "amlogic,meson-gxl";
+
Board compatible values:
- "geniatech,atv1200" (Meson6)
- "minix,neo-x8" (Meson8)
diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
index 1f78b07..57e0ae0 100644
--- a/arch/arm64/boot/dts/amlogic/Makefile
+++ b/arch/arm64/boot/dts/amlogic/Makefile
@@ -5,6 +5,8 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-pro.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-meta.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-telos.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
new file mode 100644
index 0000000..3dfaa37
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "meson-gxl-s905d-p23x.dtsi"
+
+/ {
+ compatible = "amlogic,p230", "amlogic,s905d", "amlogic,meson-gxl";
+ model = "Amlogic Meson GXL (S905D) P230 Development Board";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p231.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p231.dts
new file mode 100644
index 0000000..ade8d29
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p231.dts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "meson-gxl-s905d-p23x.dtsi"
+
+/ {
+ compatible = "amlogic,p231", "amlogic,s905d", "amlogic,meson-gxl";
+ model = "Amlogic Meson GXL (S905D) P231 Development Board";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi
new file mode 100644
index 0000000..bf08e87
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "meson-gxl-s905d.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart_AO;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+};
+
+&uart_AO {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi
new file mode 100644
index 0000000..615308e
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "meson-gxl.dtsi"
+
+/ {
+ compatible = "amlogic,s905d", "amlogic,meson-gxl";
+};
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v2 -next 2/3] ARM64: dts: amlogic: Add basic support for Amlogic S905X
From: Neil Armstrong @ 2016-10-04 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475595430-30075-1-git-send-email-narmstrong@baylibre.com>
From: Carlo Caione <carlo@endlessm.com>
This patch introduces the basic support for the Amlogic S905X (Meson
GXL) and for the Amlogic evaluation board P212.
No documentation has been released yet for this SoC, so for now only the
bare minimum has been added in the DT.
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Andreas F?rber <afaerber@suse.de>
Signed-off-by: Carlo Caione <carlo@endlessm.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
Documentation/devicetree/bindings/arm/amlogic.txt | 7 +++
arch/arm64/boot/dts/amlogic/Makefile | 1 +
.../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 69 ++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi | 48 +++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 48 +++++++++++++++
5 files changed, 173 insertions(+)
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
index fcc6f6c..7edb635 100644
--- a/Documentation/devicetree/bindings/arm/amlogic.txt
+++ b/Documentation/devicetree/bindings/arm/amlogic.txt
@@ -17,6 +17,10 @@ Boards with the Amlogic Meson GXBaby SoC shall have the following properties:
Required root node property:
compatible: "amlogic,meson-gxbb";
+Boards with the Amlogic Meson GXL S905X SoC shall have the following properties:
+ Required root node property:
+ compatible: "amlogic,s905x", "amlogic,meson-gxl";
+
Board compatible values:
- "geniatech,atv1200" (Meson6)
- "minix,neo-x8" (Meson8)
@@ -28,3 +32,6 @@ Board compatible values:
- "hardkernel,odroid-c2" (Meson gxbb)
- "amlogic,p200" (Meson gxbb)
- "amlogic,p201" (Meson gxbb)
+ - "amlogic,p212" (Meson gxl s905x)
+ - "amlogic,p230" (Meson gxl s905d)
+ - "amlogic,p231" (Meson gxl s905d)
diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
index 47ec703..1f78b07 100644
--- a/arch/arm64/boot/dts/amlogic/Makefile
+++ b/arch/arm64/boot/dts/amlogic/Makefile
@@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-p201.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-pro.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-meta.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-telos.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
new file mode 100644
index 0000000..9639f01
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "meson-gxl-s905x.dtsi"
+
+/ {
+ compatible = "amlogic,p212", "amlogic,s905x", "amlogic,meson-gxl";
+ model = "Amlogic Meson GXL (S905X) P212 Development Board";
+
+ aliases {
+ serial0 = &uart_AO;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+};
+
+/* This UART is brought out to the DB9 connector */
+&uart_AO {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi
new file mode 100644
index 0000000..07f0e0b
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "meson-gxl.dtsi"
+
+/ {
+ compatible = "amlogic,s905x", "amlogic,meson-gxl";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
new file mode 100644
index 0000000..13b10ee
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "meson-gx.dtsi"
+
+/ {
+ compatible = "amlogic,meson-gxl";
+};
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v2 -next 1/3] ARM64: dts: amlogic: Add Meson GX dtsi from GXBB
From: Neil Armstrong @ 2016-10-04 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475595430-30075-1-git-send-email-narmstrong@baylibre.com>
Move all non-gxbb specific nodes to a common GX dtsi.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 200 +++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 895 ++++++++++++----------------
2 files changed, 579 insertions(+), 516 deletions(-)
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gx.dtsi
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
new file mode 100644
index 0000000..a739d6a
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * Copyright (c) 2016 Andreas F?rber
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <0x2>;
+ #size-cells = <0x0>;
+
+ cpu0: cpu at 0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ };
+
+ cpu1: cpu at 1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x1>;
+ enable-method = "psci";
+ };
+
+ cpu2: cpu at 2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x2>;
+ enable-method = "psci";
+ };
+
+ cpu3: cpu at 3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x3>;
+ enable-method = "psci";
+ };
+ };
+
+ arm-pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ xtal: xtal-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "xtal";
+ #clock-cells = <0>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ cbus: cbus at c1100000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xc1100000 0x0 0x100000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>;
+
+ uart_A: serial at 84c0 {
+ compatible = "amlogic,meson-uart";
+ reg = <0x0 0x84c0 0x0 0x14>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>;
+ status = "disabled";
+ };
+ };
+
+ gic: interrupt-controller at c4301000 {
+ compatible = "arm,gic-400";
+ reg = <0x0 0xc4301000 0 0x1000>,
+ <0x0 0xc4302000 0 0x2000>,
+ <0x0 0xc4304000 0 0x2000>,
+ <0x0 0xc4306000 0 0x2000>;
+ interrupt-controller;
+ interrupts = <GIC_PPI 9
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ };
+
+ aobus: aobus at c8100000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xc8100000 0x0 0x100000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
+
+ uart_AO: serial at 4c0 {
+ compatible = "amlogic,meson-uart";
+ reg = <0x0 0x004c0 0x0 0x14>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>;
+ status = "disabled";
+ };
+ };
+
+ periphs: periphs at c8834000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xc8834000 0x0 0x2000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>;
+ };
+
+
+ hiubus: hiubus at c883c000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xc883c000 0x0 0x2000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>;
+ };
+
+ apb: apb at d0000000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xd0000000 0x0 0x200000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 610e0e1..443811b 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -40,9 +40,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "meson-gx.dtsi"
#include <dt-bindings/gpio/meson-gxbb-gpio.h>
#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
#include <dt-bindings/clock/gxbb-clkc.h>
@@ -51,56 +49,6 @@
/ {
compatible = "amlogic,meson-gxbb";
- interrupt-parent = <&gic>;
- #address-cells = <2>;
- #size-cells = <2>;
-
- cpus {
- #address-cells = <0x2>;
- #size-cells = <0x0>;
-
- cpu0: cpu at 0 {
- device_type = "cpu";
- compatible = "arm,cortex-a53", "arm,armv8";
- reg = <0x0 0x0>;
- enable-method = "psci";
- };
-
- cpu1: cpu at 1 {
- device_type = "cpu";
- compatible = "arm,cortex-a53", "arm,armv8";
- reg = <0x0 0x1>;
- enable-method = "psci";
- };
-
- cpu2: cpu at 2 {
- device_type = "cpu";
- compatible = "arm,cortex-a53", "arm,armv8";
- reg = <0x0 0x2>;
- enable-method = "psci";
- };
-
- cpu3: cpu at 3 {
- device_type = "cpu";
- compatible = "arm,cortex-a53", "arm,armv8";
- reg = <0x0 0x3>;
- enable-method = "psci";
- };
- };
-
- arm-pmu {
- compatible = "arm,cortex-a53-pmu";
- interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
- };
-
- psci {
- compatible = "arm,psci-0.2";
- method = "smc";
- };
firmware {
sm: secure-monitor {
@@ -126,31 +74,7 @@
};
};
- timer {
- compatible = "arm,armv8-timer";
- interrupts = <GIC_PPI 13
- (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 14
- (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 11
- (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 10
- (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>;
- };
-
- xtal: xtal-clk {
- compatible = "fixed-clock";
- clock-frequency = <24000000>;
- clock-output-names = "xtal";
- #clock-cells = <0>;
- };
-
soc {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
-
usb0_phy: phy at c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy";
#phy-cells = <0>;
@@ -170,500 +94,439 @@
status = "disabled";
};
- cbus: cbus at c1100000 {
- compatible = "simple-bus";
- reg = <0x0 0xc1100000 0x0 0x100000>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>;
+ usb0: usb at c9000000 {
+ compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
+ reg = <0x0 0xc9000000 0x0 0x40000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB0_DDR_BRIDGE>;
+ clock-names = "otg";
+ phys = <&usb0_phy>;
+ phy-names = "usb2-phy";
+ dr_mode = "host";
+ status = "disabled";
+ };
- reset: reset-controller at 4404 {
- compatible = "amlogic,meson-gxbb-reset";
- reg = <0x0 0x04404 0x0 0x20>;
- #reset-cells = <1>;
- };
+ usb1: usb at c9100000 {
+ compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
+ reg = <0x0 0xc9100000 0x0 0x40000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
+ clock-names = "otg";
+ phys = <&usb1_phy>;
+ phy-names = "usb2-phy";
+ dr_mode = "host";
+ status = "disabled";
+ };
- uart_A: serial at 84c0 {
- compatible = "amlogic,meson-uart";
- reg = <0x0 0x84c0 0x0 0x14>;
- interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
- clocks = <&xtal>;
- status = "disabled";
- };
+ ethmac: ethernet at c9410000 {
+ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac";
+ reg = <0x0 0xc9410000 0x0 0x10000
+ 0x0 0xc8834540 0x0 0x4>;
+ interrupts = <0 8 1>;
+ interrupt-names = "macirq";
+ clocks = <&clkc CLKID_ETH>,
+ <&clkc CLKID_FCLK_DIV2>,
+ <&clkc CLKID_MPLL2>;
+ clock-names = "stmmaceth", "clkin0", "clkin1";
+ phy-mode = "rgmii";
+ status = "disabled";
+ };
+ };
+};
+
+&cbus {
+ reset: reset-controller at 4404 {
+ compatible = "amlogic,meson-gxbb-reset";
+ reg = <0x0 0x04404 0x0 0x20>;
+ #reset-cells = <1>;
+ };
+
+ uart_B: serial at 84dc {
+ compatible = "amlogic,meson-uart";
+ reg = <0x0 0x84dc 0x0 0x14>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>;
+ status = "disabled";
+ };
+
+ pwm_ab: pwm at 8550 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x08550 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_cd: pwm at 8650 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x08650 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ef: pwm at 86c0 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x086c0 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ uart_C: serial at 8700 {
+ compatible = "amlogic,meson-uart";
+ reg = <0x0 0x8700 0x0 0x14>;
+ interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>;
+ status = "disabled";
+ };
+
+ watchdog at 98d0 {
+ compatible = "amlogic,meson-gxbb-wdt";
+ reg = <0x0 0x098d0 0x0 0x10>;
+ clocks = <&xtal>;
+ };
+
+ spifc: spi at 8c80 {
+ compatible = "amlogic,meson-gxbb-spifc";
+ reg = <0x0 0x08c80 0x0 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clkc CLKID_SPI>;
+ status = "disabled";
+ };
+
+ i2c_A: i2c at 8500 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x08500 0x0 0x20>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c_B: i2c at 87c0 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x087c0 0x0 0x20>;
+ interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c_C: i2c at 87e0 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x087e0 0x0 0x20>;
+ interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
+
+&aobus {
+ pinctrl_aobus: pinctrl at 14 {
+ compatible = "amlogic,meson-gxbb-aobus-pinctrl";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
- uart_B: serial at 84dc {
- compatible = "amlogic,meson-uart";
- reg = <0x0 0x84dc 0x0 0x14>;
- interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
- clocks = <&xtal>;
- status = "disabled";
+ gpio_ao: bank at 14 {
+ reg = <0x0 0x00014 0x0 0x8>,
+ <0x0 0x0002c 0x0 0x4>,
+ <0x0 0x00024 0x0 0x8>;
+ reg-names = "mux", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart_ao_a_pins: uart_ao_a {
+ mux {
+ groups = "uart_tx_ao_a", "uart_rx_ao_a";
+ function = "uart_ao";
};
+ };
- pwm_ab: pwm at 8550 {
- compatible = "amlogic,meson-gxbb-pwm";
- reg = <0x0 0x08550 0x0 0x10>;
- #pwm-cells = <3>;
- status = "disabled";
+ remote_input_ao_pins: remote_input_ao {
+ mux {
+ groups = "remote_input_ao";
+ function = "remote_input_ao";
};
+ };
- pwm_cd: pwm at 8650 {
- compatible = "amlogic,meson-gxbb-pwm";
- reg = <0x0 0x08650 0x0 0x10>;
- #pwm-cells = <3>;
- status = "disabled";
+ i2c_ao_pins: i2c_ao {
+ mux {
+ groups = "i2c_sck_ao",
+ "i2c_sda_ao";
+ function = "i2c_ao";
};
+ };
- pwm_ef: pwm at 86c0 {
- compatible = "amlogic,meson-gxbb-pwm";
- reg = <0x0 0x086c0 0x0 0x10>;
- #pwm-cells = <3>;
- status = "disabled";
+ pwm_ao_a_3_pins: pwm_ao_a_3 {
+ mux {
+ groups = "pwm_ao_a_3";
+ function = "pwm_ao_a_3";
};
+ };
- uart_C: serial at 8700 {
- compatible = "amlogic,meson-uart";
- reg = <0x0 0x8700 0x0 0x14>;
- interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
- clocks = <&xtal>;
- status = "disabled";
+ pwm_ao_a_6_pins: pwm_ao_a_6 {
+ mux {
+ groups = "pwm_ao_a_6";
+ function = "pwm_ao_a_6";
};
+ };
- watchdog at 98d0 {
- compatible = "amlogic,meson-gxbb-wdt";
- reg = <0x0 0x098d0 0x0 0x10>;
- clocks = <&xtal>;
+ pwm_ao_a_12_pins: pwm_ao_a_12 {
+ mux {
+ groups = "pwm_ao_a_12";
+ function = "pwm_ao_a_12";
};
+ };
- spifc: spi at 8c80 {
- compatible = "amlogic,meson-gxbb-spifc";
- reg = <0x0 0x08c80 0x0 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- clocks = <&clkc CLKID_SPI>;
- status = "disabled";
+ pwm_ao_b_pins: pwm_ao_b {
+ mux {
+ groups = "pwm_ao_b";
+ function = "pwm_ao_b";
};
+ };
+ };
+
+ clkc_AO: clock-controller at 040 {
+ compatible = "amlogic,gxbb-aoclkc";
+ reg = <0x0 0x00040 0x0 0x4>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ ir: ir at 580 {
+ compatible = "amlogic,meson-gxbb-ir";
+ reg = <0x0 0x00580 0x0 0x40>;
+ interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
+ };
+
+ pwm_ab_AO: pwm at 550 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x0550 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ i2c_AO: i2c at 500 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x500 0x0 0x20>;
+ interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_AO_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
+
+&periphs {
+ rng {
+ compatible = "amlogic,meson-rng";
+ reg = <0x0 0x0 0x0 0x4>;
+ };
+
+ pinctrl_periphs: pinctrl at 4b0 {
+ compatible = "amlogic,meson-gxbb-periphs-pinctrl";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ gpio: bank at 4b0 {
+ reg = <0x0 0x004b0 0x0 0x28>,
+ <0x0 0x004e8 0x0 0x14>,
+ <0x0 0x00120 0x0 0x14>,
+ <0x0 0x00430 0x0 0x40>;
+ reg-names = "mux", "pull", "pull-enable", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
- i2c_A: i2c at 8500 {
- compatible = "amlogic,meson-gxbb-i2c";
- reg = <0x0 0x08500 0x0 0x20>;
- interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>;
- clocks = <&clkc CLKID_I2C>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
+ emmc_pins: emmc {
+ mux {
+ groups = "emmc_nand_d07",
+ "emmc_cmd",
+ "emmc_clk";
+ function = "emmc";
};
+ };
- i2c_B: i2c at 87c0 {
- compatible = "amlogic,meson-gxbb-i2c";
- reg = <0x0 0x087c0 0x0 0x20>;
- interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>;
- clocks = <&clkc CLKID_I2C>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
+ nor_pins: nor {
+ mux {
+ groups = "nor_d",
+ "nor_q",
+ "nor_c",
+ "nor_cs";
+ function = "nor";
};
+ };
- i2c_C: i2c at 87e0 {
- compatible = "amlogic,meson-gxbb-i2c";
- reg = <0x0 0x087e0 0x0 0x20>;
- interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>;
- clocks = <&clkc CLKID_I2C>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
+ sdcard_pins: sdcard {
+ mux {
+ groups = "sdcard_d0",
+ "sdcard_d1",
+ "sdcard_d2",
+ "sdcard_d3",
+ "sdcard_cmd",
+ "sdcard_clk";
+ function = "sdcard";
};
};
- gic: interrupt-controller at c4301000 {
- compatible = "arm,gic-400";
- reg = <0x0 0xc4301000 0 0x1000>,
- <0x0 0xc4302000 0 0x2000>,
- <0x0 0xc4304000 0 0x2000>,
- <0x0 0xc4306000 0 0x2000>;
- interrupt-controller;
- interrupts = <GIC_PPI 9
- (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
- #interrupt-cells = <3>;
- #address-cells = <0>;
- };
-
- aobus: aobus at c8100000 {
- compatible = "simple-bus";
- reg = <0x0 0xc8100000 0x0 0x100000>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
-
- pinctrl_aobus: pinctrl at 14 {
- compatible = "amlogic,meson-gxbb-aobus-pinctrl";
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
-
- gpio_ao: bank at 14 {
- reg = <0x0 0x00014 0x0 0x8>,
- <0x0 0x0002c 0x0 0x4>,
- <0x0 0x00024 0x0 0x8>;
- reg-names = "mux", "pull", "gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- uart_ao_a_pins: uart_ao_a {
- mux {
- groups = "uart_tx_ao_a", "uart_rx_ao_a";
- function = "uart_ao";
- };
- };
-
- remote_input_ao_pins: remote_input_ao {
- mux {
- groups = "remote_input_ao";
- function = "remote_input_ao";
- };
- };
-
- i2c_ao_pins: i2c_ao {
- mux {
- groups = "i2c_sck_ao",
- "i2c_sda_ao";
- function = "i2c_ao";
- };
- };
-
- pwm_ao_a_3_pins: pwm_ao_a_3 {
- mux {
- groups = "pwm_ao_a_3";
- function = "pwm_ao_a_3";
- };
- };
-
- pwm_ao_a_6_pins: pwm_ao_a_6 {
- mux {
- groups = "pwm_ao_a_6";
- function = "pwm_ao_a_6";
- };
- };
-
- pwm_ao_a_12_pins: pwm_ao_a_12 {
- mux {
- groups = "pwm_ao_a_12";
- function = "pwm_ao_a_12";
- };
- };
-
- pwm_ao_b_pins: pwm_ao_b {
- mux {
- groups = "pwm_ao_b";
- function = "pwm_ao_b";
- };
- };
+ sdio_pins: sdio {
+ mux {
+ groups = "sdio_d0",
+ "sdio_d1",
+ "sdio_d2",
+ "sdio_d3",
+ "sdio_cmd",
+ "sdio_clk";
+ function = "sdio";
};
+ };
- clkc_AO: clock-controller at 040 {
- compatible = "amlogic,gxbb-aoclkc";
- reg = <0x0 0x00040 0x0 0x4>;
- #clock-cells = <1>;
- #reset-cells = <1>;
+ sdio_irq_pins: sdio_irq {
+ mux {
+ groups = "sdio_irq";
+ function = "sdio";
};
+ };
- uart_AO: serial at 4c0 {
- compatible = "amlogic,meson-uart";
- reg = <0x0 0x004c0 0x0 0x14>;
- interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
- clocks = <&xtal>;
- status = "disabled";
+ uart_a_pins: uart_a {
+ mux {
+ groups = "uart_tx_a",
+ "uart_rx_a";
+ function = "uart_a";
};
+ };
- ir: ir at 580 {
- compatible = "amlogic,meson-gxbb-ir";
- reg = <0x0 0x00580 0x0 0x40>;
- interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>;
- status = "disabled";
+ uart_b_pins: uart_b {
+ mux {
+ groups = "uart_tx_b",
+ "uart_rx_b";
+ function = "uart_b";
};
+ };
- pwm_ab_AO: pwm at 550 {
- compatible = "amlogic,meson-gxbb-pwm";
- reg = <0x0 0x0550 0x0 0x10>;
- #pwm-cells = <3>;
- status = "disabled";
+ uart_c_pins: uart_c {
+ mux {
+ groups = "uart_tx_c",
+ "uart_rx_c";
+ function = "uart_c";
};
+ };
- i2c_AO: i2c at 500 {
- compatible = "amlogic,meson-gxbb-i2c";
- reg = <0x0 0x500 0x0 0x20>;
- interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
- clocks = <&clkc CLKID_AO_I2C>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
+ i2c_a_pins: i2c_a {
+ mux {
+ groups = "i2c_sck_a",
+ "i2c_sda_a";
+ function = "i2c_a";
};
};
- periphs: periphs at c8834000 {
- compatible = "simple-bus";
- reg = <0x0 0xc8834000 0x0 0x2000>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>;
+ i2c_b_pins: i2c_b {
+ mux {
+ groups = "i2c_sck_b",
+ "i2c_sda_b";
+ function = "i2c_b";
+ };
+ };
- rng {
- compatible = "amlogic,meson-rng";
- reg = <0x0 0x0 0x0 0x4>;
+ i2c_c_pins: i2c_c {
+ mux {
+ groups = "i2c_sck_c",
+ "i2c_sda_c";
+ function = "i2c_c";
};
+ };
- pinctrl_periphs: pinctrl at 4b0 {
- compatible = "amlogic,meson-gxbb-periphs-pinctrl";
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
-
- gpio: bank at 4b0 {
- reg = <0x0 0x004b0 0x0 0x28>,
- <0x0 0x004e8 0x0 0x14>,
- <0x0 0x00120 0x0 0x14>,
- <0x0 0x00430 0x0 0x40>;
- reg-names = "mux", "pull", "pull-enable", "gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- emmc_pins: emmc {
- mux {
- groups = "emmc_nand_d07",
- "emmc_cmd",
- "emmc_clk";
- function = "emmc";
- };
- };
-
- nor_pins: nor {
- mux {
- groups = "nor_d",
- "nor_q",
- "nor_c",
- "nor_cs";
- function = "nor";
- };
- };
-
- sdcard_pins: sdcard {
- mux {
- groups = "sdcard_d0",
- "sdcard_d1",
- "sdcard_d2",
- "sdcard_d3",
- "sdcard_cmd",
- "sdcard_clk";
- function = "sdcard";
- };
- };
-
- sdio_pins: sdio {
- mux {
- groups = "sdio_d0",
- "sdio_d1",
- "sdio_d2",
- "sdio_d3",
- "sdio_cmd",
- "sdio_clk";
- function = "sdio";
- };
- };
-
- sdio_irq_pins: sdio_irq {
- mux {
- groups = "sdio_irq";
- function = "sdio";
- };
- };
-
- uart_a_pins: uart_a {
- mux {
- groups = "uart_tx_a",
- "uart_rx_a";
- function = "uart_a";
- };
- };
-
- uart_b_pins: uart_b {
- mux {
- groups = "uart_tx_b",
- "uart_rx_b";
- function = "uart_b";
- };
- };
-
- uart_c_pins: uart_c {
- mux {
- groups = "uart_tx_c",
- "uart_rx_c";
- function = "uart_c";
- };
- };
-
- i2c_a_pins: i2c_a {
- mux {
- groups = "i2c_sck_a",
- "i2c_sda_a";
- function = "i2c_a";
- };
- };
-
- i2c_b_pins: i2c_b {
- mux {
- groups = "i2c_sck_b",
- "i2c_sda_b";
- function = "i2c_b";
- };
- };
-
- i2c_c_pins: i2c_c {
- mux {
- groups = "i2c_sck_c",
- "i2c_sda_c";
- function = "i2c_c";
- };
- };
-
- eth_pins: eth_c {
- mux {
- groups = "eth_mdio",
- "eth_mdc",
- "eth_clk_rx_clk",
- "eth_rx_dv",
- "eth_rxd0",
- "eth_rxd1",
- "eth_rxd2",
- "eth_rxd3",
- "eth_rgmii_tx_clk",
- "eth_tx_en",
- "eth_txd0",
- "eth_txd1",
- "eth_txd2",
- "eth_txd3";
- function = "eth";
- };
- };
-
- pwm_a_x_pins: pwm_a_x {
- mux {
- groups = "pwm_a_x";
- function = "pwm_a_x";
- };
- };
-
- pwm_a_y_pins: pwm_a_y {
- mux {
- groups = "pwm_a_y";
- function = "pwm_a_y";
- };
- };
-
- pwm_b_pins: pwm_b {
- mux {
- groups = "pwm_b";
- function = "pwm_b";
- };
- };
-
- pwm_d_pins: pwm_d {
- mux {
- groups = "pwm_d";
- function = "pwm_d";
- };
- };
-
- pwm_e_pins: pwm_e {
- mux {
- groups = "pwm_e";
- function = "pwm_e";
- };
- };
-
- pwm_f_x_pins: pwm_f_x {
- mux {
- groups = "pwm_f_x";
- function = "pwm_f_x";
- };
- };
-
- pwm_f_y_pins: pwm_f_y {
- mux {
- groups = "pwm_f_y";
- function = "pwm_f_y";
- };
- };
+ eth_pins: eth_c {
+ mux {
+ groups = "eth_mdio",
+ "eth_mdc",
+ "eth_clk_rx_clk",
+ "eth_rx_dv",
+ "eth_rxd0",
+ "eth_rxd1",
+ "eth_rxd2",
+ "eth_rxd3",
+ "eth_rgmii_tx_clk",
+ "eth_tx_en",
+ "eth_txd0",
+ "eth_txd1",
+ "eth_txd2",
+ "eth_txd3";
+ function = "eth";
};
};
- hiubus: hiubus at c883c000 {
- compatible = "simple-bus";
- reg = <0x0 0xc883c000 0x0 0x2000>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>;
+ pwm_a_x_pins: pwm_a_x {
+ mux {
+ groups = "pwm_a_x";
+ function = "pwm_a_x";
+ };
+ };
- clkc: clock-controller at 0 {
- compatible = "amlogic,gxbb-clkc";
- #clock-cells = <1>;
- reg = <0x0 0x0 0x0 0x3db>;
+ pwm_a_y_pins: pwm_a_y {
+ mux {
+ groups = "pwm_a_y";
+ function = "pwm_a_y";
};
+ };
- mailbox: mailbox at 404 {
- compatible = "amlogic,meson-gxbb-mhu";
- reg = <0 0x404 0 0x4c>;
- interrupts = <0 208 IRQ_TYPE_EDGE_RISING>,
- <0 209 IRQ_TYPE_EDGE_RISING>,
- <0 210 IRQ_TYPE_EDGE_RISING>;
- #mbox-cells = <1>;
+ pwm_b_pins: pwm_b {
+ mux {
+ groups = "pwm_b";
+ function = "pwm_b";
};
};
- apb: apb at d0000000 {
- compatible = "simple-bus";
- reg = <0x0 0xd0000000 0x0 0x200000>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>;
+ pwm_d_pins: pwm_d {
+ mux {
+ groups = "pwm_d";
+ function = "pwm_d";
+ };
};
- usb0: usb at c9000000 {
- compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
- reg = <0x0 0xc9000000 0x0 0x40000>;
- interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clkc CLKID_USB0_DDR_BRIDGE>;
- clock-names = "otg";
- phys = <&usb0_phy>;
- phy-names = "usb2-phy";
- dr_mode = "host";
- status = "disabled";
+ pwm_e_pins: pwm_e {
+ mux {
+ groups = "pwm_e";
+ function = "pwm_e";
+ };
};
- usb1: usb at c9100000 {
- compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
- reg = <0x0 0xc9100000 0x0 0x40000>;
- interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
- clock-names = "otg";
- phys = <&usb1_phy>;
- phy-names = "usb2-phy";
- dr_mode = "host";
- status = "disabled";
+ pwm_f_x_pins: pwm_f_x {
+ mux {
+ groups = "pwm_f_x";
+ function = "pwm_f_x";
+ };
};
- ethmac: ethernet at c9410000 {
- compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac";
- reg = <0x0 0xc9410000 0x0 0x10000
- 0x0 0xc8834540 0x0 0x4>;
- interrupts = <0 8 1>;
- interrupt-names = "macirq";
- clocks = <&clkc CLKID_ETH>,
- <&clkc CLKID_FCLK_DIV2>,
- <&clkc CLKID_MPLL2>;
- clock-names = "stmmaceth", "clkin0", "clkin1";
- phy-mode = "rgmii";
- status = "disabled";
+ pwm_f_y_pins: pwm_f_y {
+ mux {
+ groups = "pwm_f_y";
+ function = "pwm_f_y";
+ };
};
};
};
+
+&hiubus {
+ clkc: clock-controller at 0 {
+ compatible = "amlogic,gxbb-clkc";
+ #clock-cells = <1>;
+ reg = <0x0 0x0 0x0 0x3db>;
+ };
+
+ mailbox: mailbox at 404 {
+ compatible = "amlogic,meson-gxbb-mhu";
+ reg = <0 0x404 0 0x4c>;
+ interrupts = <0 208 IRQ_TYPE_EDGE_RISING>,
+ <0 209 IRQ_TYPE_EDGE_RISING>,
+ <0 210 IRQ_TYPE_EDGE_RISING>;
+ #mbox-cells = <1>;
+ };
+};
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v2 -next 0/3] ARM64: amlogic: Add support for GXL SoC Family
From: Neil Armstrong @ 2016-10-04 15:37 UTC (permalink / raw)
To: linux-arm-kernel
This is a resend rebased on linux-next-20161004 tag.
The new Amlogic GXL SoCs (S905X and S905D) are part of the Meson GX family and
share some common features that can be described in a common GX dtsi file used
by the Meson GXBB and Meson GXL Family dtsi.
This patchset introduces the common GX dtsi and switches the GXBB to use
the common GX dtsi.
Then it introduces the GXL S905X SoC with the GXL common dtsi, then the S905D
dtsi and the p212 board dts.
Finally the GXL S905D SoC is introduced with a S905D dtsi using the GXL common
and the p23x Board dtsi for the p231 and p230 development boards.
Changes since v1 at http://lkml.kernel.org/r/20160903082227.30559-1-narmstrong at baylibre.com :
- Add missing copyrigh in gx dtsi
- Rename gxl SoCs compatibles to amlogic,s905x and amlogic,s905d
Changes since RFC v1:
- Merge GX common and GXBB changes in a single patch
- Integrate GXL S905X patch
- Add support for S905D and the p23x boards
Note: This patchset integrates the patch "ARM64: dts: amlogic: Add basic support for Amlogic S905X" [1]
from Carlo Caione.
[1] http://lkml.kernel.org/r/1472382113-10754-1-git-send-email-carlo at caione.org
Carlo Caione (1):
ARM64: dts: amlogic: Add basic support for Amlogic S905X
Neil Armstrong (2):
ARM64: dts: amlogic: Add Meson GX dtsi from GXBB
ARM64: dts: amlogic: Add basic support for Amlogic S905D
Documentation/devicetree/bindings/arm/amlogic.txt | 11 +
arch/arm64/boot/dts/amlogic/Makefile | 3 +
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 200 +++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 895 +++++++++------------
.../boot/dts/amlogic/meson-gxl-s905d-p230.dts | 51 ++
.../boot/dts/amlogic/meson-gxl-s905d-p231.dts | 51 ++
.../boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi | 63 ++
arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi | 48 ++
.../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 69 ++
arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi | 48 ++
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 48 ++
11 files changed, 971 insertions(+), 516 deletions(-)
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gx.dtsi
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p231.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
--
1.9.1
^ permalink raw reply
* [PATCH] dmaengine: coh901318: fix integer overflow when shifting more than 32 places
From: Vinod Koul @ 2016-10-04 15:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdZ1gfZu=Snh9YK1X9w+ZW-zcuEFh8aojGi-LUKoyMKcCQ@mail.gmail.com>
On Tue, Oct 04, 2016 at 02:23:51PM +0200, Linus Walleij wrote:
> On Thu, Sep 29, 2016 at 8:06 PM, Joe Perches <joe@perches.com> wrote:
> > On Thu, 2016-09-29 at 18:57 +0100, Colin King wrote:
> >> Currently U300_DMA_CHANNELS is set to 40, meaning that the shift of 1 can
> >> be more than 32 places, which leads to a 32 bit integer overflow. Fix this
> >> by casting 1 to a u64 (the same type as started_channels) before shifting
> >> it.
> >
> > trivia:
> >
> >> diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
> > []
> >> @@ -1353,7 +1353,7 @@ static ssize_t coh901318_debugfs_read(struct file *file, char __user *buf,
> >> tmp += sprintf(tmp, "DMA -- enabled dma channels\n");
> >>
> >> for (i = 0; i < U300_DMA_CHANNELS; i++)
> >> - if (started_channels & (1 << i))
> >> + if (started_channels & ((u64)1 << i))
> >
> > Using
> >
> > if (started_channels & (1ULL << i))
> >
> > would be more common.
>
> Even better (IMO):
>
> #include <linux/bitops.h>
>
> if (started_channels & BIT(i))
>
> Apparently code is there to avoid the bit 31 problem, mea culpa.
I have already applied this one, so feel free to send this as an update :)
--
~Vinod
^ permalink raw reply
* [PATCH v2] arm: Added support for getcpu() vDSO using TPIDRURW
From: Fredrik Markstrom @ 2016-10-04 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475589000-29315-1-git-send-email-fredrik.markstrom@gmail.com>
This makes getcpu() ~1000 times faster, this is very useful when
implementing per-cpu buffers in userspace (to avoid cache line
bouncing). As an example lttng ust becomes ~30% faster.
The patch will break applications using TPIDRURW (which is context switched
since commit 4780adeefd042482f624f5e0d577bf9cdcbb760 ("ARM: 7735/2:
Preserve the user r/w register TPIDRURW on context switch and fork")) and
is therefore made configurable.
Signed-off-by: Fredrik Markstrom <fredrik.markstrom@gmail.com>
---
arch/arm/include/asm/tls.h | 8 +++++++-
arch/arm/kernel/entry-armv.S | 1 -
arch/arm/mm/Kconfig | 10 ++++++++++
arch/arm/vdso/Makefile | 3 +++
arch/arm/vdso/vdso.lds.S | 3 +++
arch/arm/vdso/vgetcpu.c | 34 ++++++++++++++++++++++++++++++++++
6 files changed, 57 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/vdso/vgetcpu.c
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
index 5f833f7..170fd76 100644
--- a/arch/arm/include/asm/tls.h
+++ b/arch/arm/include/asm/tls.h
@@ -10,10 +10,15 @@
.endm
.macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
+#ifdef CONFIG_VDSO_GETCPU
+ ldr \tpuser, [r2, #TI_CPU]
+#else
mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
+ ldr \tpuser, [r2, #TI_TP_VALUE + 4]
+ str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
+#endif
mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register
- str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
.endm
.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
@@ -22,6 +27,7 @@
mov \tmp2, #0xffff0fff
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
+ ldrne \tpuser, [r2, #TI_TP_VALUE + 4] @ load the saved user r/w reg
mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 9f157e7..4e1369a 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -787,7 +787,6 @@ ENTRY(__switch_to)
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
ldr r4, [r2, #TI_TP_VALUE]
- ldr r5, [r2, #TI_TP_VALUE + 4]
#ifdef CONFIG_CPU_USE_DOMAINS
mrc p15, 0, r6, c3, c0, 0 @ Get domain register
str r6, [r1, #TI_CPU_DOMAIN] @ Save old domain register
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index c1799dd..f18334a 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -854,6 +854,16 @@ config VDSO
You must have glibc 2.22 or later for programs to seamlessly
take advantage of this.
+config VDSO_GETCPU
+ bool "Enable VDSO for getcpu"
+ depends on VDSO && (CPU_V6K || CPU_V7 || CPU_V7M)
+ help
+ Say Y to make getcpu a VDSO (fast) call. This is useful if you
+ want to implement per cpu buffers to avoid cache line bouncing
+ in user mode.
+ This mechanism uses the TPIDRURW register so enabling it will break
+ applications using this register for it's own purpose.
+
config DMA_CACHE_RWFO
bool "Enable read/write for ownership DMA cache maintenance"
depends on CPU_V6K && SMP
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile
index 59a8fa7..9f1ec51 100644
--- a/arch/arm/vdso/Makefile
+++ b/arch/arm/vdso/Makefile
@@ -1,6 +1,9 @@
hostprogs-y := vdsomunge
obj-vdso := vgettimeofday.o datapage.o
+#ifeq ($(CONFIG_VDSO_GETCPU),y)
+obj-vdso += vgetcpu.o
+#endif
# Build rules
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds
diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S
index 89ca89f..1af39fb 100644
--- a/arch/arm/vdso/vdso.lds.S
+++ b/arch/arm/vdso/vdso.lds.S
@@ -82,6 +82,9 @@ VERSION
global:
__vdso_clock_gettime;
__vdso_gettimeofday;
+#ifdef CONFIG_VDSO_GETCPU
+ __vdso_getcpu;
+#endif
local: *;
};
}
diff --git a/arch/arm/vdso/vgetcpu.c b/arch/arm/vdso/vgetcpu.c
new file mode 100644
index 0000000..1b710af
--- /dev/null
+++ b/arch/arm/vdso/vgetcpu.c
@@ -0,0 +1,34 @@
+/*
+ * 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; version 2 of the
+ * License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/compiler.h>
+#include <asm/topology.h>
+
+struct getcpu_cache;
+
+notrace int __vdso_getcpu(unsigned int *cpup, unsigned int *nodep,
+ struct getcpu_cache *tcache)
+{
+ unsigned long node_and_cpu;
+
+ asm("mrc p15, 0, %0, c13, c0, 2\n" : "=r"(node_and_cpu));
+
+ if (nodep)
+ *nodep = cpu_to_node(node_and_cpu >> 16);
+ if (cpup)
+ *cpup = node_and_cpu & 0xffffUL;
+
+ return 0;
+}
+
--
2.7.2
^ permalink raw reply related
* PROBLEM: DWC3 USB 3.0 not working on Odroid-XU4 with Exynos 5422
From: Anand Moon @ 2016-10-04 15:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAFp+6iGx-jf+xrdHF=0J3FK9dDBg54zESYNVo8bz2Qz6G4gEZg@mail.gmail.com>
Hi Vivek,
On 4 October 2016 at 17:32, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
> Hi Michael,
>
>
> On Tue, Oct 4, 2016 at 4:28 PM, Michael Niew?hner <linux@mniewoehner.de> wrote:
>
>> > > > > > [1.] One line summary of the problem:
>> > > > > > DWC3 USB 3.0 not working on Odroid-XU4 with Exynos 5422
>> > > > > >
>> > > > > > [2.] Full description of the problem/report:
>> > > > > > No usb 3.0 devices are being detected when attached while USB 2.0
>> > > > > > devices work on the same port.
>> > > > > > USB 3.0 works after applying patches [9.1] and [9.2], but seems
>> > > > > > to be
>> > > > > > buggy. The usb hub is redetected every time an usb device is
>> > > > > > attached.
>
> [snip]
>
>>> > > > > > [9.] Other notes, patches, fixes, workarounds:
>>> > > > > > [9.1] https://lkml.org/lkml/2014/4/28/234
>>> > > > > > [9.2] https://lkml.org/lkml/2015/2/2/259
>>>
>>> These patches are required to get USB super-speed working on Exynos5420/5800.
>>> But they did not make to upstream. There was resistance on adding new
>>> phy_calibrate()
>>> callback.
>>>
>>> Without these patches the Exynos5420/5800 will enumerate all
>>> super-speed capable devices
>>> as high-speed devices.
>>> Last time we checked with exynos542x smdk boards and peach-* boards,
>>> we could get the
>>> Super - speed devices working. I have not tested odroid anytime so
>>> don't have much idea about the
>>> its intricacies.
>>> I guess Anand was able to use these patches to get his kernel working in past.
>>
>>
>> The patches don't work anymore with 4.8-rc* / 4.8. They worked - but very
>> unstable - with 4.7.
>>
>> One more problem appeared since one of the 4.8-RCs: reboot hangs when the dwc3
>> module is loaded. If I unload it before reboot / shutdown everything is fine.
>>
>>
>>>
>>> When you have a downstream on-board usb hub, ideally it should be able
>>> to detect the devices
>>> and not reset everytime you connect a new device (like you mentioned earlier).
>>> There can be two possible reasons why the hub keeps getting reset ever
>>> after applying the above
>>> mentioned patches:
>>> 1) the clock rates are not proper.
>>> 2) the regulator load setting is not enough to drive the hub.
>>>
>>> Anand, can you please point Michael to an older kernel with which you
>>> could test usb on odroid successfully ?
>>> You can compare the clocks with an older version and see if there'a
>>> any difference.
>>>
>>> Any possibility of any other framework (such as, bus-freq) trimming
>>> down the clock - rates ?
>>
>>
>> ################################
>> # v4.7.5
>> ################################
>>
>> $ cat /sys/kernel/debug/clk/clk_summary | grep usb
>> sclk_usbh20_scan_clk 0 0 480000000 0
>> sclk_usbh20 0 0 48000
>> 000 0
>> mout_usbd300 1 1 24000000 0
>> dout_usbd300 0 0 24000000 0
>> sclk_usbd300
>> 0 0 24000000 0
>> dout_usbphy300 1 1 24000000 0
>> sclk_usbphy300 4 4 24000
>> 000 0
>> mout_usbd301 1 1 24000000 0
>> dout_usbd301 0 0 24000000 0
>> sclk_usbd301
>> 0 0 24000000 0
>> dout_usbphy301 1 1 24000000 0
>> sclk_usbphy301 3 3 24000
>> 000 0
>> usbd301 1 1 100000000
>> usbd300 1 1 100000000
>>
>> usbh20 3 3 100000000 0
>
>>
>> ################################
>> # v4.8.0
>> ################################
>>
>> $ cat /sys/kernel/debug/clk/clk_summary | grep usb
>> sclk_usbh20_scan_clk 0 0 480000000 0
>> sclk_usbh20 0 0 48000000
>> 0
>> mout_usbd300 1 1 24000000 0
>> dout_usbd300 0 0 24000000 0
>> sclk_usbd300
>> 0 0 24000000 0
>> dout_usbphy300 1 1 24000000 0
>> sclk_usbphy300 4 4 24000000
>> 0
>> mout_usbd301 1 1 24000000 0
>> dout_usbd301 0 0 24000000 0
>> sclk_usbd301
>> 0 0 24000000 0
>> dout_usbphy301 1 1 24000000 0
>> sclk_usbphy301 3 3 24000000
>> 0
>> usbd301 1 1 100000000
>
> This clock should have been 200MHz.
>
>> usbd300 1 1 100000000
>> usbh2
>> 0 3 3 100000000 0
>>
>> $ cat /sys/kernel/debug/usb/devices
>> <<system hangs>>
>>
>
> The clocks are same across working/non-working.
> Is it possible to bisect the commit that's causing hang for 4.8x ?
>
> Adding few of the folks from Samsung who can test dwc3 usb on smdk/peach boards.
> +Alim, Pankaj
>
> Hi Alim, Pankaj,
> can you please give a try with 4.8 kernel on peach/smdk542x board and
> see if dwc3 usb works or not.
> You may need to the patches mentioned in [9.1] and [9.2] mentioned above.
>
>
[9.1] https://lkml.org/lkml/2014/4/28/234 base: platform: name the
device already during allocation
Dose not help. it's not useful at all.
What I feel is that their need to be some reset of usb phy so that
device are assigned to respective bus ports.
odroid at odroid:~$ lsusb -t
/: Bus 06.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/1p, 5000M
/: Bus 05.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/1p, 480M
|__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=r8152, 480M
/: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/1p, 5000M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/2p, 5000M
|__ Port 1: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 5000M
|__ Port 2: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 5000M
/: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/2p, 480M
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=exynos-ohci/3p, 12M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=exynos-ehci/3p, 480M
|__ Port 1: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 480M
Bus 06.Port should register the Realtek Ethernet r8153 device.
But I am not able to trace out how it's should happen.
-Best Regards
Anand Moon
> [snip]
>
>
> Thanks
> Vivek
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
^ permalink raw reply
* [RFC 10/10] irqchip: meson: Add support for IRQ_TYPE_EDGE_BOTH
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
The IP cannot take IRQ_EDGE_BOTH because the polarity in the filtering
block is just one bit. It can trigger on either edge, but not both with
the same configuration.
This prevents meson based SoC to use some simple generic driver, like
gpio-keys. The proposition is to change edge polarity in the end of
interrupt callback (just toggling the polarity register of the IP).
This works nicely but has 2 limitations:
1) If the signal is initially high, the first falling edge will not be
detected, because the chip is initially configured for a rising
edge.
2) If the signal changes too quickly for all edges to be properly
handled, an additional edge might get lost, for the same reason as
point 1.
There is no drawback for introducing this work around so, knowing the
limitation, it would be nice to have it
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/irqchip/irq-meson-gpio.c | 45 +++++++++++++++++++++++++++++++++++++---
1 file changed, 42 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 184025a9cdaf..5bcbefef3e94 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -58,6 +58,7 @@ struct meson_gpio_irq_domain {
struct meson_gpio_irq_chip {
void __iomem *base;
int index;
+ unsigned int flow_type;
};
static const struct meson_gpio_irq_params meson8_params = {
@@ -91,6 +92,19 @@ static void meson_gpio_irq_update_bits(void __iomem *base, unsigned int reg,
writel(tmp, base + reg);
}
+static void meson_gpio_irq_flip_bits(void __iomem *base, unsigned int reg,
+ u32 mask)
+{
+ u32 tmp, val;
+
+ tmp = readl(base + reg);
+ val = tmp ^ mask;
+ tmp = (tmp & val) | val;
+
+ writel(tmp, base + reg);
+}
+
+
static int meson_gpio_irq_get_index(struct meson_gpio_irq_domain *domain_data,
int hwirq)
{
@@ -135,11 +149,15 @@ static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
pr_debug("set type of hwirq %lu to %u\n", data->hwirq, type);
- if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- return -EINVAL;
+ cd->flow_type = type;
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
val |= REG_EDGE_POL_EDGE(cd->index);
+ /*
+ * Take care of the dual polarity issue here, starting positive
+ */
+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ type &= ~IRQ_TYPE_EDGE_FALLING;
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
val |= REG_EDGE_POL_LOW(cd->index);
@@ -162,11 +180,31 @@ static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
return irq_chip_set_type_parent(data, type);
}
+static void meson_gpio_irq_eoi(struct irq_data *data)
+{
+ struct meson_gpio_irq_chip *cd = irq_data_get_irq_chip_data(data);
+
+ /*
+ * To simulate IRQ_TYPE_EDGE_BOTH, change the polarity of the edge
+ * after each interrupt.
+ * Limitation:
+ * 1) If the signal is initially high, the first falling edge will not
+ * be detected
+ * 2) If the signal changes too quickly to detect all the edges, an
+ * additional edge might get lost.
+ */
+ if ((cd->flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ meson_gpio_irq_flip_bits(cd->base, REG_EDGE_POL,
+ REG_EDGE_POL_LOW(cd->index));
+
+ irq_chip_eoi_parent(data);
+}
+
static struct irq_chip meson_gpio_irq_chip = {
.name = "meson-gpio-irqchip",
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
- .irq_eoi = irq_chip_eoi_parent,
+ .irq_eoi = meson_gpio_irq_eoi,
.irq_set_type = meson_gpio_irq_set_type,
.irq_retrigger = irq_chip_retrigger_hierarchy,
#ifdef CONFIG_SMP
@@ -221,6 +259,7 @@ static int meson_gpio_irq_domain_alloc(struct irq_domain *domain,
cd->base = domain_data->base;
cd->index = index;
+ cd->flow_type = type;
fwspec_parent = &domain_data->parent_irqs[index];
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
--
2.7.4
^ permalink raw reply related
* [RFC 09/10] ARM: dts: amlogic: enable gpio interrupt controller on meson8
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm/boot/dts/meson8.dtsi | 19 +++++++++++++++++++
arch/arm/boot/dts/meson8b.dtsi | 19 +++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 45619f6162c5..82690e0352c9 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -43,6 +43,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/meson8-gpio.h>
/include/ "meson.dtsi"
@@ -91,6 +93,21 @@
clock-frequency = <141666666>;
};
+ gpio_interrupt: interrupt-controller at c1109880 {
+ compatible = "amlogic,meson8-gpio-intc";
+ reg = <0xc1109880 0x10>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+ <GIC_SPI 65 IRQ_TYPE_NONE>,
+ <GIC_SPI 66 IRQ_TYPE_NONE>,
+ <GIC_SPI 67 IRQ_TYPE_NONE>,
+ <GIC_SPI 68 IRQ_TYPE_NONE>,
+ <GIC_SPI 69 IRQ_TYPE_NONE>,
+ <GIC_SPI 70 IRQ_TYPE_NONE>,
+ <GIC_SPI 71 IRQ_TYPE_NONE>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pinctrl_cbus: pinctrl at c1109880 {
compatible = "amlogic,meson8-cbus-pinctrl";
reg = <0xc1109880 0x10>;
@@ -106,6 +123,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
spi_nor_pins: nor {
@@ -148,6 +166,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 41fd53671859..d76e7cb4d3dc 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -44,6 +44,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/meson8b-clkc.h>
#include <dt-bindings/gpio/meson8b-gpio.h>
#include <dt-bindings/reset/amlogic,meson8b-reset.h>
@@ -183,6 +185,21 @@
status = "disabled";
};
+ gpio_interrupt: interrupt-controller at c1109880 {
+ compatible = "amlogic,meson8b-gpio-intc";
+ reg = <0xc1109880 0x10>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+ <GIC_SPI 65 IRQ_TYPE_NONE>,
+ <GIC_SPI 66 IRQ_TYPE_NONE>,
+ <GIC_SPI 67 IRQ_TYPE_NONE>,
+ <GIC_SPI 68 IRQ_TYPE_NONE>,
+ <GIC_SPI 69 IRQ_TYPE_NONE>,
+ <GIC_SPI 70 IRQ_TYPE_NONE>,
+ <GIC_SPI 71 IRQ_TYPE_NONE>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pinctrl_cbus: pinctrl at c1109880 {
compatible = "amlogic,meson8b-cbus-pinctrl";
reg = <0xc1109880 0x10>;
@@ -198,6 +215,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
};
@@ -215,6 +233,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
--
2.7.4
^ permalink raw reply related
* [RFC 08/10] ARM64: dts: amlogic: enable gpio interrupt controller on gxbb
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 610e0e1c3cee..e5c6372dbe1c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -183,6 +183,21 @@
#reset-cells = <1>;
};
+ gpio_interrupt: interrupt-controller at 9880 {
+ compatible = "amlogic,gxbb-gpio-intc";
+ reg = <0x0 0x9880 0x0 0x10>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+ <GIC_SPI 65 IRQ_TYPE_NONE>,
+ <GIC_SPI 66 IRQ_TYPE_NONE>,
+ <GIC_SPI 67 IRQ_TYPE_NONE>,
+ <GIC_SPI 68 IRQ_TYPE_NONE>,
+ <GIC_SPI 69 IRQ_TYPE_NONE>,
+ <GIC_SPI 70 IRQ_TYPE_NONE>,
+ <GIC_SPI 71 IRQ_TYPE_NONE>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
uart_A: serial at 84c0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84c0 0x0 0x14>;
@@ -307,6 +322,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
@@ -426,6 +442,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
emmc_pins: emmc {
--
2.7.4
^ permalink raw reply related
* [RFC 07/10] ARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Add select MESON_IRQ_GPIO in Kconfig for Amlogic's meson8 and meson8b SoC
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm/mach-meson/Kconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index b6e3acc63e14..63157295cd9d 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -21,11 +21,13 @@ config MACH_MESON8
bool "Amlogic Meson8 SoCs support"
default ARCH_MESON
select MESON6_TIMER
+ select MESON_IRQ_GPIO
config MACH_MESON8B
bool "Amlogic Meson8b SoCs support"
default ARCH_MESON
select MESON6_TIMER
select COMMON_CLK_MESON8B
+ select MESON_IRQ_GPIO
endif
--
2.7.4
^ permalink raw reply related
* [RFC 06/10] ARM64: meson: enable MESON_IRQ_GPIO in Kconfig
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Add select MESON_IRQ_GPIO in Kconfig for Amlogic's meson SoC family
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm64/Kconfig.platforms | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index cfbdf02ef566..846479d4492d 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -95,6 +95,7 @@ config ARCH_MESON
select PINCTRL_MESON
select COMMON_CLK_AMLOGIC
select COMMON_CLK_GXBB
+ select MESON_GPIO_IRQ
help
This enables support for the Amlogic S905 SoCs.
--
2.7.4
^ permalink raw reply related
* [RFC 05/10] dt-bindings: pinctrl: meson: update gpio dt-bindings
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Add description for the interrupt-parent property of the gpio sub-node
If provided here, this property must be a phandle to an interrupt
controller suitable for meson pinctrl, like the meson gpio interrupt
controller.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
index fe7fe0b03cfb..39932c4dfb32 100644
--- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -23,6 +23,10 @@ Required properties for sub-nodes are:
- gpio-controller: identifies the node as a gpio controller
- #gpio-cells: must be 2
+Optional property for sub-nodes is:
+ - interrupt-parent: must be a phandle to the meson gpio interrupt controller.
+ if this property is provided, enables gpio ability to generate interrupts
+
=== Other sub-nodes ===
Child nodes without the "gpio-controller" represent some desired
--
2.7.4
^ permalink raw reply related
* [RFC 04/10] pinctrl: meson: allow gpio to request irq
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Add the ability for gpio to request irq from the gpio interrupt controller
if present. We have to specificaly that the parent interrupt controller is
the gpio interrupt controller because gpio on meson SoCs can't generate
interrupt directly on the GIC.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/pinctrl/Kconfig | 2 +
drivers/pinctrl/meson/pinctrl-meson.c | 83 ++++++++++++++++++++++++++++++++++-
drivers/pinctrl/meson/pinctrl-meson.h | 1 +
3 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 0e75d94972ba..d5bfbfcddab0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -126,7 +126,9 @@ config PINCTRL_MESON
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
+ select IRQ_DOMAIN
select OF_GPIO
+ select OF_IRQ
select REGMAP_MMIO
config PINCTRL_OXNAS
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 57122eda155a..f9be3ff5e11d 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -50,6 +50,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -481,6 +482,58 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
value ? BIT(bit) : 0);
}
+static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
+{
+ unsigned int hwirq;
+
+ if (bank->irq_first < 0)
+ /* this bank cannot generate irqs */
+ return -1;
+
+ hwirq = offset - bank->first + bank->irq_first;
+
+ if (hwirq > bank->irq_last)
+ /* this pin cannot generate irqs */
+ return -1;
+
+ return hwirq;
+}
+
+static int meson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct meson_pinctrl *pc = gpiochip_get_data(chip);
+ struct meson_bank *bank;
+ struct irq_fwspec fwspec;
+ unsigned int hwirq;
+ int ret;
+
+ ret = meson_get_bank(pc, offset, &bank);
+ if (ret)
+ return ret;
+
+ /*
+ * The interrupt controller might be missing, in such case we can't
+ * provide an interrupt for a pin
+ */
+ if (is_fwnode_irqchip(pc->fwnode)) {
+ dev_info(pc->dev, "interrupt controller not found\n");
+ return 0;
+ }
+
+ hwirq = meson_gpio_to_hwirq(bank, offset);
+ if (hwirq < 0) {
+ dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
+ return 0;
+ }
+
+ fwspec.fwnode = pc->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_NONE;
+
+ return irq_create_fwspec_mapping(&fwspec);
+}
+
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
struct meson_pinctrl *pc = gpiochip_get_data(chip);
@@ -539,6 +592,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
pc->chip.direction_output = meson_gpio_direction_output;
pc->chip.get = meson_gpio_get;
pc->chip.set = meson_gpio_set;
+ pc->chip.to_irq = meson_gpio_to_irq;
pc->chip.base = pc->data->pin_base;
pc->chip.ngpio = pc->data->num_pins;
pc->chip.can_sleep = false;
@@ -598,6 +652,33 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc,
return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config);
}
+static int meson_pinctrl_get_irq_gpio_intc(struct meson_pinctrl *pc,
+ struct device_node *node)
+{
+ struct device_node *np;
+
+ /*
+ * Make sure gpio don't request IRQ directly to the GIC
+ * TODO: Find a better way to make sure we have a compatible
+ * Interrupt controller here
+ */
+ if (!of_get_property(node, "interrupt-parent", NULL)) {
+ dev_dbg(pc->dev, "interrupt controller not found\n");
+ pc->fwnode = NULL;
+ return 0;
+ }
+
+ np = of_irq_find_parent(node);
+ if (!np) {
+ dev_err(pc->dev, "irq parent not found\n");
+ return -EINVAL;
+ }
+
+ pc->fwnode = of_node_to_fwnode(np);
+
+ return 0;
+}
+
static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
struct device_node *node)
{
@@ -643,7 +724,7 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
return PTR_ERR(pc->reg_gpio);
}
- return 0;
+ return meson_pinctrl_get_irq_gpio_intc(pc, gpio_np);
}
static int meson_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 785705996e60..4bcc4900b3eb 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -122,6 +122,7 @@ struct meson_pinctrl {
struct regmap *reg_gpio;
struct gpio_chip chip;
struct device_node *of_node;
+ struct fwnode_handle *fwnode;
};
#define PIN(x, b) (b + x)
--
2.7.4
^ permalink raw reply related
* [RFC 03/10] pinctrl: meson: update pinctrl data with gpio irq base number
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
This patch extends meson's pinctrl SoC specific data by adding the gpio
irq base number. This will allow gpios to request an interrupt on the
gpio interrupt controller using this base irq number the pin offset in
bank
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 22 ++++++++++----------
drivers/pinctrl/meson/pinctrl-meson.h | 15 +++++++++-----
drivers/pinctrl/meson/pinctrl-meson8.c | 20 +++++++++----------
drivers/pinctrl/meson/pinctrl-meson8b.c | 32 ++++++++++++++++++++----------
4 files changed, 53 insertions(+), 36 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index c3928aa3fefa..29b66684b287 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -715,20 +715,20 @@ static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
};
static struct meson_bank meson_gxbb_periphs_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
- BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
- BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
- BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
- BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
- BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
- BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 106, 128, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
+ BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 89, 105, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 59, 88, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
+ BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 30, 33, 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
+ BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 14, 29, 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
+ BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 52, 58, 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
+ BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 34, 51, 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
+ BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 129, 132, 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
};
static struct meson_bank meson_gxbb_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 98b5080650c1..785705996e60 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -81,6 +81,7 @@ enum meson_reg_type {
* @name: bank name
* @first: first pin of the bank
* @last: last pin of the bank
+ * @irq: hwirq base number of the bank
* @regs: array of register descriptors
*
* A bank represents a set of pins controlled by a contiguous set of
@@ -92,6 +93,8 @@ struct meson_bank {
const char *name;
unsigned int first;
unsigned int last;
+ int irq_first;
+ int irq_last;
struct meson_reg_desc regs[NUM_REG];
};
@@ -147,12 +150,14 @@ struct meson_pinctrl {
.num_groups = ARRAY_SIZE(fn ## _groups), \
}
-#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
{ \
- .name = n, \
- .first = f, \
- .last = l, \
- .regs = { \
+ .name = n, \
+ .first = f, \
+ .last = l, \
+ .irq_first = fi, \
+ .irq_last = li, \
+ .regs = { \
[REG_PULLEN] = { per, peb }, \
[REG_PULL] = { pr, pb }, \
[REG_DIR] = { dr, db }, \
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 07f1cb21c1b8..32449820f455 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -916,19 +916,19 @@ static struct meson_pmx_func meson8_aobus_functions[] = {
};
static struct meson_bank meson8_cbus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
- BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_0, 0), PIN(GPIODV_29, 0), 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
- BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
- BANK("Z", PIN(GPIOZ_0, 0), PIN(GPIOZ_14, 0), 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
- BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
- BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 112, 133, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 95, 111, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_0, 0), PIN(GPIODV_29, 0), 65, 94, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 29, 38, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("Z", PIN(GPIOZ_0, 0), PIN(GPIOZ_14, 0), 14, 28, 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
+ BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 58, 64, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 39, 57, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
};
static struct meson_bank meson8_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index 76f077f18193..9242888fea5f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -124,6 +124,12 @@ static const struct pinctrl_pin_desc meson8b_aobus_pins[] = {
MESON_PIN(GPIOAO_11, AO_OFF),
MESON_PIN(GPIOAO_12, AO_OFF),
MESON_PIN(GPIOAO_13, AO_OFF),
+
+ /*
+ * The following 2 pins are not mentionned in the public datasheet
+ * According to this datasheet, they can't be used with the gpio
+ * interrupt controller
+ */
MESON_PIN(GPIO_BSD_EN, AO_OFF),
MESON_PIN(GPIO_TEST_N, AO_OFF),
};
@@ -881,19 +887,25 @@ static struct meson_pmx_func meson8b_aobus_functions[] = {
};
static struct meson_bank meson8b_cbus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
- BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_9, 0), PIN(GPIODV_29, 0), 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
- BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
- BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
- BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
- BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 97, 118, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 80, 96, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_9, 0), PIN(GPIODV_29, 0), 59, 79, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 14, 23, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 43, 49, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 24, 42, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+
+ /*
+ * The following bank is not mentionned in the public datasheet
+ * There is no information whether it can be used with the gpio
+ * interrupt controller
+ */
+ BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), -1, -1, 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
};
static struct meson_bank meson8b_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
--
2.7.4
^ permalink raw reply related
* [RFC 02/10] dt-bindings: interrupt-controller: add DT binding for meson GPIO interrupt controller
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
This commit adds the device tree bindings description for Amlogic's GPIO
interrupt controller available on the meson8, meson8b and gxbb SoC families
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
.../amlogic,meson-gpio-intc.txt | 39 ++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
new file mode 100644
index 000000000000..bd4cceefcda1
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
@@ -0,0 +1,39 @@
+Amlogic meson GPIO interrupt controller
+
+Meson SoCs contains an interrupt controller which is able watch the SoC pads
+and generate an interrupt on edges or level. The controller is essentially a
+256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge
+or level and polarity. We don?t expose all 256 mux inputs because the
+documentation shows that upper part is not mapped to any pad. The actual number
+of interrupt exposed depends on the SoC.
+
+Required properties:
+
+- compatible : should be: "amlogic,meson8-gpio-intc? or
+ ?amlogic,meson8b-gpio-intc? or ?amlogic,gxbb-gpio-intc?
+- interrupts : List of the GIC?s interrupts used as parent interrupts.
+ There should 8 of these interrupts.
+- interrupt-parent : a phandle to the GIC the interrupts are routed to.
+ Usually this is provided at the root level of the device tree as it is
+ common to most of the SoC
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value must be 2.
+
+Exemple:
+
+gpio_interrupt: interrupt-controller at 9880 {
+ compatible = "amlogic,gxbb-gpio-intc";
+ reg = <0x0 0x9880 0x0 0x10>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+ <GIC_SPI 65 IRQ_TYPE_NONE>,
+ <GIC_SPI 66 IRQ_TYPE_NONE>,
+ <GIC_SPI 67 IRQ_TYPE_NONE>,
+ <GIC_SPI 68 IRQ_TYPE_NONE>,
+ <GIC_SPI 69 IRQ_TYPE_NONE>,
+ <GIC_SPI 70 IRQ_TYPE_NONE>,
+ <GIC_SPI 71 IRQ_TYPE_NONE>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+};
--
2.7.4
^ permalink raw reply related
* [RFC 01/10] irqchip: meson: add support for gpio interrupt controller
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475593708-10526-1-git-send-email-jbrunet@baylibre.com>
Add support for the intterrupt gpio controller found on Amlogic's meson
SoC family.
Unlike what the IP name suggest, it is not directly linked to the gpio
subsystem. It is actually an indepedent IP that is able to spy on the
SoC pad. For that purpose, it can mux and filter (edge or level and
polarity) any single SoC pad to one of the 8 GIC's interrupts it owns.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-meson-gpio.c | 398 +++++++++++++++++++++++++++++++++++++++
3 files changed, 408 insertions(+)
create mode 100644 drivers/irqchip/irq-meson-gpio.c
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 82b0b5daf3f5..168837263e80 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -279,3 +279,12 @@ config EZNPS_GIC
config STM32_EXTI
bool
select IRQ_DOMAIN
+
+config MESON_GPIO_IRQ
+ bool "Meson GPIO Interrupt Multiplexer"
+ depends on ARCH_MESON || COMPILE_TEST
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ Support Meson SoC Family GPIO Interrupt Multiplexer
+
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc85abdb..33f913d037d0 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
+obj-$(CONFIG_MESON_GPIO_IRQ) += irq-meson-gpio.o
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
new file mode 100644
index 000000000000..184025a9cdaf
--- /dev/null
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#define IRQ_FREE (-1)
+
+#define REG_EDGE_POL 0x00
+#define REG_PIN_03_SEL 0x04
+#define REG_PIN_47_SEL 0x08
+#define REG_FILTER_SEL 0x0c
+
+#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x)))
+#define REG_EDGE_POL_EDGE(x) BIT(x)
+#define REG_EDGE_POL_LOW(x) BIT(16 + (x))
+#define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8)
+#define REG_FILTER_SEL_SHIFT(x) ((x) * 4)
+
+struct meson_gpio_irq_params {
+ unsigned int nr_hwirqs;
+};
+
+struct meson_gpio_irq_domain {
+ struct irq_fwspec *parent_irqs;
+ void __iomem *base;
+ int nr_parent_irqs;
+ int *irq_map;
+};
+
+struct meson_gpio_irq_chip {
+ void __iomem *base;
+ int index;
+};
+
+static const struct meson_gpio_irq_params meson8_params = {
+ .nr_hwirqs = 134,
+};
+
+static const struct meson_gpio_irq_params meson8b_params = {
+ .nr_hwirqs = 119,
+};
+
+static const struct meson_gpio_irq_params gxbb_params = {
+ .nr_hwirqs = 133,
+};
+
+static const struct of_device_id meson_irq_gpio_matches[] = {
+ { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
+ { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
+ { .compatible = "amlogic,gxbb-gpio-intc", .data = &gxbb_params },
+ { }
+};
+
+static void meson_gpio_irq_update_bits(void __iomem *base, unsigned int reg,
+ u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = readl(base + reg);
+ tmp &= ~mask;
+ tmp |= val;
+
+ writel(tmp, base + reg);
+}
+
+static int meson_gpio_irq_get_index(struct meson_gpio_irq_domain *domain_data,
+ int hwirq)
+{
+ int i;
+
+ for (i = 0; i < domain_data->nr_parent_irqs; i++) {
+ if (domain_data->irq_map[i] == hwirq)
+ return i;
+ }
+
+ return -1;
+}
+
+static int meson_gpio_irq_map_pirq(struct meson_gpio_irq_domain *domain_data,
+ irq_hw_number_t hwirq)
+{
+ int index;
+ unsigned int reg;
+
+ index = meson_gpio_irq_get_index(domain_data, IRQ_FREE);
+ if (index < 0) {
+ pr_err("No irq available\n");
+ return -ENOSPC;
+ }
+
+ domain_data->irq_map[index] = hwirq;
+
+ reg = (index < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL;
+ meson_gpio_irq_update_bits(domain_data->base, reg,
+ 0xff << REG_PIN_SEL_SHIFT(index),
+ hwirq << REG_PIN_SEL_SHIFT(index));
+
+ pr_debug("hwirq %d assigned to channel %d\n", (int)hwirq, index);
+
+ return index;
+}
+
+static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct meson_gpio_irq_chip *cd = irq_data_get_irq_chip_data(data);
+ u32 val = 0;
+
+ pr_debug("set type of hwirq %lu to %u\n", data->hwirq, type);
+
+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ return -EINVAL;
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ val |= REG_EDGE_POL_EDGE(cd->index);
+
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
+ val |= REG_EDGE_POL_LOW(cd->index);
+
+ /*
+ * According to the datasheet, the polarity block invert the
+ * signal on the path to parent interrupt
+ */
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ type = (type & ~IRQ_TYPE_LEVEL_LOW)
+ | IRQ_TYPE_LEVEL_HIGH;
+ else
+ type = (type & ~IRQ_TYPE_EDGE_FALLING)
+ | IRQ_TYPE_EDGE_RISING;
+ }
+
+ meson_gpio_irq_update_bits(cd->base, REG_EDGE_POL,
+ REG_EDGE_POL_MASK(cd->index), val);
+
+ return irq_chip_set_type_parent(data, type);
+}
+
+static struct irq_chip meson_gpio_irq_chip = {
+ .name = "meson-gpio-irqchip",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_type = meson_gpio_irq_set_type,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+#endif
+};
+
+static int meson_gpio_irq_domain_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int meson_gpio_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs,
+ void *data)
+{
+ struct irq_fwspec *fwspec_parent, *fwspec = data;
+ struct meson_gpio_irq_domain *domain_data = domain->host_data;
+ struct meson_gpio_irq_chip *cd;
+ unsigned long hwirq;
+ unsigned int type;
+ int i, index, ret;
+
+ ret = meson_gpio_irq_domain_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return ret;
+
+ pr_debug("irq %d, nr_irqs %d, hwirqs %lu\n", virq, nr_irqs, hwirq);
+
+ for (i = 0; i < nr_irqs; i++) {
+ index = meson_gpio_irq_map_pirq(domain_data, hwirq + i);
+ if (index < 0)
+ return index;
+
+ cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+ if (!cd)
+ return -ENOMEM;
+
+ cd->base = domain_data->base;
+ cd->index = index;
+ fwspec_parent = &domain_data->parent_irqs[index];
+
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &meson_gpio_irq_chip,
+ cd);
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1,
+ fwspec_parent);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void meson_gpio_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct meson_gpio_irq_domain *domain_data = domain->host_data;
+ struct meson_gpio_irq_chip *cd;
+ struct irq_data *irq_data;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ cd = irq_data_get_irq_chip_data(irq_data);
+
+ domain_data->irq_map[cd->index] = IRQ_FREE;
+ kfree(cd);
+ }
+
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+
+static const struct irq_domain_ops meson_gpio_irq_domain_ops = {
+ .alloc = meson_gpio_irq_domain_alloc,
+ .free = meson_gpio_irq_domain_free,
+ .translate = meson_gpio_irq_domain_translate,
+};
+
+
+static int __init meson_gpio_irq_get_one_pirq(struct device_node *node,
+ int index,
+ struct irq_fwspec *pirq)
+{
+ int ret, i;
+ struct of_phandle_args oirq;
+
+ ret = of_irq_parse_one(node, index, &oirq);
+ if (ret < 0)
+ return ret;
+
+ pirq->fwnode = of_node_to_fwnode(oirq.np);
+
+ if (!pirq->fwnode) {
+ pr_err("can't get interrupt fwnode\n");
+ return -ENODEV;
+ }
+
+ pirq->param_count = oirq.args_count;
+ for (i = 0; i < oirq.args_count; i++)
+ pirq->param[i] = oirq.args[i];
+
+ return 0;
+}
+
+
+static int __init
+meson_gpio_irq_init_domain(struct device_node *node,
+ struct meson_gpio_irq_domain *domain_data)
+{
+ int ret, i, n_pirqs;
+ int *map;
+ struct irq_fwspec *pirqs;
+
+ n_pirqs = of_irq_count(node);
+ if (n_pirqs == 0) {
+ pr_err("missing parent interrupts\n");
+ return -ENODEV;
+ }
+
+ pirqs = kcalloc(n_pirqs, sizeof(*pirqs), GFP_KERNEL);
+ if (!pirqs)
+ return -ENOMEM;
+
+ map = kcalloc(n_pirqs, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ for (i = 0; i < n_pirqs; i++) {
+ map[i] = IRQ_FREE;
+ ret = meson_gpio_irq_get_one_pirq(node, i, &pirqs[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ domain_data->nr_parent_irqs = n_pirqs;
+ domain_data->parent_irqs = pirqs;
+ domain_data->irq_map = map;
+
+ return 0;
+}
+
+static int __init meson_gpio_irq_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *domain, *parent_domain;
+ const struct of_device_id *match;
+ const struct meson_gpio_irq_params *params;
+ struct meson_gpio_irq_domain *domain_data;
+ int ret;
+
+ match = of_match_node(meson_irq_gpio_matches, node);
+ if (!match)
+ return -ENODEV;
+ params = match->data;
+
+ if (!parent) {
+ pr_err("missing parent interrupt node\n");
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("unable to obtain parent domain\n");
+ return -ENXIO;
+ }
+
+ domain_data = kzalloc(sizeof(*domain_data), GFP_KERNEL);
+ if (!domain_data)
+ return -ENOMEM;
+
+ domain_data->base = of_iomap(node, 0);
+ if (!domain_data->base) {
+ ret = -ENOMEM;
+ goto out_free_dev;
+ }
+
+ ret = meson_gpio_irq_init_domain(node, domain_data);
+ if (ret < 0)
+ goto out_free_dev_content;
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, params->nr_hwirqs,
+ node, &meson_gpio_irq_domain_ops,
+ domain_data);
+
+ if (!domain) {
+ pr_err("failed to allocated domain\n");
+ ret = -ENOMEM;
+ goto out_free_dev_content;
+ }
+
+ pr_info("%d to %d gpio interrupt mux initialized\n",
+ params->nr_hwirqs, domain_data->nr_parent_irqs);
+
+ return 0;
+
+out_free_dev_content:
+ kfree(domain_data->parent_irqs);
+ kfree(domain_data->irq_map);
+ iounmap(domain_data->base);
+
+out_free_dev:
+ kfree(domain_data);
+
+ return ret;
+}
+IRQCHIP_DECLARE(meson8_gpio_intc, "amlogic,meson8-gpio-intc",
+ meson_gpio_irq_of_init);
+IRQCHIP_DECLARE(meson8b_gpio_intc, "amlogic,meson8b-gpio-intc",
+ meson_gpio_irq_of_init);
+IRQCHIP_DECLARE(gxbb_gpio_intc, "amlogic,gxbb-gpio-intc",
+ meson_gpio_irq_of_init);
--
2.7.4
^ permalink raw reply related
* [RFC 00/10] irqchip: meson: add support for the gpio interrupt controller
From: Jerome Brunet @ 2016-10-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
This patch series adds support for the GPIO interrupt controller found
on Amlogic's meson SoC families.
Unlike what the name suggests, this controller is not part of the SoC GPIO
subsystem. It's an indepedent controller which can watch almost all pad of
the SoC and generate and interrupt from it. Some pins, which are not part
of the public datasheet, don't seem to have this capability though.
Hardware wise, the controller is a 256 to 8 multiplexer. It can take up
to 256 input pads and route them to any of 8 GIC's interrupts. There is also
a filter block in the middle to select the appropriate edge or level.
The number of interrupt declared by the irqchip is lowered from 256 to the
actual number of signal routed to the controller on each SoC family. As we
have access to only 8 GIC?s interrupts, these are allocated when an
interrupt is requested from the controller, on a first come, first served
basis.
This series has been tested on Amlogic S905-P200 board with the front
panel power button. Directly passing an IRQ or using gpio_to_irq both work
with this driver.
This work is derived from the previous work of Carlo Caione [1].
http://lkml.kernel.org/r/1448987062-31225-1-git-send-email-carlo at caione.org
Note:
As the comment will explain, patch 10 is not strictly required but would
be an appreciated bonus.
Jerome Brunet (10):
irqchip: meson: add support for gpio interrupt controller
dt-bindings: interrupt-controller: add DT binding for meson GPIO
interrupt controller
pinctrl: meson: update pinctrl data with gpio irq base number
pinctrl: meson: allow gpio to request irq
dt-bindings: pinctrl: meson: update gpio dt-bindings
ARM64: meson: enable MESON_IRQ_GPIO in Kconfig
ARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8
ARM64: dts: amlogic: enable gpio interrupt controller on gxbb
ARM: dts: amlogic: enable gpio interrupt controller on meson8
irqchip: meson: Add support for IRQ_TYPE_EDGE_BOTH
.../amlogic,meson-gpio-intc.txt | 39 ++
.../devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 +
arch/arm/boot/dts/meson8.dtsi | 19 +
arch/arm/boot/dts/meson8b.dtsi | 19 +
arch/arm/mach-meson/Kconfig | 2 +
arch/arm64/Kconfig.platforms | 1 +
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 17 +
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-meson-gpio.c | 437 +++++++++++++++++++++
drivers/pinctrl/Kconfig | 2 +
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 22 +-
drivers/pinctrl/meson/pinctrl-meson.c | 83 +++-
drivers/pinctrl/meson/pinctrl-meson.h | 16 +-
drivers/pinctrl/meson/pinctrl-meson8.c | 20 +-
drivers/pinctrl/meson/pinctrl-meson8b.c | 32 +-
16 files changed, 686 insertions(+), 37 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
create mode 100644 drivers/irqchip/irq-meson-gpio.c
--
2.7.4
^ permalink raw reply
* [PATCH 2/2] mfd: ab8500-debugfs: remove unused function
From: Lee Jones @ 2016-10-04 14:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474695413-30460-1-git-send-email-baoyou.xie@linaro.org>
On Sat, 24 Sep 2016, Baoyou Xie wrote:
> We get 1 warning when building kernel with W=1:
> drivers/mfd/ab8500-debugfs.c:1395:6: warning: no previous prototype for 'ab8500_dump_all_banks_to_mem' [-Wmissing-prototypes]
>
> In fact, this function is called by no one and not exported,
> so this patch removes it.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> drivers/mfd/ab8500-debugfs.c | 54 --------------------------------------------
> 1 file changed, 54 deletions(-)
This is already in -next:
e310960300e78764f59a4b044205b02a5c59381a
> diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
> index 0aecd7b..9f04a25 100644
> --- a/drivers/mfd/ab8500-debugfs.c
> +++ b/drivers/mfd/ab8500-debugfs.c
> @@ -1382,60 +1382,6 @@ void ab8500_dump_all_banks(struct device *dev)
> }
> }
>
> -/* Space for 500 registers. */
> -#define DUMP_MAX_REGS 700
> -static struct ab8500_register_dump
> -{
> - u8 bank;
> - u8 reg;
> - u8 value;
> -} ab8500_complete_register_dump[DUMP_MAX_REGS];
> -
> -/* This shall only be called upon kernel panic! */
> -void ab8500_dump_all_banks_to_mem(void)
> -{
> - int i, r = 0;
> - u8 bank;
> - int err = 0;
> -
> - pr_info("Saving all ABB registers for crash analysis.\n");
> -
> - for (bank = 0; bank < AB8500_NUM_BANKS; bank++) {
> - for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
> - u8 reg;
> -
> - for (reg = debug_ranges[bank].range[i].first;
> - reg <= debug_ranges[bank].range[i].last;
> - reg++) {
> - u8 value;
> -
> - err = prcmu_abb_read(bank, reg, &value, 1);
> -
> - if (err < 0)
> - goto out;
> -
> - ab8500_complete_register_dump[r].bank = bank;
> - ab8500_complete_register_dump[r].reg = reg;
> - ab8500_complete_register_dump[r].value = value;
> -
> - r++;
> -
> - if (r >= DUMP_MAX_REGS) {
> - pr_err("%s: too many register to dump!\n",
> - __func__);
> - err = -EINVAL;
> - goto out;
> - }
> - }
> - }
> - }
> -out:
> - if (err >= 0)
> - pr_info("Saved all ABB registers.\n");
> - else
> - pr_info("Failed to save all ABB registers.\n");
> -}
> -
> static int ab8500_all_banks_open(struct inode *inode, struct file *file)
> {
> struct seq_file *s;
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v6] soc: qcom: add l2 cache perf events driver
From: Neil Leeder @ 2016-10-04 14:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474492374-12140-1-git-send-email-nleeder@codeaurora.org>
On 9/21/2016 05:12 PM, Neil Leeder wrote:
> Adds perf events support for L2 cache PMU.
>
> The L2 cache PMU driver is named 'l2cache_0' and can be used
> with perf events to profile L2 events such as cache hits
> and misses.
>
> Signed-off-by: Neil Leeder <nleeder@codeaurora.org>
> ---
> v6: restore accidentally dropped Kconfig dependencies
>
> v5:
> Fold the header and l2-accessors into .c file
> Use multi-instance framework for hotplug
> Change terminology from slice to cluster for clarity
> Remove unnecessary rmw sequence for enable registers
> Use prev_count in hwc rather than in slice
> Enforce all events in same group on same CPU
> Add comments, rename variables for clarity
>
> v4:
> Replace notifier with hotplug statemachine
> Allocate PMU struct dynamically
>
> v3:
> Remove exports from l2-accessors
> Change l2-accessors Kconfig to make it not user-selectable
> Reorder and remove unnecessary includes
>
> v2:
> Add the l2-accessors patch to this patchset, previously posted separately.
> Remove sampling and per-task functionality for this uncore PMU.
> Use cpumask to replace code which filtered events to one cpu per slice.
> Replace manual event filtering with filter_match callback.
> Use a separate used_mask for event groups.
> Add hotplug notifier for CPU and irq migration.
> Remove extraneous synchronisation instructions.
> Other miscellaneous cleanup.
>
> drivers/soc/qcom/Kconfig | 9 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/perf_event_l2.c | 948 +++++++++++++++++++++++++++++++++++++++
> include/linux/cpuhotplug.h | 1 +
> 4 files changed, 959 insertions(+)
> create mode 100644 drivers/soc/qcom/perf_event_l2.c
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 461b387..3fa27a8 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -10,6 +10,15 @@ config QCOM_GSBI
> functions for connecting the underlying serial UART, SPI, and I2C
> devices to the output pins.
>
> +config QCOM_PERF_EVENTS_L2
> + bool "Qualcomm Technologies L2-cache perf events"
> + depends on ARCH_QCOM && ARM64 && HW_PERF_EVENTS && ACPI
> + help
> + Provides support for the L2 cache performance monitor unit (PMU)
> + in Qualcomm Technologies processors.
> + Adds the L2 cache PMU into the perf events subsystem for
> + monitoring L2 cache events.
> +
> config QCOM_PM
> bool "Qualcomm Power Management"
> depends on ARCH_QCOM && !ARM64
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index fdd664e..4c9df3b 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -1,4 +1,5 @@
> obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
> +obj-$(CONFIG_QCOM_PERF_EVENTS_L2) += perf_event_l2.o
> obj-$(CONFIG_QCOM_PM) += spm.o
> obj-$(CONFIG_QCOM_SMD) += smd.o
> obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
> diff --git a/drivers/soc/qcom/perf_event_l2.c b/drivers/soc/qcom/perf_event_l2.c
> new file mode 100644
> index 0000000..bbf47c9
> --- /dev/null
> +++ b/drivers/soc/qcom/perf_event_l2.c
> @@ -0,0 +1,948 @@
> +/* Copyright (c) 2015,2016 The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +#include <linux/acpi.h>
> +#include <linux/interrupt.h>
> +#include <linux/perf_event.h>
> +#include <linux/platform_device.h>
> +
> +#define MAX_L2_CTRS 9
> +
> +#define L2PMCR_NUM_EV_SHIFT 11
> +#define L2PMCR_NUM_EV_MASK 0x1F
> +
> +#define L2PMCR 0x400
> +#define L2PMCNTENCLR 0x403
> +#define L2PMCNTENSET 0x404
> +#define L2PMINTENCLR 0x405
> +#define L2PMINTENSET 0x406
> +#define L2PMOVSCLR 0x407
> +#define L2PMOVSSET 0x408
> +#define L2PMCCNTCR 0x409
> +#define L2PMCCNTR 0x40A
> +#define L2PMCCNTSR 0x40C
> +#define L2PMRESR 0x410
> +#define IA_L2PMXEVCNTCR_BASE 0x420
> +#define IA_L2PMXEVCNTR_BASE 0x421
> +#define IA_L2PMXEVFILTER_BASE 0x423
> +#define IA_L2PMXEVTYPER_BASE 0x424
> +
> +#define IA_L2_REG_OFFSET 0x10
> +
> +#define L2PMXEVFILTER_SUFILTER_ALL 0x000E0000
> +#define L2PMXEVFILTER_ORGFILTER_IDINDEP 0x00000004
> +#define L2PMXEVFILTER_ORGFILTER_ALL 0x00000003
> +
> +#define L2PM_CC_ENABLE 0x80000000
> +
> +#define L2EVTYPER_REG_SHIFT 3
> +
> +#define L2PMRESR_GROUP_BITS 8
> +#define L2PMRESR_GROUP_MASK GENMASK(7, 0)
> +
> +#define L2CYCLE_CTR_BIT 31
> +#define L2CYCLE_CTR_RAW_CODE 0xFE
> +
> +#define L2PMCR_RESET_ALL 0x6
> +#define L2PMCR_COUNTERS_ENABLE 0x1
> +#define L2PMCR_COUNTERS_DISABLE 0x0
> +
> +#define L2PMRESR_EN ((u64)1 << 63)
> +
> +#define L2_EVT_MASK 0x00000FFF
> +#define L2_EVT_CODE_MASK 0x00000FF0
> +#define L2_EVT_GRP_MASK 0x0000000F
> +#define L2_EVT_CODE_SHIFT 4
> +#define L2_EVT_GRP_SHIFT 0
> +
> +#define L2_EVT_CODE(event) (((event) & L2_EVT_CODE_MASK) >> L2_EVT_CODE_SHIFT)
> +#define L2_EVT_GROUP(event) (((event) & L2_EVT_GRP_MASK) >> L2_EVT_GRP_SHIFT)
> +
> +#define L2_EVT_GROUP_MAX 7
> +
> +#define L2_MAX_PERIOD U32_MAX
> +#define L2_CNT_PERIOD (U32_MAX - GENMASK(26, 0))
> +
> +#define L2CPUSRSELR_EL1 S3_3_c15_c0_6
> +#define L2CPUSRDR_EL1 S3_3_c15_c0_7
> +
> +static DEFINE_RAW_SPINLOCK(l2_access_lock);
> +
> +/**
> + * set_l2_indirect_reg: write value to an L2 register
> + * @reg: Address of L2 register.
> + * @value: Value to be written to register.
> + *
> + * Use architecturally required barriers for ordering between system register
> + * accesses
> + */
> +static void set_l2_indirect_reg(u64 reg, u64 val)
> +{
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&l2_access_lock, flags);
> + write_sysreg(reg, L2CPUSRSELR_EL1);
> + isb();
> + write_sysreg(val, L2CPUSRDR_EL1);
> + isb();
> + raw_spin_unlock_irqrestore(&l2_access_lock, flags);
> +}
> +
> +/**
> + * get_l2_indirect_reg: read an L2 register value
> + * @reg: Address of L2 register.
> + *
> + * Use architecturally required barriers for ordering between system register
> + * accesses
> + */
> +static u64 get_l2_indirect_reg(u64 reg)
> +{
> + u64 val;
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&l2_access_lock, flags);
> + write_sysreg(reg, L2CPUSRSELR_EL1);
> + isb();
> + val = read_sysreg(L2CPUSRDR_EL1);
> + raw_spin_unlock_irqrestore(&l2_access_lock, flags);
> +
> + return val;
> +}
> +
> +/*
> + * Aggregate PMU. Implements the core pmu functions and manages
> + * the hardware PMUs.
> + */
> +struct l2cache_pmu {
> + struct hlist_node node;
> + u32 num_pmus;
> + struct pmu pmu;
> + int num_counters;
> + cpumask_t cpumask;
> + struct platform_device *pdev;
> +};
> +
> +/*
> + * The cache is made up of one or more clusters, each cluster has its own PMU.
> + * Each cluster is associated with one or more CPUs.
> + * This structure represents one of the hardware PMUs.
> + *
> + * Events can be envisioned as a 2-dimensional array. Each column represents
> + * a group of events. There are 8 groups. Only one entry from each
> + * group can be in use at a time. When an event is assigned a counter
> + * by *_event_add(), the counter index is assigned to group_to_counter[group].
> + * This allows *filter_match() to detect and reject conflicting events in
> + * the same group.
> + * Events are specified as 0xCCG, where CC is 2 hex digits specifying
> + * the code (array row) and G specifies the group (column).
> + *
> + * In addition there is a cycle counter event specified by L2CYCLE_CTR_RAW_CODE
> + * which is outside the above scheme.
> + */
> +struct hml2_pmu {
> + struct perf_event *events[MAX_L2_CTRS];
> + struct l2cache_pmu *l2cache_pmu;
> + DECLARE_BITMAP(used_counters, MAX_L2_CTRS);
> + DECLARE_BITMAP(used_groups, L2_EVT_GROUP_MAX + 1);
> + int group_to_counter[L2_EVT_GROUP_MAX + 1];
> + int irq;
> + /* The CPU that is used for collecting events on this cluster */
> + int on_cpu;
> + /* All the CPUs associated with this cluster */
> + cpumask_t cluster_cpus;
> + spinlock_t pmu_lock;
> +};
> +
> +#define to_l2cache_pmu(p) (container_of(p, struct l2cache_pmu, pmu))
> +
> +static DEFINE_PER_CPU(struct hml2_pmu *, pmu_cluster);
> +static u32 l2_cycle_ctr_idx;
> +static u32 l2_counter_present_mask;
> +
> +static inline u32 idx_to_reg_bit(u32 idx)
> +{
> + if (idx == l2_cycle_ctr_idx)
> + return BIT(L2CYCLE_CTR_BIT);
> +
> + return BIT(idx);
> +}
> +
> +static inline struct hml2_pmu *get_hml2_pmu(int cpu)
> +{
> + return per_cpu(pmu_cluster, cpu);
> +}
> +
> +static void hml2_pmu__reset_on_cluster(void *x)
> +{
> + /* Reset all ctrs */
> + set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
> + set_l2_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask);
> + set_l2_indirect_reg(L2PMINTENCLR, l2_counter_present_mask);
> + set_l2_indirect_reg(L2PMOVSCLR, l2_counter_present_mask);
> +}
> +
> +static inline void hml2_pmu__reset(struct hml2_pmu *cluster)
> +{
> + cpumask_t *mask = &cluster->cluster_cpus;
> +
> + if (smp_call_function_any(mask, hml2_pmu__reset_on_cluster, NULL, 1))
> + dev_err(&cluster->l2cache_pmu->pdev->dev,
> + "Failed to reset on cluster with cpu %d\n",
> + cpumask_first(&cluster->cluster_cpus));
> +}
> +
> +static inline void hml2_pmu__enable(void)
> +{
> + set_l2_indirect_reg(L2PMCR, L2PMCR_COUNTERS_ENABLE);
> +}
> +
> +static inline void hml2_pmu__disable(void)
> +{
> + set_l2_indirect_reg(L2PMCR, L2PMCR_COUNTERS_DISABLE);
> +}
> +
> +static inline void hml2_pmu__counter_set_value(u32 idx, u64 value)
> +{
> + u32 counter_reg;
> +
> + if (idx == l2_cycle_ctr_idx) {
> + set_l2_indirect_reg(L2PMCCNTR, value);
> + } else {
> + counter_reg = (idx * IA_L2_REG_OFFSET) + IA_L2PMXEVCNTR_BASE;
> + set_l2_indirect_reg(counter_reg, value & GENMASK(31, 0));
> + }
> +}
> +
> +static inline u64 hml2_pmu__counter_get_value(u32 idx)
> +{
> + u64 value;
> + u32 counter_reg;
> +
> + if (idx == l2_cycle_ctr_idx) {
> + value = get_l2_indirect_reg(L2PMCCNTR);
> + } else {
> + counter_reg = (idx * IA_L2_REG_OFFSET) + IA_L2PMXEVCNTR_BASE;
> + value = get_l2_indirect_reg(counter_reg);
> + }
> +
> + return value;
> +}
> +
> +static inline void hml2_pmu__counter_enable(u32 idx)
> +{
> + set_l2_indirect_reg(L2PMCNTENSET, idx_to_reg_bit(idx));
> +}
> +
> +static inline void hml2_pmu__counter_disable(u32 idx)
> +{
> + set_l2_indirect_reg(L2PMCNTENCLR, idx_to_reg_bit(idx));
> +}
> +
> +static inline void hml2_pmu__counter_enable_interrupt(u32 idx)
> +{
> + set_l2_indirect_reg(L2PMINTENSET, idx_to_reg_bit(idx));
> +}
> +
> +static inline void hml2_pmu__counter_disable_interrupt(u32 idx)
> +{
> + set_l2_indirect_reg(L2PMINTENCLR, idx_to_reg_bit(idx));
> +}
> +
> +static inline void hml2_pmu__set_evccntcr(u32 val)
> +{
> + set_l2_indirect_reg(L2PMCCNTCR, val);
> +}
> +
> +static inline void hml2_pmu__set_evcntcr(u32 ctr, u32 val)
> +{
> + u32 evtcr_reg = (ctr * IA_L2_REG_OFFSET) + IA_L2PMXEVCNTCR_BASE;
> +
> + set_l2_indirect_reg(evtcr_reg, val);
> +}
> +
> +static inline void hml2_pmu__set_evtyper(u32 ctr, u32 val)
> +{
> + u32 evtype_reg = (ctr * IA_L2_REG_OFFSET) + IA_L2PMXEVTYPER_BASE;
> +
> + set_l2_indirect_reg(evtype_reg, val);
> +}
> +
> +static void hml2_pmu__set_resr(struct hml2_pmu *cluster,
> + u32 event_group, u32 event_cc)
> +{
> + u64 field;
> + u64 resr_val;
> + u32 shift;
> + unsigned long flags;
> +
> + shift = L2PMRESR_GROUP_BITS * event_group;
> + field = ((u64)(event_cc & L2PMRESR_GROUP_MASK) << shift) | L2PMRESR_EN;
> +
> + spin_lock_irqsave(&cluster->pmu_lock, flags);
> +
> + resr_val = get_l2_indirect_reg(L2PMRESR);
> + resr_val &= ~(L2PMRESR_GROUP_MASK << shift);
> + resr_val |= field;
> + set_l2_indirect_reg(L2PMRESR, resr_val);
> +
> + spin_unlock_irqrestore(&cluster->pmu_lock, flags);
> +}
> +
> +/*
> + * Hardware allows filtering of events based on the originating
> + * CPU. Turn this off by setting filter bits to allow events from
> + * all CPUS, subunits and ID independent events in this cluster.
> + */
> +static inline void hml2_pmu__set_evfilter_sys_mode(u32 ctr)
> +{
> + u32 reg = (ctr * IA_L2_REG_OFFSET) + IA_L2PMXEVFILTER_BASE;
> + u32 val = L2PMXEVFILTER_SUFILTER_ALL |
> + L2PMXEVFILTER_ORGFILTER_IDINDEP |
> + L2PMXEVFILTER_ORGFILTER_ALL;
> +
> + set_l2_indirect_reg(reg, val);
> +}
> +
> +static inline u32 hml2_pmu__getreset_ovsr(void)
> +{
> + u32 result = get_l2_indirect_reg(L2PMOVSSET);
> +
> + set_l2_indirect_reg(L2PMOVSCLR, result);
> + return result;
> +}
> +
> +static inline bool hml2_pmu__has_overflowed(u32 ovsr)
> +{
> + return !!(ovsr & l2_counter_present_mask);
> +}
> +
> +static inline bool hml2_pmu__counter_has_overflowed(u32 ovsr, u32 idx)
> +{
> + return !!(ovsr & idx_to_reg_bit(idx));
> +}
> +
> +static void l2_cache__event_update_from_cluster(struct perf_event *event,
> + struct hml2_pmu *cluster)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + u64 delta64, prev, now;
> + u32 delta;
> + u32 idx = hwc->idx;
> +
> + do {
> + prev = local64_read(&hwc->prev_count);
> + now = hml2_pmu__counter_get_value(idx);
> + } while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
> +
> + if (idx == l2_cycle_ctr_idx) {
> + /*
> + * The cycle counter is 64-bit so needs separate handling
> + * of 64-bit delta.
> + */
> + delta64 = now - prev;
> + local64_add(delta64, &event->count);
> + } else {
> + /*
> + * 32-bit counters need the unsigned 32-bit math to handle
> + * overflow and now < prev
> + */
> + delta = now - prev;
> + local64_add(delta, &event->count);
> + }
> +}
> +
> +static void l2_cache__cluster_set_period(struct hml2_pmu *cluster,
> + struct hw_perf_event *hwc)
> +{
> + u64 base = L2_MAX_PERIOD - (L2_CNT_PERIOD - 1);
> + u32 idx = hwc->idx;
> + u64 prev = local64_read(&hwc->prev_count);
> + u64 value;
> +
> + /*
> + * Limit the maximum period to prevent the counter value
> + * from overtaking the one we are about to program.
> + * Use a starting value which is high enough that after
> + * an overflow, interrupt latency will not cause the count
> + * to reach the base value. If the previous value
> + * is below the base, increase it to be above the base
> + * and update prev_count accordingly. Otherwise if
> + * the previous value is already above the base
> + * nothing needs to be done to prev_count.
> + */
> + if (prev < base) {
> + value = base + prev;
> + local64_set(&hwc->prev_count, value);
> + } else {
> + value = prev;
> + }
> +
> + hml2_pmu__counter_set_value(idx, value);
> +}
> +
> +static int l2_cache__get_event_idx(struct hml2_pmu *cluster,
> + struct perf_event *event)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + int idx;
> +
> + if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
> + if (test_and_set_bit(l2_cycle_ctr_idx, cluster->used_counters))
> + return -EAGAIN;
> +
> + return l2_cycle_ctr_idx;
> + }
> +
> + for (idx = 0; idx < cluster->l2cache_pmu->num_counters - 1; idx++) {
> + if (!test_and_set_bit(idx, cluster->used_counters)) {
> + set_bit(L2_EVT_GROUP(hwc->config_base),
> + cluster->used_groups);
> + return idx;
> + }
> + }
> +
> + /* The counters are all in use. */
> + return -EAGAIN;
> +}
> +
> +static void l2_cache__clear_event_idx(struct hml2_pmu *cluster,
> + struct perf_event *event)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + int idx = hwc->idx;
> +
> + clear_bit(idx, cluster->used_counters);
> + if (hwc->config_base != L2CYCLE_CTR_RAW_CODE)
> + clear_bit(L2_EVT_GROUP(hwc->config_base), cluster->used_groups);
> +}
> +
> +static irqreturn_t l2_cache__handle_irq(int irq_num, void *data)
> +{
> + struct hml2_pmu *cluster = data;
> + int num_counters = cluster->l2cache_pmu->num_counters;
> + u32 ovsr;
> + int idx;
> +
> + ovsr = hml2_pmu__getreset_ovsr();
> + if (!hml2_pmu__has_overflowed(ovsr))
> + return IRQ_NONE;
> +
> + for_each_set_bit(idx, cluster->used_counters, num_counters) {
> + struct perf_event *event = cluster->events[idx];
> + struct hw_perf_event *hwc;
> +
> + if (!hml2_pmu__counter_has_overflowed(ovsr, idx))
> + continue;
> +
> + l2_cache__event_update_from_cluster(event, cluster);
> + hwc = &event->hw;
> +
> + l2_cache__cluster_set_period(cluster, hwc);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +/*
> + * Implementation of abstract pmu functionality required by
> + * the core perf events code.
> + */
> +
> +static void l2_cache__pmu_enable(struct pmu *pmu)
> +{
> + /*
> + * Although there is only one PMU (per socket) controlling multiple
> + * physical PMUs (per cluster), because we do not support per-task mode
> + * each event is associated with a CPU. Each event has pmu_enable
> + * called on its CPU, so here it is only necessary to enable the
> + * counters for the current CPU.
> + */
> +
> + hml2_pmu__enable();
> +}
> +
> +static void l2_cache__pmu_disable(struct pmu *pmu)
> +{
> + hml2_pmu__disable();
> +}
> +
> +static int l2_cache__event_init(struct perf_event *event)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + struct hml2_pmu *cluster;
> + struct perf_event *sibling;
> + struct l2cache_pmu *l2cache_pmu;
> +
> + if (event->attr.type != event->pmu->type)
> + return -ENOENT;
> +
> + l2cache_pmu = to_l2cache_pmu(event->pmu);
> +
> + if (hwc->sample_period) {
> + dev_warn(&l2cache_pmu->pdev->dev, "Sampling not supported\n");
> + return -EOPNOTSUPP;
> + }
> +
> + if (event->cpu < 0) {
> + dev_warn(&l2cache_pmu->pdev->dev, "Per-task mode not supported\n");
> + return -EOPNOTSUPP;
> + }
> +
> + /* We cannot filter accurately so we just don't allow it. */
> + if (event->attr.exclude_user || event->attr.exclude_kernel ||
> + event->attr.exclude_hv || event->attr.exclude_idle) {
> + dev_warn(&l2cache_pmu->pdev->dev, "Can't exclude execution levels\n");
> + return -EOPNOTSUPP;
> + }
> +
> + if (((L2_EVT_GROUP(event->attr.config) > L2_EVT_GROUP_MAX) ||
> + ((event->attr.config & ~L2_EVT_MASK) != 0)) &&
> + (event->attr.config != L2CYCLE_CTR_RAW_CODE)) {
> + dev_warn(&l2cache_pmu->pdev->dev, "Invalid config %llx\n",
> + event->attr.config);
> + return -EINVAL;
> + }
> +
> + /* Don't allow groups with mixed PMUs, except for s/w events */
> + if (event->group_leader->pmu != event->pmu &&
> + !is_software_event(event->group_leader)) {
> + dev_warn(&l2cache_pmu->pdev->dev,
> + "Can't create mixed PMU group\n");
> + return -EINVAL;
> + }
> +
> + list_for_each_entry(sibling, &event->group_leader->sibling_list,
> + group_entry)
> + if (sibling->pmu != event->pmu &&
> + !is_software_event(sibling)) {
> + dev_warn(&l2cache_pmu->pdev->dev,
> + "Can't create mixed PMU group\n");
> + return -EINVAL;
> + }
> +
> + /* Ensure all events in a group are on the same cpu */
> + cluster = get_hml2_pmu(event->cpu);
> + if ((event->group_leader != event) &&
> + (cluster->on_cpu != event->group_leader->cpu)) {
> + dev_warn(&l2cache_pmu->pdev->dev,
> + "Can't create group on CPUs %d and %d",
> + event->cpu, event->group_leader->cpu);
> + return -EINVAL;
> + }
> +
> + hwc->idx = -1;
> + hwc->config_base = event->attr.config;
> +
> + /*
> + * Ensure all events are on the same cpu so all events are in the
> + * same cpu context, to avoid races on pmu_enable etc.
> + */
> + event->cpu = cluster->on_cpu;
> +
> + return 0;
> +}
> +
> +static void l2_cache__event_start(struct perf_event *event, int flags)
> +{
> + struct hml2_pmu *cluster;
> + struct hw_perf_event *hwc = &event->hw;
> + int idx = hwc->idx;
> + u32 config;
> + u32 event_cc, event_group;
> +
> + hwc->state = 0;
> +
> + cluster = get_hml2_pmu(event->cpu);
> + l2_cache__cluster_set_period(cluster, hwc);
> +
> + if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
> + hml2_pmu__set_evccntcr(0x0);
> + } else {
> + config = hwc->config_base;
> + event_cc = L2_EVT_CODE(config);
> + event_group = L2_EVT_GROUP(config);
> +
> + hml2_pmu__set_evcntcr(idx, 0x0);
> + hml2_pmu__set_evtyper(idx, event_group);
> + hml2_pmu__set_resr(cluster, event_group, event_cc);
> + hml2_pmu__set_evfilter_sys_mode(idx);
> + }
> +
> + hml2_pmu__counter_enable_interrupt(idx);
> + hml2_pmu__counter_enable(idx);
> +}
> +
> +static void l2_cache__event_stop(struct perf_event *event, int flags)
> +{
> + struct hml2_pmu *cluster;
> + struct hw_perf_event *hwc = &event->hw;
> + int idx = hwc->idx;
> +
> + if (!(hwc->state & PERF_HES_STOPPED)) {
> + cluster = get_hml2_pmu(event->cpu);
> + hml2_pmu__counter_disable_interrupt(idx);
> + hml2_pmu__counter_disable(idx);
> +
> + if (flags & PERF_EF_UPDATE)
> + l2_cache__event_update_from_cluster(event, cluster);
> + hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
> + }
> +}
> +
> +static int l2_cache__event_add(struct perf_event *event, int flags)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + int idx;
> + int err = 0;
> + struct hml2_pmu *cluster;
> +
> + cluster = get_hml2_pmu(event->cpu);
> +
> + idx = l2_cache__get_event_idx(cluster, event);
> + if (idx < 0) {
> + err = idx;
> + return err;
> + }
> +
> + hwc->idx = idx;
> + hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
> + cluster->events[idx] = event;
> + cluster->group_to_counter[L2_EVT_GROUP(hwc->config_base)] = idx;
> + local64_set(&hwc->prev_count, 0ULL);
> +
> + if (flags & PERF_EF_START)
> + l2_cache__event_start(event, flags);
> +
> + /* Propagate changes to the userspace mapping. */
> + perf_event_update_userpage(event);
> +
> + return err;
> +}
> +
> +static void l2_cache__event_del(struct perf_event *event, int flags)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + struct hml2_pmu *cluster;
> + int idx = hwc->idx;
> +
> + cluster = get_hml2_pmu(event->cpu);
> + l2_cache__event_stop(event, flags | PERF_EF_UPDATE);
> + cluster->events[idx] = NULL;
> + l2_cache__clear_event_idx(cluster, event);
> +
> + perf_event_update_userpage(event);
> +}
> +
> +static void l2_cache__event_read(struct perf_event *event)
> +{
> + l2_cache__event_update_from_cluster(event, get_hml2_pmu(event->cpu));
> +}
> +
> +static int l2_cache_filter_match(struct perf_event *event)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + struct hml2_pmu *cluster = get_hml2_pmu(event->cpu);
> + unsigned int group = L2_EVT_GROUP(hwc->config_base);
> +
> + /* check for column exclusion: group already in use by another event */
> + if (test_bit(group, cluster->used_groups) &&
> + cluster->events[cluster->group_to_counter[group]] != event)
> + return 0;
> +
> + return 1;
> +}
> +
> +static ssize_t l2_cache_pmu_cpumask_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct l2cache_pmu *l2cache_pmu = to_l2cache_pmu(dev_get_drvdata(dev));
> +
> + return cpumap_print_to_pagebuf(true, buf, &l2cache_pmu->cpumask);
> +}
> +
> +static struct device_attribute l2_cache_pmu_cpumask_attr =
> + __ATTR(cpumask, S_IRUGO, l2_cache_pmu_cpumask_show, NULL);
> +
> +static struct attribute *l2_cache_pmu_cpumask_attrs[] = {
> + &l2_cache_pmu_cpumask_attr.attr,
> + NULL,
> +};
> +
> +static struct attribute_group l2_cache_pmu_cpumask_group = {
> + .attrs = l2_cache_pmu_cpumask_attrs,
> +};
> +
> +/* CCG format for perf RAW codes. */
> +PMU_FORMAT_ATTR(l2_code, "config:4-11");
> +PMU_FORMAT_ATTR(l2_group, "config:0-3");
> +static struct attribute *l2_cache_pmu_formats[] = {
> + &format_attr_l2_code.attr,
> + &format_attr_l2_group.attr,
> + NULL,
> +};
> +
> +static struct attribute_group l2_cache_pmu_format_group = {
> + .name = "format",
> + .attrs = l2_cache_pmu_formats,
> +};
> +
> +static const struct attribute_group *l2_cache_pmu_attr_grps[] = {
> + &l2_cache_pmu_format_group,
> + &l2_cache_pmu_cpumask_group,
> + NULL,
> +};
> +
> +/*
> + * Generic device handlers
> + */
> +
> +static const struct acpi_device_id l2_cache_pmu_acpi_match[] = {
> + { "QCOM8130", },
> + { }
> +};
> +
> +static int get_num_counters(void)
> +{
> + int val;
> +
> + val = get_l2_indirect_reg(L2PMCR);
> +
> + /*
> + * Read number of counters from L2PMCR and add 1
> + * for the cycle counter.
> + */
> + return ((val >> L2PMCR_NUM_EV_SHIFT) & L2PMCR_NUM_EV_MASK) + 1;
> +}
> +
> +static int l2cache_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
> +{
> + struct hml2_pmu *cluster;
> + cpumask_t cluster_online_cpus;
> + struct l2cache_pmu *l2cache_pmu;
> +
> + l2cache_pmu = hlist_entry_safe(node, struct l2cache_pmu, node);
> + cluster = get_hml2_pmu(cpu);
> + cpumask_and(&cluster_online_cpus, &cluster->cluster_cpus,
> + cpu_online_mask);
> +
> + if (cpumask_weight(&cluster_online_cpus) == 1) {
> + /* all CPUs on this cluster were down, use this one */
> + cluster->on_cpu = cpu;
> + cpumask_set_cpu(cpu, &l2cache_pmu->cpumask);
> + WARN_ON(irq_set_affinity(cluster->irq, cpumask_of(cpu)));
> + }
> +
> + return 0;
> +}
> +
> +static int l2cache_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
> +{
> + struct hml2_pmu *cluster;
> + struct l2cache_pmu *l2cache_pmu;
> + cpumask_t cluster_online_cpus;
> + unsigned int target;
> +
> + l2cache_pmu = hlist_entry_safe(node, struct l2cache_pmu, node);
> +
> + if (!cpumask_test_and_clear_cpu(cpu, &l2cache_pmu->cpumask))
> + return 0;
> + cluster = get_hml2_pmu(cpu);
> + cpumask_and(&cluster_online_cpus, &cluster->cluster_cpus,
> + cpu_online_mask);
> +
> + /* Any other CPU for this cluster which is still online */
> + target = cpumask_any_but(&cluster_online_cpus, cpu);
> + if (target >= nr_cpu_ids)
> + return 0;
> +
> + perf_pmu_migrate_context(&l2cache_pmu->pmu, cpu, target);
> + cluster->on_cpu = target;
> + cpumask_set_cpu(target, &l2cache_pmu->cpumask);
> + WARN_ON(irq_set_affinity(cluster->irq, cpumask_of(target)));
> +
> + return 0;
> +}
> +
> +static int l2_cache_pmu_probe_cluster(struct device *dev, void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev->parent);
> + struct platform_device *sdev = to_platform_device(dev);
> + struct l2cache_pmu *l2cache_pmu = data;
> + struct hml2_pmu *cluster;
> + struct acpi_device *device;
> + unsigned long fw_cluster_id;
> + int cpu;
> + int err;
> + int irq;
> +
> + if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
> + return -ENODEV;
> +
> + if (kstrtol(device->pnp.unique_id, 10, &fw_cluster_id) < 0) {
> + dev_err(&pdev->dev, "unable to read ACPI uid\n");
> + return -ENODEV;
> + }
> +
> + irq = platform_get_irq(sdev, 0);
> + if (irq < 0) {
> + dev_err(&pdev->dev,
> + "Failed to get valid irq for cluster %ld\n",
> + fw_cluster_id);
> + return irq;
> + }
> +
> + cluster = devm_kzalloc(&pdev->dev, sizeof(*cluster), GFP_KERNEL);
> + if (!cluster)
> + return -ENOMEM;
> +
> + cluster->l2cache_pmu = l2cache_pmu;
> + for_each_present_cpu(cpu) {
> + if (topology_physical_package_id(cpu) == fw_cluster_id) {
> + cpumask_set_cpu(cpu, &cluster->cluster_cpus);
> + per_cpu(pmu_cluster, cpu) = cluster;
> + }
> + }
> + cluster->irq = irq;
> +
> + if (cpumask_empty(&cluster->cluster_cpus)) {
> + dev_err(&pdev->dev, "No CPUs found for L2 cache instance %ld\n",
> + fw_cluster_id);
> + return -ENODEV;
> + }
> +
> + /* Pick one CPU to be the preferred one to use in the cluster */
> + cluster->on_cpu = cpumask_first(&cluster->cluster_cpus);
> +
> + if (irq_set_affinity(irq, cpumask_of(cluster->on_cpu))) {
> + dev_err(&pdev->dev,
> + "Unable to set irq affinity (irq=%d, cpu=%d)\n",
> + irq, cluster->on_cpu);
> + return -ENODEV;
> + }
> +
> + err = devm_request_irq(&pdev->dev, irq, l2_cache__handle_irq,
> + IRQF_NOBALANCING, "l2-cache-pmu", cluster);
> + if (err) {
> + dev_err(&pdev->dev,
> + "Unable to request IRQ%d for L2 PMU counters\n", irq);
> + return err;
> + }
> +
> + dev_info(&pdev->dev,
> + "Registered L2 cache PMU instance %ld with %d CPUs\n",
> + fw_cluster_id, cpumask_weight(&cluster->cluster_cpus));
> +
> + cluster->pmu_lock = __SPIN_LOCK_UNLOCKED(cluster->pmu_lock);
> + cpumask_set_cpu(cluster->on_cpu, &l2cache_pmu->cpumask);
> +
> + hml2_pmu__reset(cluster);
> + l2cache_pmu->num_pmus++;
> +
> + return 0;
> +}
> +
> +static int l2_cache_pmu_probe(struct platform_device *pdev)
> +{
> + int err;
> + struct l2cache_pmu *l2cache_pmu;
> +
> + l2cache_pmu =
> + devm_kzalloc(&pdev->dev, sizeof(*l2cache_pmu), GFP_KERNEL);
> + if (!l2cache_pmu)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, l2cache_pmu);
> + l2cache_pmu->pmu = (struct pmu) {
> + /* suffix is instance id for future use with multiple sockets */
> + .name = "l2cache_0",
> + .task_ctx_nr = perf_invalid_context,
> + .pmu_enable = l2_cache__pmu_enable,
> + .pmu_disable = l2_cache__pmu_disable,
> + .event_init = l2_cache__event_init,
> + .add = l2_cache__event_add,
> + .del = l2_cache__event_del,
> + .start = l2_cache__event_start,
> + .stop = l2_cache__event_stop,
> + .read = l2_cache__event_read,
> + .attr_groups = l2_cache_pmu_attr_grps,
> + .filter_match = l2_cache_filter_match,
> + };
> +
> + l2cache_pmu->num_counters = get_num_counters();
> + l2cache_pmu->pdev = pdev;
> + l2_cycle_ctr_idx = l2cache_pmu->num_counters - 1;
> + l2_counter_present_mask = GENMASK(l2cache_pmu->num_counters - 2, 0) |
> + L2PM_CC_ENABLE;
> +
> + cpumask_clear(&l2cache_pmu->cpumask);
> +
> + /* Read cluster info and initialize each cluster */
> + err = device_for_each_child(&pdev->dev, l2cache_pmu,
> + l2_cache_pmu_probe_cluster);
> + if (err < 0)
> + return err;
> +
> + if (l2cache_pmu->num_pmus == 0) {
> + dev_err(&pdev->dev, "No hardware L2 cache PMUs found\n");
> + return -ENODEV;
> + }
> +
> + err = perf_pmu_register(&l2cache_pmu->pmu, l2cache_pmu->pmu.name, -1);
> + if (err < 0) {
> + dev_err(&pdev->dev, "Error %d registering L2 cache PMU\n", err);
> + return err;
> + }
> +
> + dev_info(&pdev->dev, "Registered L2 cache PMU using %d HW PMUs\n",
> + l2cache_pmu->num_pmus);
> +
> + err = cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
> + &l2cache_pmu->node);
> +
> + return err;
> +}
> +
> +static int l2_cache_pmu_remove(struct platform_device *pdev)
> +{
> + struct l2cache_pmu *l2cache_pmu =
> + to_l2cache_pmu(platform_get_drvdata(pdev));
> +
> + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
> + &l2cache_pmu->node);
> + perf_pmu_unregister(&l2cache_pmu->pmu);
> + return 0;
> +}
> +
> +static struct platform_driver l2_cache_pmu_driver = {
> + .driver = {
> + .name = "qcom-l2cache-pmu",
> + .owner = THIS_MODULE,
> + .acpi_match_table = ACPI_PTR(l2_cache_pmu_acpi_match),
> + },
> + .probe = l2_cache_pmu_probe,
> + .remove = l2_cache_pmu_remove,
> +};
> +
> +static int __init register_l2_cache_pmu_driver(void)
> +{
> + int err;
> +
> + err = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
> + "AP_PERF_ARM_QCOM_L2_ONLINE",
> + l2cache_pmu_online_cpu,
> + l2cache_pmu_offline_cpu);
> + if (err)
> + return err;
> +
> + return platform_driver_register(&l2_cache_pmu_driver);
> +}
> +device_initcall(register_l2_cache_pmu_driver);
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index 45a4287..f342842 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -113,6 +113,7 @@ enum cpuhp_state {
> CPUHP_AP_PERF_ARM_CCI_ONLINE,
> CPUHP_AP_PERF_ARM_CCN_ONLINE,
> CPUHP_AP_PERF_ARM_L2X0_ONLINE,
> + CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
> CPUHP_AP_WORKQUEUE_ONLINE,
> CPUHP_AP_RCUTREE_ONLINE,
> CPUHP_AP_NOTIFY_ONLINE,
>
I believe this addresses all the issues raised previously - are there any other comments? Thanks.
Neil
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
^ permalink raw reply
* Coresight ETF trace dump failed in Juno r1 with 4.8-rc8
From: Suzuki K Poulose @ 2016-10-04 14:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGhh56H7a9oEYxzEA4gGvBey=COMqwgisd4tzewU8DLGcGrsww@mail.gmail.com>
On 04/10/16 06:37, Venkatesh Vivekanandan wrote:
> On Mon, Oct 3, 2016 at 6:44 PM, Sudeep Holla <sudeep.holla@arm.com> wrote:
>> Hi Venkatesh,
>>
>> On 03/10/16 12:36, Venkatesh Vivekanandan wrote:
>>>
>>> Hi All,
>>>
>>> I am trying to collect ETF trace from Juno R1 and could see "cpu
>>> stall" while dumping the trace. Attached is the log of sequence
>>> followed. Was trying to collect the trace data from hardware and see
>>> if it is any valid data. Am I missing anything here?.
>>>
>>
>> There are few fixes from me and Suzuki queued for v4.9.
>> Can you check if this issue persists even on linux-next ?
>
> Issue is the same in linux-next as well. Please find the attached log.
>
> linaro-test [rc=0]# dd if=/dev/20010000.etf of=/cstrace.bin bs=1
> [ 120.009698] INFO: rcu_preempt detected stalls on CPUs/tasks:
> [ 120.015307] 2-...: (1 GPs behind) idle=f11/140000000000000/0
> softirq=224/224 fqs=1903
> [ 120.023226] (detected by 1, t=5255 jiffies, g=-1, c=-2, q=19)
> [ 120.029001] Task dump for CPU 2:
> [ 120.032190] dd R running task 0 1270 1267 0x00000002
> [ 120.039172] Call trace:
> [ 120.041594] [<ffff000008085534>] __switch_to+0xc8/0xd4
> [ 120.046675] [<0000000000020000>] 0x20000
>
> Steps followed,
> # git clone git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
> linux-next
> # cd linux-next
> # make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
> # make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig <---
> enable coresight
> # make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 Image
> # make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
> # arch/arm64/boot/Image <--- copied this kernel
> # arch/arm64/boot/dts/arm/juno-r1.dtb <--- copied this dtb
>
> Top commit in linux-next is,
>
> commit c7d3b912180a9bb0733e5cfab84e5a7493dd3599
> Author: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Tue Oct 4 14:52:03 2016 +1100
>
> Add linux-next specific files for 20161004
Can't reproduce it here either.
root at localhost:/sys/bus/coresight/devices# echo 1 > 20010000.etf/enable_sink
root at localhost:/sys/bus/coresight/devices# echo 1 > 22140000.etm/enable_source
root at localhost:/sys/bus/coresight/devices# dd if=/dev/20010000.etf bs=1 of=/root/etr.bin
65536+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 0.227546 s, 288 kB/s
root at localhost:/sys/bus/coresight/devices# dd if=/dev/20010000.etf bs=1 of=/root/etr.bin
65536+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 0.233527 s, 281 kB/s
root at localhost:/sys/bus/coresight/devices# echo 0 > 20010000.etf/enable_sink
root at localhost:/sys/bus/coresight/devices# dd if=/dev/20010000.etf bs=1 of=/root/etr.bin
65536+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 0.474943 s, 138 kB/s
FWIW, here is my firmware version :
NOTICE: Booting Trusted Firmware
NOTICE: BL1: v1.1(release):e04723e21362
NOTICE: BL1: Built : 15:39:56, Sep 1 2015
NOTICE: BL1: Booting BL2
NOTICE: BL2: v1.1(release):e04723e21362
NOTICE: BL2: Built : 15:42:30, Sep 1 2015
NOTICE: BL1: Booting BL3-1
NOTICE: BL3-1: v1.1(release):604d5da6f2aa
NOTICE: BL3-1: Built : 14:50:36, Sep 10 2015
UEFI firmware (version ea31f8e built at 16:35:17 on Aug 5 2015)
Cheers
Suzuki
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox