* Re: [PATCH v1 2/2] of: Let of_for_each_phandle fallback to non-negative cell_count
From: Geert Uytterhoeven @ 2019-09-17 12:52 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Frank Rowand, Joerg Roedel, Linux Kernel Mailing List,
Linux-Renesas, Wolfram Sang, Linux IOMMU,
linux-mediatek@lists.infradead.org, Linux I2C, Sascha Hauer,
Matthias Brugger, Will Deacon, Peter Rosin, Linux ARM,
Robin Murphy
In-Reply-To: <20190917122530.3xy7sut3xdvzlomj@pengutronix.de>
Hi Uwe,
On Tue, Sep 17, 2019 at 2:25 PM Uwe Kleine-König
<u.kleine-koenig@pengutronix.de> wrote:
> On Tue, Sep 17, 2019 at 11:25:46AM +0000, Peter Rosin wrote:
> > On 2019-09-17 12:13, Uwe Kleine-König wrote:
> > > On Tue, Sep 17, 2019 at 11:40:25AM +0200, Geert Uytterhoeven wrote:
> > >> On Fri, Sep 13, 2019 at 11:58 PM Rob Herring <robh@kernel.org> wrote:
> > >>> On Sat, 24 Aug 2019 15:28:46 +0200, =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= wrote:
> > >>>> Referencing device tree nodes from a property allows to pass arguments.
> > >>>> This is for example used for referencing gpios. This looks as follows:
> > >>>>
> > >>>> gpio_ctrl: gpio-controller {
> > >>>> #gpio-cells = <2>
> > >>>> ...
> > >>>> }
> > >>>>
> > >>>> someothernode {
> > >>>> gpios = <&gpio_ctrl 5 0 &gpio_ctrl 3 0>;
> > >>>> ...
> > >>>> }
> > >>>>
> > >>>> To know the number of arguments this must be either fixed, or the
> > >>>> referenced node is checked for a $cells_name (here: "#gpio-cells")
> > >>>> property and with this information the start of the second reference can
> > >>>> be determined.
> > >>>>
> > >>>> Currently regulators are referenced with no additional arguments. To
> > >>>> allow some optional arguments without having to change all referenced
> > >>>> nodes this change introduces a way to specify a default cell_count. So
> > >>>> when a phandle is parsed we check for the $cells_name property and use
> > >>>> it as before if present. If it is not present we fall back to
> > >>>> cells_count if non-negative and only fail if cells_count is smaller than
> > >>>> zero.
> > >>>>
> > >>>> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > >>
> > >> This is now commit e42ee61017f58cd9 ("of: Let of_for_each_phandle fallback
> > >> to non-negative cell_count") in robh/for-next, which causes a lock-up when
> > >> booting a shmobile_defconfig kernel on r8a7791/koelsch:
> > >>
> > >> rcu: INFO: rcu_sched self-detected stall on CPU
> Oh yeah, you're right. I'm a bit disappointed that I didn't spot this
> myself :-|
>
> Untested patch to fix this problem:
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index 2f25d2dfecfa..26f7a21d7187 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1284,6 +1284,13 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
> const __be32 *list;
> int size;
>
> + /*
> + * one of cell_count or cells_name must be provided to determine the
> + * argument length.
> + */
> + if (cell_count < 0 && !cells_name)
> + return -EINVAL;
> +
> memset(it, 0, sizeof(*it));
>
> list = of_get_property(np, list_name, &size);
> @@ -1765,6 +1772,18 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
> struct of_phandle_iterator it;
> int rc, cur_index = 0;
>
> + /* If cells_name is NULL we assume an cell_count of 0 */
a cell count
> + if (cells_name == NULL) {
> + const __be32 *list;
> + int size;
> +
> + list = of_get_property(np, list_name, &size);
> + if (!list)
> + return -ENOENT;
> +
> + return size / sizeof(*list);
> + }
> +
> rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1);
> if (rc)
> return rc;
Thanks, that fixes the boot for me!
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v1 2/2] of: Let of_for_each_phandle fallback to non-negative cell_count
From: Marek Szyprowski @ 2019-09-17 12:44 UTC (permalink / raw)
To: Uwe Kleine-König, Peter Rosin
Cc: Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Frank Rowand, Joerg Roedel, Linux Kernel Mailing List,
Linux-Renesas, Wolfram Sang, Linux IOMMU, Geert Uytterhoeven,
Linux I2C, Sascha Hauer, Matthias Brugger,
linux-mediatek@lists.infradead.org, Will Deacon, Linux ARM,
Robin Murphy
In-Reply-To: <20190917122530.3xy7sut3xdvzlomj@pengutronix.de>
Hi Uwe,
On 17.09.2019 14:25, Uwe Kleine-König wrote:
> On Tue, Sep 17, 2019 at 11:25:46AM +0000, Peter Rosin wrote:
>> On 2019-09-17 12:13, Uwe Kleine-König wrote:
>>> Hello Geert,
>>>
>>> On Tue, Sep 17, 2019 at 11:40:25AM +0200, Geert Uytterhoeven wrote:
>>>> Hi Rob, Uwe,
>>>>
>>>> On Fri, Sep 13, 2019 at 11:58 PM Rob Herring <robh@kernel.org> wrote:
>>>>> On Sat, 24 Aug 2019 15:28:46 +0200, =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= wrote:
>>>>>> Referencing device tree nodes from a property allows to pass arguments.
>>>>>> This is for example used for referencing gpios. This looks as follows:
>>>>>>
>>>>>> gpio_ctrl: gpio-controller {
>>>>>> #gpio-cells = <2>
>>>>>> ...
>>>>>> }
>>>>>>
>>>>>> someothernode {
>>>>>> gpios = <&gpio_ctrl 5 0 &gpio_ctrl 3 0>;
>>>>>> ...
>>>>>> }
>>>>>>
>>>>>> To know the number of arguments this must be either fixed, or the
>>>>>> referenced node is checked for a $cells_name (here: "#gpio-cells")
>>>>>> property and with this information the start of the second reference can
>>>>>> be determined.
>>>>>>
>>>>>> Currently regulators are referenced with no additional arguments. To
>>>>>> allow some optional arguments without having to change all referenced
>>>>>> nodes this change introduces a way to specify a default cell_count. So
>>>>>> when a phandle is parsed we check for the $cells_name property and use
>>>>>> it as before if present. If it is not present we fall back to
>>>>>> cells_count if non-negative and only fail if cells_count is smaller than
>>>>>> zero.
>>>>>>
>>>>>> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
>>>> This is now commit e42ee61017f58cd9 ("of: Let of_for_each_phandle fallback
>>>> to non-negative cell_count") in robh/for-next, which causes a lock-up when
>>>> booting a shmobile_defconfig kernel on r8a7791/koelsch:
>>>>
>>>> rcu: INFO: rcu_sched self-detected stall on CPU
>>>> rcu: 0-....: (2099 ticks this GP) idle=6fe/1/0x40000002
>>>> softirq=29/29 fqs=1050
>>>> (t=2100 jiffies g=-1131 q=0)
>>>> NMI backtrace for cpu 0
>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>>>> 5.3.0-rc2-shmobile-00050-ge42ee61017f58cd9 #376
>>>> Hardware name: Generic R-Car Gen2 (Flattened Device Tree)
>>>> [<c010f8ac>] (unwind_backtrace) from [<c010b620>] (show_stack+0x10/0x14)
>>>> [<c010b620>] (show_stack) from [<c073d038>] (dump_stack+0x7c/0x9c)
>>>> [<c073d038>] (dump_stack) from [<c0742e80>] (nmi_cpu_backtrace+0xa0/0xb8)
>>>> [<c0742e80>] (nmi_cpu_backtrace) from [<c0742f1c>] (nmi_trigger_cpumask_backtrace+0x84/0x114)
>>>> [<c0742f1c>] (nmi_trigger_cpumask_backtrace) from [<c017d684>] (rcu_dump_cpu_stacks+0xac/0xc8)
>>>> [<c017d684>] (rcu_dump_cpu_stacks) from [<c017a598>] (rcu_sched_clock_irq+0x2ac/0x6b4)
>>>> [<c017a598>] (rcu_sched_clock_irq) from [<c0183980>] (update_process_times+0x30/0x5c)
>>>> [<c0183980>] (update_process_times) from [<c01941a8>] (tick_nohz_handler+0xcc/0x120)
>>>> [<c01941a8>] (tick_nohz_handler) from [<c05b1d40>] (arch_timer_handler_virt+0x28/0x30)
>>>> [<c05b1d40>] (arch_timer_handler_virt) from [<c016c9e0>] (handle_percpu_devid_irq+0xe8/0x21c)
>>>> [<c016c9e0>] (handle_percpu_devid_irq) from [<c0167a8c>] (generic_handle_irq+0x18/0x28)
>>>> [<c0167a8c>] (generic_handle_irq) from [<c0167b3c>] (__handle_domain_irq+0xa0/0xb4)
>>>> [<c0167b3c>] (__handle_domain_irq) from [<c03673ec>] (gic_handle_irq+0x58/0x90)
>>>> [<c03673ec>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
>>>> Exception stack(0xeb08dd30 to 0xeb08dd78)
>>>> dd20: c0cc7514 20000013 00000005 00003b27
>>>> dd40: eb7c4020 c0cc750c 00000051 00000051 20000013 c0c66b08 eb1cdc00 00000018
>>>> dd60: 00000000 eb08dd80 c05c1a38 c0756c00 20000013 ffffffff
>>>> [<c0101a8c>] (__irq_svc) from [<c0756c00>] (_raw_spin_unlock_irqrestore+0x1c/0x20)
>>>> [<c0756c00>] (_raw_spin_unlock_irqrestore) from [<c05c1a38>] (of_find_node_by_phandle+0xcc/0xf0)
>>>> [<c05c1a38>] (of_find_node_by_phandle) from [<c05c1bb8>] (of_phandle_iterator_next+0x68/0x178)
>>>> [<c05c1bb8>] (of_phandle_iterator_next) from [<c05c22bc>] (of_count_phandle_with_args+0x5c/0x7c)
>>>> [<c05c22bc>] (of_count_phandle_with_args) from [<c053fc38>] (i2c_demux_pinctrl_probe+0x24/0x1fc)
>>>> [<c053fc38>] (i2c_demux_pinctrl_probe) from [<c04463c4>] (platform_drv_probe+0x48/0x94)
>>>> [<c04463c4>] (platform_drv_probe) from [<c0444a20>] (really_probe+0x1f0/0x2b8)
>>>> [<c0444a20>] (really_probe) from [<c0444e68>] (driver_probe_device+0x140/0x158)
>>>> [<c0444e68>] (driver_probe_device) from [<c0444ff0>] (device_driver_attach+0x44/0x5c)
>>>> [<c0444ff0>] (device_driver_attach) from [<c04450b4>] (__driver_attach+0xac/0xb4)
>>>> [<c04450b4>] (__driver_attach) from [<c0443178>] (bus_for_each_dev+0x64/0xa0)
>>>> [<c0443178>] (bus_for_each_dev) from [<c04438a8>] (bus_add_driver+0x148/0x1a8)
>>>> [<c04438a8>] (bus_add_driver) from [<c0445ad0>] (driver_register+0xac/0xf0)
>>>> [<c0445ad0>] (driver_register) from [<c0b010b0>] (do_one_initcall+0xa8/0x1d4)
>>>> [<c0b010b0>] (do_one_initcall) from [<c0b01448>] (kernel_init_freeable+0x26c/0x2c8)
>>>> [<c0b01448>] (kernel_init_freeable) from [<c0751c70>] (kernel_init+0x8/0x10c)
>>>> [<c0751c70>] (kernel_init) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
>>>> Exception stack(0xeb08dfb0 to 0xeb08dff8)
>>>> dfa0: 00000000 00000000 00000000 00000000
>>>> dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
>>>> dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
>>>>
>>>> Presumably it loops forever, due to a conversion of -1 to unsigned
>>>> somewhere?
>>> Hmm, I fail to see the culprit. i2c_demux_pinctrl_probe calls
>>> of_count_phandle_with_args with cells_name=NULL. With that I don't see
>>> how my patch changes anything as the only change is in an if
>>> (it->cells_name) block that shouldn't be relevant in your case.
>>>
>>> Can you please verify that the loop in of_count_phandle_with_args is
>>> indeed not terminating, e.g. with
>> The below indicated else-branch was not touched by e42ee61017f58cd9,
>> which ends up setting the count to -1 (aka 0xff...ff in this case).
>> No?
>>
>> int of_phandle_iterator_next(struct of_phandle_iterator *it)
>> {
>>
>> ...
>>
>> if (it->cells_name) {
>>
>> ...
>>
>> } else {
>> count = it->cell_count; /* <---- SUSPECT!!! */
>> }
> Oh yeah, you're right. I'm a bit disappointed that I didn't spot this
> myself :-|
>
> Untested patch to fix this problem:
Yesterday I've noticed that sound driver fails to initialize on TM2(e)
board (arm64) and today I've bisected to this commit. Nice to see that
the issue has been already investigated.
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index 2f25d2dfecfa..26f7a21d7187 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1284,6 +1284,13 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
> const __be32 *list;
> int size;
>
> + /*
> + * one of cell_count or cells_name must be provided to determine the
> + * argument length.
> + */
> + if (cell_count < 0 && !cells_name)
> + return -EINVAL;
> +
> memset(it, 0, sizeof(*it));
>
> list = of_get_property(np, list_name, &size);
> @@ -1765,6 +1772,18 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
> struct of_phandle_iterator it;
> int rc, cur_index = 0;
>
> + /* If cells_name is NULL we assume an cell_count of 0 */
> + if (cells_name == NULL) {
> + const __be32 *list;
> + int size;
> +
> + list = of_get_property(np, list_name, &size);
> + if (!list)
> + return -ENOENT;
> +
> + return size / sizeof(*list);
> + }
> +
> rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1);
> if (rc)
> return rc;
>
I confirm that the above code works. The patch fixes my TM2(e) sound
issue, feel free to add:
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] ARM: dts: imx6dl: SolidRun: add phy node with 100Mb/s max-speed
From: tinywrkb @ 2019-09-17 12:41 UTC (permalink / raw)
To: Andrew Lunn
Cc: Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Baruch Siach, Fabio Estevam, Sascha Hauer, Russell King,
open list, Rob Herring, NXP Linux Team, Pengutronix Kernel Team,
Shawn Guo, linux-arm-kernel
In-Reply-To: <20190915135652.GC3427@lunn.ch>
On Sun, Sep 15, 2019 at 03:56:52PM +0200, Andrew Lunn wrote:
> > Tinywrkb confirmed to me in private communication that revert of
> > 5502b218e001 fixes Ethernet for him on effected system.
> >
> > He also referred me to an old Cubox-i spec that lists 10/100 Ethernet
> > only for i.MX6 Solo/DualLite variants of Cubox-i. It turns out that
> > there was a plan to use a different 10/100 PHY for Solo/DualLite
> > SOMs. This plan never materialized. All SolidRun i.MX6 SOMs use the same
> > AR8035 PHY that supports 1Gb.
> >
> > Commit 5502b218e001 might be triggering a hardware issue on the affected
> > Cubox-i. I could not reproduce the issue here with Cubox-i and a Dual
> > SOM variant running v5.3-rc8. I have no Solo/DualLite variant handy at
> > the moment.
>
> Could somebody with an affected device show us the output of ethtool
> with and without 5502b218e001. Does one show 1G has been negotiated,
> and the other 100Mbps? If this is true, how does it get 100Mbps
> without that patch? We are missing a piece of the puzzle.
>
> Andrew
linux-test-5.1rc1-a2703de70942-without_bad_commit
Settings for eth0:
Supported ports: [ TP MII ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: Symmetric
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: Symmetric
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Link partner advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Link partner advertised pause frame use: Symmetric
Link partner advertised auto-negotiation: Yes
Link partner advertised FEC modes: Not reported
Speed: 100Mb/s
Duplex: Full
Port: MII
PHYAD: 0
Transceiver: internal
Auto-negotiation: on
Supports Wake-on: d
Wake-on: d
Link detected: yes
journalctl -b | egrep -i 'phy|eth|fec'|grep -v usb
kernel: Booting Linux on physical CPU 0x0
kernel: libphy: Fixed MDIO Bus: probed
kernel: libphy: fec_enet_mii_bus: probed
kernel: fec 2188000.ethernet eth0: registered PHC device 0
kernel: dwhdmi-imx 120000.hdmi: Detected HDMI TX controller v1.31a with HDCP (DWC HDMI 3D TX PHY)
kernel: Generic PHY 2188000.ethernet-1:00: attached PHY driver [Generic PHY] (mii_bus:phy_addr=2188000.ethernet-1:00, irq=POLL)
kernel: fec 2188000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
kernel: IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
systemd-networkd[243]: eth0: Gained carrier
systemd-networkd[243]: eth0: DHCPv4 address 192.168.15.101/24 via 192.168.15.1
systemd-networkd[243]: eth0: Gained IPv6LL
systemd-networkd[243]: eth0: Configured
######################################################################
linux-test-5.1rc1-5502b218e001-with_bad_commit
Settings for eth0:
Supported ports: [ TP MII ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: Symmetric
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: Symmetric
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Link partner advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Link partner advertised pause frame use: Symmetric
Link partner advertised auto-negotiation: Yes
Link partner advertised FEC modes: Not reported
Speed: 1000Mb/s
Duplex: Full
Port: MII
PHYAD: 0
Transceiver: internal
Auto-negotiation: on
Supports Wake-on: d
Wake-on: d
Link detected: yes
journalctl -b | egrep -i 'phy|eth|fec'|grep -v usb
kernel: Booting Linux on physical CPU 0x0
kernel: libphy: Fixed MDIO Bus: probed
kernel: libphy: fec_enet_mii_bus: probed
kernel: fec 2188000.ethernet eth0: registered PHC device 0
kernel: dwhdmi-imx 120000.hdmi: Detected HDMI TX controller v1.31a with HDCP (DWC HDMI 3D TX PHY)
kernel: Generic PHY 2188000.ethernet-1:00: attached PHY driver [Generic PHY] (mii_bus:phy_addr=2188000.ethernet-1:00, irq=POLL)
kernel: fec 2188000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx
kernel: IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
systemd-networkd[239]: eth0: Gained carrier
systemd-networkd[239]: eth0: Gained IPv6LL
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 0/2] iio: stm32-adc: fix a race with dma and irq
From: Fabrice Gasnier @ 2019-09-17 12:38 UTC (permalink / raw)
To: jic23
Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
mcoquelin.stm32, knaack.h, fabrice.gasnier, linux-stm32,
linux-arm-kernel
This series fixes a race condition observed when using several ADCs with DMA
and irq.
There's a precusor patch to the fix. It keeps registers definitions as a whole
block, to ease readability and allow simple (readl) access path to EOC bits in
stm32-adc-core driver.
---
Changes in v2:
- Add a precursor patch to follow Jonathan's comment on readability
Fabrice Gasnier (2):
iio: adc: stm32-adc: move registers definitions
iio: adc: stm32-adc: fix a race when using several adcs with dma and
irq
drivers/iio/adc/stm32-adc-core.c | 70 +++++++++++---------
drivers/iio/adc/stm32-adc-core.h | 137 +++++++++++++++++++++++++++++++++++++++
drivers/iio/adc/stm32-adc.c | 109 -------------------------------
3 files changed, 177 insertions(+), 139 deletions(-)
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 1/2] iio: adc: stm32-adc: move registers definitions
From: Fabrice Gasnier @ 2019-09-17 12:38 UTC (permalink / raw)
To: jic23
Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
mcoquelin.stm32, knaack.h, fabrice.gasnier, linux-stm32,
linux-arm-kernel
In-Reply-To: <1568723896-19063-1-git-send-email-fabrice.gasnier@st.com>
Move STM32 ADC registers definitions to common header.
This is precursor patch to:
- iio: adc: stm32-adc: fix a race when using several adcs with dma and irq
It keeps registers definitions as a whole block, to ease readability and
allow simple access path to EOC bits (readl) in stm32-adc-core driver.
Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
drivers/iio/adc/stm32-adc-core.c | 27 --------
drivers/iio/adc/stm32-adc-core.h | 136 +++++++++++++++++++++++++++++++++++++++
drivers/iio/adc/stm32-adc.c | 109 -------------------------------
3 files changed, 136 insertions(+), 136 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 9b85fef..84ac326 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -24,33 +24,6 @@
#include "stm32-adc-core.h"
-/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */
-#define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
-#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
-
-/* STM32F4_ADC_CSR - bit fields */
-#define STM32F4_EOC3 BIT(17)
-#define STM32F4_EOC2 BIT(9)
-#define STM32F4_EOC1 BIT(1)
-
-/* STM32F4_ADC_CCR - bit fields */
-#define STM32F4_ADC_ADCPRE_SHIFT 16
-#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16)
-
-/* STM32H7 - common registers for all ADC instances */
-#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
-#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
-
-/* STM32H7_ADC_CSR - bit fields */
-#define STM32H7_EOC_SLV BIT(18)
-#define STM32H7_EOC_MST BIT(2)
-
-/* STM32H7_ADC_CCR - bit fields */
-#define STM32H7_PRESC_SHIFT 18
-#define STM32H7_PRESC_MASK GENMASK(21, 18)
-#define STM32H7_CKMODE_SHIFT 16
-#define STM32H7_CKMODE_MASK GENMASK(17, 16)
-
#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
/* SYSCFG registers */
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 8af507b..94aa2d2 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -27,6 +27,142 @@
#define STM32_ADC_MAX_ADCS 3
#define STM32_ADCX_COMN_OFFSET 0x300
+/* STM32F4 - Registers for each ADC instance */
+#define STM32F4_ADC_SR 0x00
+#define STM32F4_ADC_CR1 0x04
+#define STM32F4_ADC_CR2 0x08
+#define STM32F4_ADC_SMPR1 0x0C
+#define STM32F4_ADC_SMPR2 0x10
+#define STM32F4_ADC_HTR 0x24
+#define STM32F4_ADC_LTR 0x28
+#define STM32F4_ADC_SQR1 0x2C
+#define STM32F4_ADC_SQR2 0x30
+#define STM32F4_ADC_SQR3 0x34
+#define STM32F4_ADC_JSQR 0x38
+#define STM32F4_ADC_JDR1 0x3C
+#define STM32F4_ADC_JDR2 0x40
+#define STM32F4_ADC_JDR3 0x44
+#define STM32F4_ADC_JDR4 0x48
+#define STM32F4_ADC_DR 0x4C
+
+/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */
+#define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
+#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
+
+/* STM32F4_ADC_SR - bit fields */
+#define STM32F4_STRT BIT(4)
+#define STM32F4_EOC BIT(1)
+
+/* STM32F4_ADC_CR1 - bit fields */
+#define STM32F4_RES_SHIFT 24
+#define STM32F4_RES_MASK GENMASK(25, 24)
+#define STM32F4_SCAN BIT(8)
+#define STM32F4_EOCIE BIT(5)
+
+/* STM32F4_ADC_CR2 - bit fields */
+#define STM32F4_SWSTART BIT(30)
+#define STM32F4_EXTEN_SHIFT 28
+#define STM32F4_EXTEN_MASK GENMASK(29, 28)
+#define STM32F4_EXTSEL_SHIFT 24
+#define STM32F4_EXTSEL_MASK GENMASK(27, 24)
+#define STM32F4_EOCS BIT(10)
+#define STM32F4_DDS BIT(9)
+#define STM32F4_DMA BIT(8)
+#define STM32F4_ADON BIT(0)
+
+/* STM32F4_ADC_CSR - bit fields */
+#define STM32F4_EOC3 BIT(17)
+#define STM32F4_EOC2 BIT(9)
+#define STM32F4_EOC1 BIT(1)
+
+/* STM32F4_ADC_CCR - bit fields */
+#define STM32F4_ADC_ADCPRE_SHIFT 16
+#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16)
+
+/* STM32H7 - Registers for each ADC instance */
+#define STM32H7_ADC_ISR 0x00
+#define STM32H7_ADC_IER 0x04
+#define STM32H7_ADC_CR 0x08
+#define STM32H7_ADC_CFGR 0x0C
+#define STM32H7_ADC_SMPR1 0x14
+#define STM32H7_ADC_SMPR2 0x18
+#define STM32H7_ADC_PCSEL 0x1C
+#define STM32H7_ADC_SQR1 0x30
+#define STM32H7_ADC_SQR2 0x34
+#define STM32H7_ADC_SQR3 0x38
+#define STM32H7_ADC_SQR4 0x3C
+#define STM32H7_ADC_DR 0x40
+#define STM32H7_ADC_DIFSEL 0xC0
+#define STM32H7_ADC_CALFACT 0xC4
+#define STM32H7_ADC_CALFACT2 0xC8
+
+/* STM32H7 - common registers for all ADC instances */
+#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
+#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
+
+/* STM32H7_ADC_ISR - bit fields */
+#define STM32MP1_VREGREADY BIT(12)
+#define STM32H7_EOC BIT(2)
+#define STM32H7_ADRDY BIT(0)
+
+/* STM32H7_ADC_IER - bit fields */
+#define STM32H7_EOCIE STM32H7_EOC
+
+/* STM32H7_ADC_CR - bit fields */
+#define STM32H7_ADCAL BIT(31)
+#define STM32H7_ADCALDIF BIT(30)
+#define STM32H7_DEEPPWD BIT(29)
+#define STM32H7_ADVREGEN BIT(28)
+#define STM32H7_LINCALRDYW6 BIT(27)
+#define STM32H7_LINCALRDYW5 BIT(26)
+#define STM32H7_LINCALRDYW4 BIT(25)
+#define STM32H7_LINCALRDYW3 BIT(24)
+#define STM32H7_LINCALRDYW2 BIT(23)
+#define STM32H7_LINCALRDYW1 BIT(22)
+#define STM32H7_ADCALLIN BIT(16)
+#define STM32H7_BOOST BIT(8)
+#define STM32H7_ADSTP BIT(4)
+#define STM32H7_ADSTART BIT(2)
+#define STM32H7_ADDIS BIT(1)
+#define STM32H7_ADEN BIT(0)
+
+/* STM32H7_ADC_CFGR bit fields */
+#define STM32H7_EXTEN_SHIFT 10
+#define STM32H7_EXTEN_MASK GENMASK(11, 10)
+#define STM32H7_EXTSEL_SHIFT 5
+#define STM32H7_EXTSEL_MASK GENMASK(9, 5)
+#define STM32H7_RES_SHIFT 2
+#define STM32H7_RES_MASK GENMASK(4, 2)
+#define STM32H7_DMNGT_SHIFT 0
+#define STM32H7_DMNGT_MASK GENMASK(1, 0)
+
+enum stm32h7_adc_dmngt {
+ STM32H7_DMNGT_DR_ONLY, /* Regular data in DR only */
+ STM32H7_DMNGT_DMA_ONESHOT, /* DMA one shot mode */
+ STM32H7_DMNGT_DFSDM, /* DFSDM mode */
+ STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */
+};
+
+/* STM32H7_ADC_CALFACT - bit fields */
+#define STM32H7_CALFACT_D_SHIFT 16
+#define STM32H7_CALFACT_D_MASK GENMASK(26, 16)
+#define STM32H7_CALFACT_S_SHIFT 0
+#define STM32H7_CALFACT_S_MASK GENMASK(10, 0)
+
+/* STM32H7_ADC_CALFACT2 - bit fields */
+#define STM32H7_LINCALFACT_SHIFT 0
+#define STM32H7_LINCALFACT_MASK GENMASK(29, 0)
+
+/* STM32H7_ADC_CSR - bit fields */
+#define STM32H7_EOC_SLV BIT(18)
+#define STM32H7_EOC_MST BIT(2)
+
+/* STM32H7_ADC_CCR - bit fields */
+#define STM32H7_PRESC_SHIFT 18
+#define STM32H7_PRESC_MASK GENMASK(21, 18)
+#define STM32H7_CKMODE_SHIFT 16
+#define STM32H7_CKMODE_MASK GENMASK(17, 16)
+
/**
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
* @base: control registers base cpu addr
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 6a7dd08..663f8a5 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -28,115 +28,6 @@
#include "stm32-adc-core.h"
-/* STM32F4 - Registers for each ADC instance */
-#define STM32F4_ADC_SR 0x00
-#define STM32F4_ADC_CR1 0x04
-#define STM32F4_ADC_CR2 0x08
-#define STM32F4_ADC_SMPR1 0x0C
-#define STM32F4_ADC_SMPR2 0x10
-#define STM32F4_ADC_HTR 0x24
-#define STM32F4_ADC_LTR 0x28
-#define STM32F4_ADC_SQR1 0x2C
-#define STM32F4_ADC_SQR2 0x30
-#define STM32F4_ADC_SQR3 0x34
-#define STM32F4_ADC_JSQR 0x38
-#define STM32F4_ADC_JDR1 0x3C
-#define STM32F4_ADC_JDR2 0x40
-#define STM32F4_ADC_JDR3 0x44
-#define STM32F4_ADC_JDR4 0x48
-#define STM32F4_ADC_DR 0x4C
-
-/* STM32F4_ADC_SR - bit fields */
-#define STM32F4_STRT BIT(4)
-#define STM32F4_EOC BIT(1)
-
-/* STM32F4_ADC_CR1 - bit fields */
-#define STM32F4_RES_SHIFT 24
-#define STM32F4_RES_MASK GENMASK(25, 24)
-#define STM32F4_SCAN BIT(8)
-#define STM32F4_EOCIE BIT(5)
-
-/* STM32F4_ADC_CR2 - bit fields */
-#define STM32F4_SWSTART BIT(30)
-#define STM32F4_EXTEN_SHIFT 28
-#define STM32F4_EXTEN_MASK GENMASK(29, 28)
-#define STM32F4_EXTSEL_SHIFT 24
-#define STM32F4_EXTSEL_MASK GENMASK(27, 24)
-#define STM32F4_EOCS BIT(10)
-#define STM32F4_DDS BIT(9)
-#define STM32F4_DMA BIT(8)
-#define STM32F4_ADON BIT(0)
-
-/* STM32H7 - Registers for each ADC instance */
-#define STM32H7_ADC_ISR 0x00
-#define STM32H7_ADC_IER 0x04
-#define STM32H7_ADC_CR 0x08
-#define STM32H7_ADC_CFGR 0x0C
-#define STM32H7_ADC_SMPR1 0x14
-#define STM32H7_ADC_SMPR2 0x18
-#define STM32H7_ADC_PCSEL 0x1C
-#define STM32H7_ADC_SQR1 0x30
-#define STM32H7_ADC_SQR2 0x34
-#define STM32H7_ADC_SQR3 0x38
-#define STM32H7_ADC_SQR4 0x3C
-#define STM32H7_ADC_DR 0x40
-#define STM32H7_ADC_DIFSEL 0xC0
-#define STM32H7_ADC_CALFACT 0xC4
-#define STM32H7_ADC_CALFACT2 0xC8
-
-/* STM32H7_ADC_ISR - bit fields */
-#define STM32MP1_VREGREADY BIT(12)
-#define STM32H7_EOC BIT(2)
-#define STM32H7_ADRDY BIT(0)
-
-/* STM32H7_ADC_IER - bit fields */
-#define STM32H7_EOCIE STM32H7_EOC
-
-/* STM32H7_ADC_CR - bit fields */
-#define STM32H7_ADCAL BIT(31)
-#define STM32H7_ADCALDIF BIT(30)
-#define STM32H7_DEEPPWD BIT(29)
-#define STM32H7_ADVREGEN BIT(28)
-#define STM32H7_LINCALRDYW6 BIT(27)
-#define STM32H7_LINCALRDYW5 BIT(26)
-#define STM32H7_LINCALRDYW4 BIT(25)
-#define STM32H7_LINCALRDYW3 BIT(24)
-#define STM32H7_LINCALRDYW2 BIT(23)
-#define STM32H7_LINCALRDYW1 BIT(22)
-#define STM32H7_ADCALLIN BIT(16)
-#define STM32H7_BOOST BIT(8)
-#define STM32H7_ADSTP BIT(4)
-#define STM32H7_ADSTART BIT(2)
-#define STM32H7_ADDIS BIT(1)
-#define STM32H7_ADEN BIT(0)
-
-/* STM32H7_ADC_CFGR bit fields */
-#define STM32H7_EXTEN_SHIFT 10
-#define STM32H7_EXTEN_MASK GENMASK(11, 10)
-#define STM32H7_EXTSEL_SHIFT 5
-#define STM32H7_EXTSEL_MASK GENMASK(9, 5)
-#define STM32H7_RES_SHIFT 2
-#define STM32H7_RES_MASK GENMASK(4, 2)
-#define STM32H7_DMNGT_SHIFT 0
-#define STM32H7_DMNGT_MASK GENMASK(1, 0)
-
-enum stm32h7_adc_dmngt {
- STM32H7_DMNGT_DR_ONLY, /* Regular data in DR only */
- STM32H7_DMNGT_DMA_ONESHOT, /* DMA one shot mode */
- STM32H7_DMNGT_DFSDM, /* DFSDM mode */
- STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */
-};
-
-/* STM32H7_ADC_CALFACT - bit fields */
-#define STM32H7_CALFACT_D_SHIFT 16
-#define STM32H7_CALFACT_D_MASK GENMASK(26, 16)
-#define STM32H7_CALFACT_S_SHIFT 0
-#define STM32H7_CALFACT_S_MASK GENMASK(10, 0)
-
-/* STM32H7_ADC_CALFACT2 - bit fields */
-#define STM32H7_LINCALFACT_SHIFT 0
-#define STM32H7_LINCALFACT_MASK GENMASK(29, 0)
-
/* Number of linear calibration shadow registers / LINCALRDYW control bits */
#define STM32H7_LINCALFACT_NUM 6
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 2/2] iio: adc: stm32-adc: fix a race when using several adcs with dma and irq
From: Fabrice Gasnier @ 2019-09-17 12:38 UTC (permalink / raw)
To: jic23
Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
mcoquelin.stm32, knaack.h, fabrice.gasnier, linux-stm32,
linux-arm-kernel
In-Reply-To: <1568723896-19063-1-git-send-email-fabrice.gasnier@st.com>
End of conversion may be handled by using IRQ or DMA. There may be a
race when two conversions complete at the same time on several ADCs.
EOC can be read as 'set' for several ADCs, with:
- an ADC configured to use IRQs. EOCIE bit is set. The handler is normally
called in this case.
- an ADC configured to use DMA. EOCIE bit isn't set. EOC triggers the DMA
request instead. It's then automatically cleared by DMA read. But the
handler gets called due to status bit is temporarily set (IRQ triggered
by the other ADC).
So both EOC status bit in CSR and EOCIE control bit must be checked
before invoking the interrupt handler (e.g. call ISR only for
IRQ-enabled ADCs).
Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- Keep registers definitions as a whole block to ease readability (add
a precursor patch to move them to header file)
---
drivers/iio/adc/stm32-adc-core.c | 43 +++++++++++++++++++++++++++++++++++++---
drivers/iio/adc/stm32-adc-core.h | 1 +
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 84ac326..93a096a 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -44,6 +44,8 @@
* @eoc1: adc1 end of conversion flag in @csr
* @eoc2: adc2 end of conversion flag in @csr
* @eoc3: adc3 end of conversion flag in @csr
+ * @ier: interrupt enable register offset for each adc
+ * @eocie_msk: end of conversion interrupt enable mask in @ier
*/
struct stm32_adc_common_regs {
u32 csr;
@@ -51,6 +53,8 @@ struct stm32_adc_common_regs {
u32 eoc1_msk;
u32 eoc2_msk;
u32 eoc3_msk;
+ u32 ier;
+ u32 eocie_msk;
};
struct stm32_adc_priv;
@@ -276,6 +280,8 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.eoc1_msk = STM32F4_EOC1,
.eoc2_msk = STM32F4_EOC2,
.eoc3_msk = STM32F4_EOC3,
+ .ier = STM32F4_ADC_CR1,
+ .eocie_msk = STM32F4_EOCIE,
};
/* STM32H7 common registers definitions */
@@ -284,8 +290,24 @@ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.ccr = STM32H7_ADC_CCR,
.eoc1_msk = STM32H7_EOC_MST,
.eoc2_msk = STM32H7_EOC_SLV,
+ .ier = STM32H7_ADC_IER,
+ .eocie_msk = STM32H7_EOCIE,
};
+static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
+ 0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2,
+};
+
+static unsigned int stm32_adc_eoc_enabled(struct stm32_adc_priv *priv,
+ unsigned int adc)
+{
+ u32 ier, offset = stm32_adc_offset[adc];
+
+ ier = readl_relaxed(priv->common.base + offset + priv->cfg->regs->ier);
+
+ return ier & priv->cfg->regs->eocie_msk;
+}
+
/* ADC common interrupt for all instances */
static void stm32_adc_irq_handler(struct irq_desc *desc)
{
@@ -296,13 +318,28 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
chained_irq_enter(chip, desc);
status = readl_relaxed(priv->common.base + priv->cfg->regs->csr);
- if (status & priv->cfg->regs->eoc1_msk)
+ /*
+ * End of conversion may be handled by using IRQ or DMA. There may be a
+ * race here when two conversions complete at the same time on several
+ * ADCs. EOC may be read 'set' for several ADCs, with:
+ * - an ADC configured to use DMA (EOC triggers the DMA request, and
+ * is then automatically cleared by DR read in hardware)
+ * - an ADC configured to use IRQs (EOCIE bit is set. The handler must
+ * be called in this case)
+ * So both EOC status bit in CSR and EOCIE control bit must be checked
+ * before invoking the interrupt handler (e.g. call ISR only for
+ * IRQ-enabled ADCs).
+ */
+ if (status & priv->cfg->regs->eoc1_msk &&
+ stm32_adc_eoc_enabled(priv, 0))
generic_handle_irq(irq_find_mapping(priv->domain, 0));
- if (status & priv->cfg->regs->eoc2_msk)
+ if (status & priv->cfg->regs->eoc2_msk &&
+ stm32_adc_eoc_enabled(priv, 1))
generic_handle_irq(irq_find_mapping(priv->domain, 1));
- if (status & priv->cfg->regs->eoc3_msk)
+ if (status & priv->cfg->regs->eoc3_msk &&
+ stm32_adc_eoc_enabled(priv, 2))
generic_handle_irq(irq_find_mapping(priv->domain, 2));
chained_irq_exit(chip, desc);
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 94aa2d2..2579d51 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -25,6 +25,7 @@
* --------------------------------------------------------
*/
#define STM32_ADC_MAX_ADCS 3
+#define STM32_ADC_OFFSET 0x100
#define STM32_ADCX_COMN_OFFSET 0x300
/* STM32F4 - Registers for each ADC instance */
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [REGRESSION] sdhci no longer detects SD cards on LX2160A
From: Russell King - ARM Linux admin @ 2019-09-17 12:33 UTC (permalink / raw)
To: Adrian Hunter, Will Deacon; +Cc: linux-mmc, Linux ARM
In-Reply-To: <20190917114210.GM25745@shell.armlinux.org.uk>
On Tue, Sep 17, 2019 at 12:42:10PM +0100, Russell King - ARM Linux admin wrote:
> On Tue, Sep 17, 2019 at 12:16:31PM +0100, Russell King - ARM Linux admin wrote:
> > On Tue, Sep 17, 2019 at 11:42:00AM +0100, Russell King - ARM Linux admin wrote:
> > > On Tue, Sep 17, 2019 at 09:19:31AM +0100, Russell King - ARM Linux admin wrote:
> > > > On Tue, Sep 17, 2019 at 10:06:12AM +0200, Marc Gonzalez wrote:
> > > > > On 16/09/2019 19:15, Russell King - ARM Linux admin wrote:
> > > > >
> > > > > > The platform has an iommu, which is in pass-through mode, via
> > > > > > arm_smmu.disable_bypass=0.
> > > > >
> > > > > Could be 954a03be033c7cef80ddc232e7cbdb17df735663
> > > > > "iommu/arm-smmu: Break insecure users by disabling bypass by default"
> > > > >
> > > > > Although it had already landed in v5.2
> > > >
> > > > It is not - and the two lines that you quoted above are sufficient
> > > > to negate that as a cause. (Please read the help for the option that
> > > > the commit referrs to.)
> > > >
> > > > In fact, with bypass disabled, the SoC fails due to other masters.
> > > > That's already been discussed privately between myself and Will
> > > > Deacon.
> > > >
> > > > arm_smmu.disable_bypass=0 re-enables bypass mode irrespective of
> > > > the default setting in the Kconfig.
> > >
> > > Adding some further debugging, and fixing the existing ADMA debugging
> > > shows:
> > >
> > > mmc0: ADMA error: 0x02000000
> > >
> > > So this is an ADMA error without the transfer having completed.
> > >
> > > mmc0: sdhci: Blk size: 0x00000008 | Blk cnt: 0x00000001
> > >
> > > The block size is 8, with one block.
> > >
> > > mmc0: sdhci: ADMA Err: 0x00000009 | ADMA Ptr: 0x000000236df1d20c
> > >
> > > The ADMA error is a descriptor error at address 0x000000236df1d20c.
> > > The descriptor table contains (including the following entry):
> > >
> > > mmc0: sdhci: 236df1d200: DMA 0x000000236d40e980, LEN 0x0008, Attr=0x23
> > > mmc0: sdhci: 236df1d20c: DMA 0x0000000000000000, LEN 0x0000, Attr=0x00
> > >
> > > The descriptor table contains one descriptor of 8 bytes, is marked
> > > as the last (END bit set) and is at DMA address 0x236df1d200. The
> > > following descriptor is empty, with VALID=0.
> > >
> > > One may be tempted to blame it on the following descriptor, but having
> > > had another example on eMMC while userspace was booting (rootfs on
> > > eMMC):
> > >
> > > mmc1: ADMA error: 0x02000000
> > > mmc1: sdhci: Blk size: 0x00000200 | Blk cnt: 0x00000099
> > > mmc1: sdhci: ADMA Err: 0x00000006 | ADMA Ptr: 0x000000236dbfa26c
> > > mmc1: sdhci: 236dbfa200: DMA 0x000000236c25c000, LEN 0x2000, Attr=0x21
> > > mmc1: sdhci: 236dbfa20c: DMA 0x000000236938c000, LEN 0x0000, Attr=0x21
> > > mmc1: sdhci: 236dbfa218: DMA 0x000000236939c000, LEN 0x5000, Attr=0x21
> > > mmc1: sdhci: 236dbfa224: DMA 0x0000002368545000, LEN 0x1000, Attr=0x21
> > > mmc1: sdhci: 236dbfa230: DMA 0x00000023684f1000, LEN 0x1000, Attr=0x21
> > > mmc1: sdhci: 236dbfa23c: DMA 0x0000002368504000, LEN 0x2000, Attr=0x21
> > > mmc1: sdhci: 236dbfa248: DMA 0x0000002368546000, LEN 0x2000, Attr=0x21
> > > mmc1: sdhci: 236dbfa254: DMA 0x00000023684f2000, LEN 0x2000, Attr=0x21
> > > mmc1: sdhci: 236dbfa260: DMA 0x0000002368500000, LEN 0x1000, Attr=0x23
> > > mmc1: sdhci: 236dbfa26c: DMA 0x000000236b55d000, LEN 0x1000, Attr=0x21
> > >
> > > ... which is interesting for several reasons:
> > > - The ADMA error register indicates a length mismatch error. The
> > > transfer was for 0x99 blocks of 0x200, which is 0x13200 bytes.
> > > Summing the ADMA lengths up to the last descriptor (length=0 is
> > > 0x10000 bytes) gives 0x20000 bytes. So the DMA table contains more
> > > bytes than the requested transfer.
> > >
> > > - The ADMA error register indicates ST_CADR, which is described as
> > > "This state is never set because do not generate ADMA error in this
> > > state."
> > >
> > > - The error descriptor is again after the descriptor with END=1, but
> > > this time has VALID=1.
> > >
> > > This _feels_ like a coherency issue, where the SDHCI engine is not
> > > correctly seeing the descriptor table, but then I would have expected
> > > userspace (which is basically debian stable) to fail to boot every
> > > time given that its rootfs is on eMMC.
> > >
> > > The other weird thing is if I wind the core MMC code back via:
> > >
> > > $ git diff -u 7559d612dff0..v5.3 drivers/mmc/core | patch -p1 -R
> > >
> > > and fix the lack of dma_max_pfn(), then SDHCI is more stable - not
> > > completely stable, but way better than plain v5.3. I don't see
> > > much in that diff which would be responsible for this - although it
> > > does seem that hch's DMA changes do make the problem more likely.
> > > (going from 1 in 3 boots with a problem to being not able to boot.)
> > >
> > > Note, with v5.2, I _never_ saw any ADMA errors, except if I disabled
> > > bypass mode on the IOMMU (but then I saw global smmu errors right
> > > from when the IOMMU had bypass disabled before MMC was probed - the
> > > reason being is the SoC is not currently setup to have the MMU
> > > bypass mode disabled.)
> >
> > This looks like an ARM64 coherency issue.
> >
> > I first tried adding a dma_wmb() to the end of sdhci_adma_table_pre(),
> > which had no effect. I then tried adding:
> >
> > + __dma_flush_area(host->adma_table, desc - host->adma_table);
> > + dma_wmb();
> >
> > and so far I haven't had any further ADMA errors. Adding Will Deacon
> > to the thread.
>
> These are the changes to sdhci that I'm currently running. I think
> some of the debugging related changes are probably worth adding to
> the driver, particularly printing the intmask on ADMA error (which
> is not printed by the register dump, as the value is lost) and printing
> the DMA addresses of the descriptor table entries which can be tied
> up with the DMA address error register. Also, maybe printing the
> DMA descriptor table with the register dump, rather than having to
> resort to enabling debug would be a good idea?
>
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index a5dc5aae973e..884dcaa9cad5 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -773,6 +773,8 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
> /* Add a terminating entry - nop, end, valid */
> __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
> }
> + __dma_flush_area(host->adma_table, desc - host->adma_table);
> + dma_wmb();
> }
>
> static void sdhci_adma_table_post(struct sdhci_host *host,
> @@ -2855,6 +2857,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
> static void sdhci_adma_show_error(struct sdhci_host *host)
> {
> void *desc = host->adma_table;
> + dma_addr_t dma = host->adma_addr;
> + bool end = false;
>
> sdhci_dumpregs(host);
>
> @@ -2862,21 +2866,26 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
> struct sdhci_adma2_64_desc *dma_desc = desc;
>
> if (host->flags & SDHCI_USE_64_BIT_DMA)
> - DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
> - desc, le32_to_cpu(dma_desc->addr_hi),
> + SDHCI_DUMP("%08llx: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
> + (unsigned long long)dma,
> + le32_to_cpu(dma_desc->addr_hi),
> le32_to_cpu(dma_desc->addr_lo),
> le16_to_cpu(dma_desc->len),
> le16_to_cpu(dma_desc->cmd));
> else
> - DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
> - desc, le32_to_cpu(dma_desc->addr_lo),
> + SDHCI_DUMP("%08llx: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
> + (unsigned long long)dma,
> + le32_to_cpu(dma_desc->addr_lo),
> le16_to_cpu(dma_desc->len),
> le16_to_cpu(dma_desc->cmd));
>
> + if (end) break;
> +
> desc += host->desc_sz;
> + dma += host->desc_sz;
>
> if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
> - break;
> + end = true;
> }
> }
>
> @@ -2949,7 +2958,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
> != MMC_BUS_TEST_R)
> host->data->error = -EILSEQ;
> else if (intmask & SDHCI_INT_ADMA_ERROR) {
> - pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
> + pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc), intmask);
> sdhci_adma_show_error(host);
> host->data->error = -EIO;
> if (host->ops->adma_workaround)
Further debug shows:
coherent=0 - sdhci device is not cache coherent
swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000081cac000
[ffffff8010fd5200] pgd=000000237ffff003, pud=000000237ffff003,
pmd=000000237fffb003, pte=00e800236d62270f
The mapping for the ADMA table seems to be using MAIR index 3, which is
MT_MEMORY_NC, so should be non-cacheable.
vmallocinfo:
0xffffff8010fd5000-0xffffff8010fd7000 8192 dma_direct_alloc+0x4c/0x54
user
So this memory has been remapped. Could there be an alias that has
cache lines still in the cache for the physical address, and could we
be hitting those cache lines while accessing through a non-cacheable
mapping? (On 32-bit ARM, this is "unpredictable" and this problem
definitely _feels_ like it has unpredictable attributes!)
Also, given that this memory is mapped NC, then surely
__dma_flush_area() should have no effect? However, it _does_ have the
effect of reliably solving the problem, which to me implies that there
_are_ cache lines in this NC mapping.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v1 2/2] of: Let of_for_each_phandle fallback to non-negative cell_count
From: Uwe Kleine-König @ 2019-09-17 12:25 UTC (permalink / raw)
To: Peter Rosin
Cc: Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Frank Rowand, Joerg Roedel, Linux Kernel Mailing List,
Linux-Renesas, Wolfram Sang, Linux IOMMU, Geert Uytterhoeven,
Linux I2C, Sascha Hauer, Matthias Brugger,
linux-mediatek@lists.infradead.org, Will Deacon, Linux ARM,
Robin Murphy
In-Reply-To: <489c90fb-a135-4fd8-ecb9-46404bd3c234@axentia.se>
On Tue, Sep 17, 2019 at 11:25:46AM +0000, Peter Rosin wrote:
> On 2019-09-17 12:13, Uwe Kleine-König wrote:
> > Hello Geert,
> >
> > On Tue, Sep 17, 2019 at 11:40:25AM +0200, Geert Uytterhoeven wrote:
> >> Hi Rob, Uwe,
> >>
> >> On Fri, Sep 13, 2019 at 11:58 PM Rob Herring <robh@kernel.org> wrote:
> >>> On Sat, 24 Aug 2019 15:28:46 +0200, =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= wrote:
> >>>> Referencing device tree nodes from a property allows to pass arguments.
> >>>> This is for example used for referencing gpios. This looks as follows:
> >>>>
> >>>> gpio_ctrl: gpio-controller {
> >>>> #gpio-cells = <2>
> >>>> ...
> >>>> }
> >>>>
> >>>> someothernode {
> >>>> gpios = <&gpio_ctrl 5 0 &gpio_ctrl 3 0>;
> >>>> ...
> >>>> }
> >>>>
> >>>> To know the number of arguments this must be either fixed, or the
> >>>> referenced node is checked for a $cells_name (here: "#gpio-cells")
> >>>> property and with this information the start of the second reference can
> >>>> be determined.
> >>>>
> >>>> Currently regulators are referenced with no additional arguments. To
> >>>> allow some optional arguments without having to change all referenced
> >>>> nodes this change introduces a way to specify a default cell_count. So
> >>>> when a phandle is parsed we check for the $cells_name property and use
> >>>> it as before if present. If it is not present we fall back to
> >>>> cells_count if non-negative and only fail if cells_count is smaller than
> >>>> zero.
> >>>>
> >>>> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> >>
> >> This is now commit e42ee61017f58cd9 ("of: Let of_for_each_phandle fallback
> >> to non-negative cell_count") in robh/for-next, which causes a lock-up when
> >> booting a shmobile_defconfig kernel on r8a7791/koelsch:
> >>
> >> rcu: INFO: rcu_sched self-detected stall on CPU
> >> rcu: 0-....: (2099 ticks this GP) idle=6fe/1/0x40000002
> >> softirq=29/29 fqs=1050
> >> (t=2100 jiffies g=-1131 q=0)
> >> NMI backtrace for cpu 0
> >> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> >> 5.3.0-rc2-shmobile-00050-ge42ee61017f58cd9 #376
> >> Hardware name: Generic R-Car Gen2 (Flattened Device Tree)
> >> [<c010f8ac>] (unwind_backtrace) from [<c010b620>] (show_stack+0x10/0x14)
> >> [<c010b620>] (show_stack) from [<c073d038>] (dump_stack+0x7c/0x9c)
> >> [<c073d038>] (dump_stack) from [<c0742e80>] (nmi_cpu_backtrace+0xa0/0xb8)
> >> [<c0742e80>] (nmi_cpu_backtrace) from [<c0742f1c>] (nmi_trigger_cpumask_backtrace+0x84/0x114)
> >> [<c0742f1c>] (nmi_trigger_cpumask_backtrace) from [<c017d684>] (rcu_dump_cpu_stacks+0xac/0xc8)
> >> [<c017d684>] (rcu_dump_cpu_stacks) from [<c017a598>] (rcu_sched_clock_irq+0x2ac/0x6b4)
> >> [<c017a598>] (rcu_sched_clock_irq) from [<c0183980>] (update_process_times+0x30/0x5c)
> >> [<c0183980>] (update_process_times) from [<c01941a8>] (tick_nohz_handler+0xcc/0x120)
> >> [<c01941a8>] (tick_nohz_handler) from [<c05b1d40>] (arch_timer_handler_virt+0x28/0x30)
> >> [<c05b1d40>] (arch_timer_handler_virt) from [<c016c9e0>] (handle_percpu_devid_irq+0xe8/0x21c)
> >> [<c016c9e0>] (handle_percpu_devid_irq) from [<c0167a8c>] (generic_handle_irq+0x18/0x28)
> >> [<c0167a8c>] (generic_handle_irq) from [<c0167b3c>] (__handle_domain_irq+0xa0/0xb4)
> >> [<c0167b3c>] (__handle_domain_irq) from [<c03673ec>] (gic_handle_irq+0x58/0x90)
> >> [<c03673ec>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
> >> Exception stack(0xeb08dd30 to 0xeb08dd78)
> >> dd20: c0cc7514 20000013 00000005 00003b27
> >> dd40: eb7c4020 c0cc750c 00000051 00000051 20000013 c0c66b08 eb1cdc00 00000018
> >> dd60: 00000000 eb08dd80 c05c1a38 c0756c00 20000013 ffffffff
> >> [<c0101a8c>] (__irq_svc) from [<c0756c00>] (_raw_spin_unlock_irqrestore+0x1c/0x20)
> >> [<c0756c00>] (_raw_spin_unlock_irqrestore) from [<c05c1a38>] (of_find_node_by_phandle+0xcc/0xf0)
> >> [<c05c1a38>] (of_find_node_by_phandle) from [<c05c1bb8>] (of_phandle_iterator_next+0x68/0x178)
> >> [<c05c1bb8>] (of_phandle_iterator_next) from [<c05c22bc>] (of_count_phandle_with_args+0x5c/0x7c)
> >> [<c05c22bc>] (of_count_phandle_with_args) from [<c053fc38>] (i2c_demux_pinctrl_probe+0x24/0x1fc)
> >> [<c053fc38>] (i2c_demux_pinctrl_probe) from [<c04463c4>] (platform_drv_probe+0x48/0x94)
> >> [<c04463c4>] (platform_drv_probe) from [<c0444a20>] (really_probe+0x1f0/0x2b8)
> >> [<c0444a20>] (really_probe) from [<c0444e68>] (driver_probe_device+0x140/0x158)
> >> [<c0444e68>] (driver_probe_device) from [<c0444ff0>] (device_driver_attach+0x44/0x5c)
> >> [<c0444ff0>] (device_driver_attach) from [<c04450b4>] (__driver_attach+0xac/0xb4)
> >> [<c04450b4>] (__driver_attach) from [<c0443178>] (bus_for_each_dev+0x64/0xa0)
> >> [<c0443178>] (bus_for_each_dev) from [<c04438a8>] (bus_add_driver+0x148/0x1a8)
> >> [<c04438a8>] (bus_add_driver) from [<c0445ad0>] (driver_register+0xac/0xf0)
> >> [<c0445ad0>] (driver_register) from [<c0b010b0>] (do_one_initcall+0xa8/0x1d4)
> >> [<c0b010b0>] (do_one_initcall) from [<c0b01448>] (kernel_init_freeable+0x26c/0x2c8)
> >> [<c0b01448>] (kernel_init_freeable) from [<c0751c70>] (kernel_init+0x8/0x10c)
> >> [<c0751c70>] (kernel_init) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
> >> Exception stack(0xeb08dfb0 to 0xeb08dff8)
> >> dfa0: 00000000 00000000 00000000 00000000
> >> dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> >> dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
> >>
> >> Presumably it loops forever, due to a conversion of -1 to unsigned
> >> somewhere?
> >
> > Hmm, I fail to see the culprit. i2c_demux_pinctrl_probe calls
> > of_count_phandle_with_args with cells_name=NULL. With that I don't see
> > how my patch changes anything as the only change is in an if
> > (it->cells_name) block that shouldn't be relevant in your case.
> >
> > Can you please verify that the loop in of_count_phandle_with_args is
> > indeed not terminating, e.g. with
>
> The below indicated else-branch was not touched by e42ee61017f58cd9,
> which ends up setting the count to -1 (aka 0xff...ff in this case).
> No?
>
> int of_phandle_iterator_next(struct of_phandle_iterator *it)
> {
>
> ...
>
> if (it->cells_name) {
>
> ...
>
> } else {
> count = it->cell_count; /* <---- SUSPECT!!! */
> }
Oh yeah, you're right. I'm a bit disappointed that I didn't spot this
myself :-|
Untested patch to fix this problem:
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 2f25d2dfecfa..26f7a21d7187 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1284,6 +1284,13 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
const __be32 *list;
int size;
+ /*
+ * one of cell_count or cells_name must be provided to determine the
+ * argument length.
+ */
+ if (cell_count < 0 && !cells_name)
+ return -EINVAL;
+
memset(it, 0, sizeof(*it));
list = of_get_property(np, list_name, &size);
@@ -1765,6 +1772,18 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
struct of_phandle_iterator it;
int rc, cur_index = 0;
+ /* If cells_name is NULL we assume an cell_count of 0 */
+ if (cells_name == NULL) {
+ const __be32 *list;
+ int size;
+
+ list = of_get_property(np, list_name, &size);
+ if (!list)
+ return -ENOENT;
+
+ return size / sizeof(*list);
+ }
+
rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1);
if (rc)
return rc;
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [V2, 1/2] media: dt-bindings: media: i2c: Add bindings for ov8856
From: Sakari Ailus @ 2019-09-17 12:02 UTC (permalink / raw)
To: Andy Shevchenko
Cc: mark.rutland, devicetree, drinkcat, srv_heupstream, shengnan.wang,
tfiga, louis.kuo, sj.huang, robh+dt, linux-mediatek, dongchun.zhu,
matthias.bgg, bingbu.cao, mchehab, linux-arm-kernel, linux-media
In-Reply-To: <20190910173743.GI2680@smile.fi.intel.com>
On Tue, Sep 10, 2019 at 08:37:43PM +0300, Andy Shevchenko wrote:
> On Tue, Sep 10, 2019 at 09:04:45PM +0800, dongchun.zhu@mediatek.com wrote:
> > From: Dongchun Zhu <dongchun.zhu@mediatek.com>
> >
> > This patch adds device tree bindings documentation for the ov8856 CMOS
> > image sensor.
>
> New bindings in YAML, please.
My understanding is text documents are still fine.
We don't have things like graph.txt or video-interfaces.txt in YAML yet
either.
--
Sakari Ailus
sakari.ailus@linux.intel.com
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/3] pinctrl: meson-a1: add pinctrl driver for Meson A1 Soc
From: Qianggui Song @ 2019-09-17 11:51 UTC (permalink / raw)
To: Jerome Brunet
Cc: Mark Rutland, Hanjie Lin, Jianxin Pan, Neil Armstrong,
Martin Blumenstingl, Kevin Hilman, Linus Walleij, linux-kernel,
linux-gpio, Rob Herring, linux-arm-kernel, Carlo Caione,
linux-amlogic, Xingyu Chen
In-Reply-To: <1jef0f46fj.fsf@starbuckisacylon.baylibre.com>
Hi, Jerome
Thanks for your review
On 2019/9/17 17:29, Jerome Brunet wrote:
>
> On Tue 17 Sep 2019 at 08:07, Qianggui Song <qianggui.song@amlogic.com> wrote:
>
>> Add pinctrl driver for Meson A1 Soc which share the same register layout of
>> pinmux with previous Meson-G12A, however there is difference for gpio
>> and pin config register in A1. The register layout is as below:
>>
>> /* first bank */ /* addr */
>> - P_PADCTRL_GPIOP_I base + 0x00 << 2
>> - P_PADCTRL_GPIOP_O base + 0x01 << 2
>> - P_PADCTRL_GPIOP_OEN base + 0x02 << 2
>> - P_PADCTRL_GPIOP_PULL_EN base + 0x03 << 2
>> - P_PADCTRL_GPIOP_PULL_UP base + 0x04 << 2
>> - P_PADCTRL_GPIOP_DS base + 0x05 << 2
>>
>> /* second bank */
>> - P_PADCTRL_GPIOB_I base + 0x10 << 2
>> - P_PADCTRL_GPIOB_O base + 0x11 << 2
>> - P_PADCTRL_GPIOB_OEN base + 0x12 << 2
>> - P_PADCTRL_GPIOB_PULL_EN base + 0x13 << 2
>> - P_PADCTRL_GPIOB_PULL_UP base + 0x14 << 2
>> - P_PADCTRL_GPIOB_DS base + 0x15 << 2
>>
>> Each bank contains at least 6 registers to be configured, if one bank has
>> more than 16 gpios, an extra P_PADCTRL_GPIO[X]_DS_EXT is included. Between
>> two adjacent P_PADCTRL_GPIO[X]_I, there is an offset 0x10, that is to say,
>> for third bank, the offsets will be 0x20,0x21,0x22,0x23,0x24,0x25 according
>> to above register layout.
>>
>> Current Meson pinctrl driver can cover such change by using base address of
>> GPIO as that of drive-strength. While simply giving reg_ds = reg_pullen
>> make wrong value to reg_ds for Soc that not support drive-strength like AXG
>> . Here a private data used to identify register layout is introduced.
>>
>> Signed-off-by: Qianggui Song <qianggui.song@amlogic.com>
>> Signed-off-by: Xingyu Chen <xingyu.chen@amlogic.com>
>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>> ---
>> drivers/pinctrl/meson/Kconfig | 6 +
>> drivers/pinctrl/meson/Makefile | 1 +
>> drivers/pinctrl/meson/pinctrl-meson-a1.c | 942 +++++++++++++++++++++++++++++++
>> drivers/pinctrl/meson/pinctrl-meson.c | 8 +-
>> drivers/pinctrl/meson/pinctrl-meson.h | 9 +
>> 5 files changed, 964 insertions(+), 2 deletions(-)
>> create mode 100644 drivers/pinctrl/meson/pinctrl-meson-a1.c
>>
>> diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig
>> index df55f61..3cb1191 100644
>> --- a/drivers/pinctrl/meson/Kconfig
>> +++ b/drivers/pinctrl/meson/Kconfig
>> @@ -54,4 +54,10 @@ config PINCTRL_MESON_G12A
>> select PINCTRL_MESON_AXG_PMX
>> default y
>>
>> +config PINCTRL_MESON_A1
>> + bool "Meson a1 Soc pinctrl driver"
>> + depends on ARM64
>> + select PINCTRL_MESON_AXG_PMX
>> + default y
>> +
>> endif
>> diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
>> index a69c565..1a5bffe 100644
>> --- a/drivers/pinctrl/meson/Makefile
>> +++ b/drivers/pinctrl/meson/Makefile
>> @@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o
>> obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o
>> obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o
>> obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o
>> +obj-$(CONFIG_PINCTRL_MESON_A1) += pinctrl-meson-a1.o
>> diff --git a/drivers/pinctrl/meson/pinctrl-meson-a1.c b/drivers/pinctrl/meson/pinctrl-meson-a1.c
>> new file mode 100644
>> index 0000000..f3a88f1
>> --- /dev/null
>> +++ b/drivers/pinctrl/meson/pinctrl-meson-a1.c
>> @@ -0,0 +1,942 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Pin controller and GPIO driver for Amlogic Meson A1 SoC.
>> + *
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + * Author: Qianggui Song <qianggui.song@amlogic.com>
>> + */
>> +
>> +#include <dt-bindings/gpio/meson-a1-gpio.h>
>> +#include "pinctrl-meson.h"
>> +#include "pinctrl-meson-axg-pmx.h"
>> +
>> +static const struct pinctrl_pin_desc meson_a1_periphs_pins[] = {
>> + MESON_PIN(GPIOP_0),
>> + MESON_PIN(GPIOP_1),
>> + MESON_PIN(GPIOP_2),
>> + MESON_PIN(GPIOP_3),
>> + MESON_PIN(GPIOP_4),
>> + MESON_PIN(GPIOP_5),
>> + MESON_PIN(GPIOP_6),
>> + MESON_PIN(GPIOP_7),
>> + MESON_PIN(GPIOP_8),
>> + MESON_PIN(GPIOP_9),
>> + MESON_PIN(GPIOP_10),
>> + MESON_PIN(GPIOP_11),
>> + MESON_PIN(GPIOP_12),
>> + MESON_PIN(GPIOB_0),
>> + MESON_PIN(GPIOB_1),
>> + MESON_PIN(GPIOB_2),
>> + MESON_PIN(GPIOB_3),
>> + MESON_PIN(GPIOB_4),
>> + MESON_PIN(GPIOB_5),
>> + MESON_PIN(GPIOB_6),
>> + MESON_PIN(GPIOX_0),
>> + MESON_PIN(GPIOX_1),
>> + MESON_PIN(GPIOX_2),
>> + MESON_PIN(GPIOX_3),
>> + MESON_PIN(GPIOX_4),
>> + MESON_PIN(GPIOX_5),
>> + MESON_PIN(GPIOX_6),
>> + MESON_PIN(GPIOX_7),
>> + MESON_PIN(GPIOX_8),
>> + MESON_PIN(GPIOX_9),
>> + MESON_PIN(GPIOX_10),
>> + MESON_PIN(GPIOX_11),
>> + MESON_PIN(GPIOX_12),
>> + MESON_PIN(GPIOX_13),
>> + MESON_PIN(GPIOX_14),
>> + MESON_PIN(GPIOX_15),
>> + MESON_PIN(GPIOX_16),
>> + MESON_PIN(GPIOF_0),
>> + MESON_PIN(GPIOF_1),
>> + MESON_PIN(GPIOF_2),
>> + MESON_PIN(GPIOF_3),
>> + MESON_PIN(GPIOF_4),
>> + MESON_PIN(GPIOF_5),
>> + MESON_PIN(GPIOF_6),
>> + MESON_PIN(GPIOF_7),
>> + MESON_PIN(GPIOF_8),
>> + MESON_PIN(GPIOF_9),
>> + MESON_PIN(GPIOF_10),
>> + MESON_PIN(GPIOF_11),
>> + MESON_PIN(GPIOF_12),
>> + MESON_PIN(GPIOA_0),
>> + MESON_PIN(GPIOA_1),
>> + MESON_PIN(GPIOA_2),
>> + MESON_PIN(GPIOA_3),
>> + MESON_PIN(GPIOA_4),
>> + MESON_PIN(GPIOA_5),
>> + MESON_PIN(GPIOA_6),
>> + MESON_PIN(GPIOA_7),
>> + MESON_PIN(GPIOA_8),
>> + MESON_PIN(GPIOA_9),
>> + MESON_PIN(GPIOA_10),
>> + MESON_PIN(GPIOA_11),
>> +};
>> +
>> +/* psram */
>> +static const unsigned int psram_clkn_pins[] = { GPIOP_0 };
>> +static const unsigned int psram_clkp_pins[] = { GPIOP_1 };
>> +static const unsigned int psram_ce_n_pins[] = { GPIOP_2 };
>> +static const unsigned int psram_rst_n_pins[] = { GPIOP_3 };
>> +static const unsigned int psram_adq0_pins[] = { GPIOP_4 };
>> +static const unsigned int psram_adq1_pins[] = { GPIOP_5 };
>> +static const unsigned int psram_adq2_pins[] = { GPIOP_6 };
>> +static const unsigned int psram_adq3_pins[] = { GPIOP_7 };
>> +static const unsigned int psram_adq4_pins[] = { GPIOP_8 };
>> +static const unsigned int psram_adq5_pins[] = { GPIOP_9 };
>> +static const unsigned int psram_adq6_pins[] = { GPIOP_10 };
>> +static const unsigned int psram_adq7_pins[] = { GPIOP_11 };
>> +static const unsigned int psram_dqs_dm_pins[] = { GPIOP_12 };
>> +
>> +/* sdcard */
>> +static const unsigned int sdcard_d0_b_pins[] = { GPIOB_0 };
>> +static const unsigned int sdcard_d1_b_pins[] = { GPIOB_1 };
>> +static const unsigned int sdcard_d2_b_pins[] = { GPIOB_2 };
>> +static const unsigned int sdcard_d3_b_pins[] = { GPIOB_3 };
>> +static const unsigned int sdcard_clk_b_pins[] = { GPIOB_4 };
>> +static const unsigned int sdcard_cmd_b_pins[] = { GPIOB_5 };
>> +
>> +static const unsigned int sdcard_d0_x_pins[] = { GPIOX_0 };
>> +static const unsigned int sdcard_d1_x_pins[] = { GPIOX_1 };
>> +static const unsigned int sdcard_d2_x_pins[] = { GPIOX_2 };
>> +static const unsigned int sdcard_d3_x_pins[] = { GPIOX_3 };
>> +static const unsigned int sdcard_clk_x_pins[] = { GPIOX_4 };
>> +static const unsigned int sdcard_cmd_x_pins[] = { GPIOX_5 };
>> +
>> +/* spif */
>> +static const unsigned int spif_mo_pins[] = { GPIOB_0 };
>> +static const unsigned int spif_mi_pins[] = { GPIOB_1 };
>> +static const unsigned int spif_wp_n_pins[] = { GPIOB_2 };
>> +static const unsigned int spif_hold_n_pins[] = { GPIOB_3 };
>> +static const unsigned int spif_clk_pins[] = { GPIOB_4 };
>> +static const unsigned int spif_cs_pins[] = { GPIOB_5 };
>> +
>> +/* i2c0 */
>> +static const unsigned int i2c0_sck_f9_pins[] = { GPIOF_9 };
>> +static const unsigned int i2c0_sda_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int i2c0_sck_f11_pins[] = { GPIOF_11 };
>> +static const unsigned int i2c0_sda_f12_pins[] = { GPIOF_12 };
>> +
>> +/* i2c1 */
>> +static const unsigned int i2c1_sda_x_pins[] = { GPIOX_9 };
>> +static const unsigned int i2c1_sck_x_pins[] = { GPIOX_10 };
>> +static const unsigned int i2c1_sda_a_pins[] = { GPIOA_10 };
>> +static const unsigned int i2c1_sck_a_pins[] = { GPIOA_11 };
>> +
>> +/* i2c2 */
>> +static const unsigned int i2c2_sck_x0_pins[] = { GPIOX_0 };
>> +static const unsigned int i2c2_sda_x1_pins[] = { GPIOX_1 };
>> +static const unsigned int i2c2_sck_x15_pins[] = { GPIOX_15 };
>> +static const unsigned int i2c2_sda_x16_pins[] = { GPIOX_16 };
>> +static const unsigned int i2c2_sck_a4_pins[] = { GPIOA_4 };
>> +static const unsigned int i2c2_sda_a5_pins[] = { GPIOA_5 };
>> +static const unsigned int i2c2_sck_a8_pins[] = { GPIOA_8 };
>> +static const unsigned int i2c2_sda_a9_pins[] = { GPIOA_9 };
>> +
>> +/* i2c3 */
>> +static const unsigned int i2c3_sck_f_pins[] = { GPIOF_4 };
>> +static const unsigned int i2c3_sda_f_pins[] = { GPIOF_5 };
>> +static const unsigned int i2c3_sck_x_pins[] = { GPIOX_11 };
>> +static const unsigned int i2c3_sda_x_pins[] = { GPIOX_12 };
>> +
>> +/* i2c slave */
>> +static const unsigned int i2c_slave_sck_a_pins[] = { GPIOA_10 };
>> +static const unsigned int i2c_slave_sda_a_pins[] = { GPIOA_11 };
>> +static const unsigned int i2c_slave_sck_f_pins[] = { GPIOF_11 };
>> +static const unsigned int i2c_slave_sda_f_pins[] = { GPIOF_12 };
>> +
>> +/* uart_a */
>> +static const unsigned int uart_a_tx_pins[] = { GPIOX_11 };
>> +static const unsigned int uart_a_rx_pins[] = { GPIOX_12 };
>> +static const unsigned int uart_a_cts_pins[] = { GPIOX_13 };
>> +static const unsigned int uart_a_rts_pins[] = { GPIOX_14 };
>> +
>> +/* uart_b */
>> +static const unsigned int uart_b_tx_x_pins[] = { GPIOX_7 };
>> +static const unsigned int uart_b_rx_x_pins[] = { GPIOX_8 };
>> +static const unsigned int uart_b_tx_f_pins[] = { GPIOF_0 };
>> +static const unsigned int uart_b_rx_f_pins[] = { GPIOF_1 };
>> +
>> +/* uart_c */
>> +static const unsigned int uart_c_tx_x0_pins[] = { GPIOX_0 };
>> +static const unsigned int uart_c_rx_x1_pins[] = { GPIOX_1 };
>> +static const unsigned int uart_c_cts_pins[] = { GPIOX_2 };
>> +static const unsigned int uart_c_rts_pins[] = { GPIOX_3 };
>> +static const unsigned int uart_c_tx_x15_pins[] = { GPIOX_15 };
>> +static const unsigned int uart_c_rx_x16_pins[] = { GPIOX_16 };
>> +
>> +/* pmw_a */
>> +static const unsigned int pwm_a_x6_pins[] = { GPIOX_6 };
>> +static const unsigned int pwm_a_x7_pins[] = { GPIOX_7 };
>> +static const unsigned int pwm_a_f6_pins[] = { GPIOF_6 };
>> +static const unsigned int pwm_a_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int pwm_a_a_pins[] = { GPIOA_5 };
>> +
>> +/* pmw_b */
>> +static const unsigned int pwm_b_x_pins[] = { GPIOX_8 };
>> +static const unsigned int pwm_b_f_pins[] = { GPIOF_7 };
>> +static const unsigned int pwm_b_a_pins[] = { GPIOA_11 };
>> +
>> +/* pmw_c */
>> +static const unsigned int pwm_c_x_pins[] = { GPIOX_9 };
>> +static const unsigned int pwm_c_f3_pins[] = { GPIOF_3 };
>> +static const unsigned int pwm_c_f8_pins[] = { GPIOF_8 };
>> +static const unsigned int pwm_c_a_pins[] = { GPIOA_10 };
>> +
>> +/* pwm_d */
>> +static const unsigned int pwm_d_x10_pins[] = { GPIOX_10 };
>> +static const unsigned int pwm_d_x13_pins[] = { GPIOX_13 };
>> +static const unsigned int pwm_d_x15_pins[] = { GPIOX_15 };
>> +static const unsigned int pwm_d_f_pins[] = { GPIOF_11 };
>> +
>> +/* pwm_e */
>> +static const unsigned int pwm_e_p_pins[] = { GPIOP_3 };
>> +static const unsigned int pwm_e_x2_pins[] = { GPIOX_2 };
>> +static const unsigned int pwm_e_x14_pins[] = { GPIOX_14 };
>> +static const unsigned int pwm_e_x16_pins[] = { GPIOX_16 };
>> +static const unsigned int pwm_e_f_pins[] = { GPIOF_3 };
>> +static const unsigned int pwm_e_a_pins[] = { GPIOA_0 };
>> +
>> +/* pwm_f */
>> +static const unsigned int pwm_f_b_pins[] = { GPIOB_6 };
>> +static const unsigned int pwm_f_x_pins[] = { GPIOX_3 };
>> +static const unsigned int pwm_f_f4_pins[] = { GPIOF_4 };
>> +static const unsigned int pwm_f_f12_pins[] = { GPIOF_12 };
>> +
>> +/* pwm_a_hiz */
>> +static const unsigned int pwm_a_hiz_f8_pins[] = { GPIOF_8 };
>> +static const unsigned int pwm_a_hiz_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int pmw_a_hiz_f6_pins[] = { GPIOF_6 };
>> +
>> +/* pwm_b_hiz */
>> +static const unsigned int pwm_b_hiz_pins[] = { GPIOF_7 };
>> +
>> +/* pmw_c_hiz */
>> +static const unsigned int pwm_c_hiz_pins[] = { GPIOF_8 };
>> +
>> +/* tdm_a */
>> +static const unsigned int tdm_a_dout1_pins[] = { GPIOX_7 };
>> +static const unsigned int tdm_a_dout0_pins[] = { GPIOX_8 };
>> +static const unsigned int tdm_a_fs_pins[] = { GPIOX_9 };
>> +static const unsigned int tdm_a_sclk_pins[] = { GPIOX_10 };
>> +static const unsigned int tdm_a_din1_pins[] = { GPIOX_7 };
>> +static const unsigned int tdm_a_din0_pins[] = { GPIOX_8 };
>> +static const unsigned int tdm_a_slv_fs_pins[] = { GPIOX_9 };
>> +static const unsigned int tdm_a_slv_sclk_pins[] = { GPIOX_10 };
>> +
>> +/* spi_a */
>> +static const unsigned int spi_a_mosi_x2_pins[] = { GPIOX_2 };
>> +static const unsigned int spi_a_ss0_x3_pins[] = { GPIOX_3 };
>> +static const unsigned int spi_a_sclk_x4_pins[] = { GPIOX_4 };
>> +static const unsigned int spi_a_miso_x5_pins[] = { GPIOX_5 };
>> +static const unsigned int spi_a_mosi_x7_pins[] = { GPIOX_7 };
>> +static const unsigned int spi_a_miso_x8_pins[] = { GPIOX_8 };
>> +static const unsigned int spi_a_ss0_x9_pins[] = { GPIOX_9 };
>> +static const unsigned int spi_a_sclk_x10_pins[] = { GPIOX_10 };
>> +
>> +static const unsigned int spi_a_mosi_a_pins[] = { GPIOA_6 };
>> +static const unsigned int spi_a_miso_a_pins[] = { GPIOA_7 };
>> +static const unsigned int spi_a_ss0_a_pins[] = { GPIOA_8 };
>> +static const unsigned int spi_a_sclk_a_pins[] = { GPIOA_9 };
>> +
>> +/* pdm */
>> +static const unsigned int pdm_din0_x_pins[] = { GPIOX_7 };
>> +static const unsigned int pdm_din1_x_pins[] = { GPIOX_8 };
>> +static const unsigned int pdm_din2_x_pins[] = { GPIOX_9 };
>> +static const unsigned int pdm_dclk_x_pins[] = { GPIOX_10 };
>> +
>> +static const unsigned int pdm_din2_a_pins[] = { GPIOA_6 };
>> +static const unsigned int pdm_din1_a_pins[] = { GPIOA_7 };
>> +static const unsigned int pdm_din0_a_pins[] = { GPIOA_8 };
>> +static const unsigned int pdm_dclk_pins[] = { GPIOA_9 };
>> +
>> +/* gen_clk */
>> +static const unsigned int gen_clk_x_pins[] = { GPIOX_7 };
>> +static const unsigned int gen_clk_f8_pins[] = { GPIOF_8 };
>> +static const unsigned int gen_clk_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int gen_clk_a_pins[] = { GPIOA_11 };
>> +
>> +/* jtag_a */
>> +static const unsigned int jtag_a_clk_pins[] = { GPIOF_4 };
>> +static const unsigned int jtag_a_tms_pins[] = { GPIOF_5 };
>> +static const unsigned int jtag_a_tdi_pins[] = { GPIOF_6 };
>> +static const unsigned int jtag_a_tdo_pins[] = { GPIOF_7 };
>> +
>> +/* clk_32_in */
>> +static const unsigned int clk_32k_in_pins[] = { GPIOF_2 };
>> +
>> +/* ir in */
>> +static const unsigned int remote_input_f_pins[] = { GPIOF_3 };
>> +static const unsigned int remote_input_a_pins[] = { GPIOA_11 };
>> +
>> +/* ir out */
>> +static const unsigned int remote_out_pins[] = { GPIOF_5 };
>> +
>> +/* spdif */
>> +static const unsigned int spdif_in_f6_pins[] = { GPIOF_6 };
>> +static const unsigned int spdif_in_f7_pins[] = { GPIOF_7 };
>> +
>> +/* sw */
>> +static const unsigned int swclk_pins[] = { GPIOF_4 };
>> +static const unsigned int swdio_pins[] = { GPIOF_5 };
>> +
>> +/* clk_25 */
>> +static const unsigned int clk25_pins[] = { GPIOF_10 };
>> +
>> +/* cec_a */
>> +static const unsigned int cec_a_pins[] = { GPIOF_2 };
>> +
>> +/* cec_b */
>> +static const unsigned int cec_b_pins[] = { GPIOF_2 };
>> +
>> +/* clk12_24 */
>> +static const unsigned int clk12_24_pins[] = { GPIOF_10 };
>> +
>> +/* mclk_0 */
>> +static const unsigned int mclk_0_pins[] = { GPIOA_0 };
>> +
>> +/* tdm_b */
>> +static const unsigned int tdm_b_sclk_pins[] = { GPIOA_1 };
>> +static const unsigned int tdm_b_fs_pins[] = { GPIOA_2 };
>> +static const unsigned int tdm_b_dout0_pins[] = { GPIOA_3 };
>> +static const unsigned int tdm_b_dout1_pins[] = { GPIOA_4 };
>> +static const unsigned int tdm_b_dout2_pins[] = { GPIOA_5 };
>> +static const unsigned int tdm_b_dout3_pins[] = { GPIOA_6 };
>> +static const unsigned int tdm_b_dout4_pins[] = { GPIOA_7 };
>> +static const unsigned int tdm_b_dout5_pins[] = { GPIOA_8 };
>> +static const unsigned int tdm_b_slv_sclk_pins[] = { GPIOA_5 };
>> +static const unsigned int tdm_b_slv_fs_pins[] = { GPIOA_6 };
>> +static const unsigned int tdm_b_din0_pins[] = { GPIOA_7 };
>> +static const unsigned int tdm_b_din1_pins[] = { GPIOA_8 };
>> +static const unsigned int tdm_b_din2_pins[] = { GPIOA_9 };
>> +
>> +/* mclk_vad */
>> +static const unsigned int mclk_vad_pins[] = { GPIOA_0 };
>> +
>> +/* tdm_vad */
>> +static const unsigned int tdm_vad_sclk_a1_pins[] = { GPIOA_1 };
>> +static const unsigned int tdm_vad_fs_a2_pins[] = { GPIOA_2 };
>> +static const unsigned int tdm_vad_sclk_a5_pins[] = { GPIOA_5 };
>> +static const unsigned int tdm_vad_fs_a6_pins[] = { GPIOA_6 };
>> +
>> +/* tst_out */
>> +static const unsigned int tst_out0_pins[] = { GPIOA_0 };
>> +static const unsigned int tst_out1_pins[] = { GPIOA_1 };
>> +static const unsigned int tst_out2_pins[] = { GPIOA_2 };
>> +static const unsigned int tst_out3_pins[] = { GPIOA_3 };
>> +static const unsigned int tst_out4_pins[] = { GPIOA_4 };
>> +static const unsigned int tst_out5_pins[] = { GPIOA_5 };
>> +static const unsigned int tst_out6_pins[] = { GPIOA_6 };
>> +static const unsigned int tst_out7_pins[] = { GPIOA_7 };
>> +static const unsigned int tst_out8_pins[] = { GPIOA_8 };
>> +static const unsigned int tst_out9_pins[] = { GPIOA_9 };
>> +static const unsigned int tst_out10_pins[] = { GPIOA_10 };
>> +static const unsigned int tst_out11_pins[] = { GPIOA_11 };
>> +
>> +/* mute */
>> +static const unsigned int mute_key_pins[] = { GPIOA_4 };
>> +static const unsigned int mute_en_pins[] = { GPIOA_5 };
>> +
>> +static struct meson_pmx_group meson_a1_periphs_groups[] = {
>> + GPIO_GROUP(GPIOP_0),
>> + GPIO_GROUP(GPIOP_1),
>> + GPIO_GROUP(GPIOP_2),
>> + GPIO_GROUP(GPIOP_3),
>> + GPIO_GROUP(GPIOP_4),
>> + GPIO_GROUP(GPIOP_5),
>> + GPIO_GROUP(GPIOP_6),
>> + GPIO_GROUP(GPIOP_7),
>> + GPIO_GROUP(GPIOP_8),
>> + GPIO_GROUP(GPIOP_9),
>> + GPIO_GROUP(GPIOP_10),
>> + GPIO_GROUP(GPIOP_11),
>> + GPIO_GROUP(GPIOP_12),
>> + GPIO_GROUP(GPIOB_0),
>> + GPIO_GROUP(GPIOB_1),
>> + GPIO_GROUP(GPIOB_2),
>> + GPIO_GROUP(GPIOB_3),
>> + GPIO_GROUP(GPIOB_4),
>> + GPIO_GROUP(GPIOB_5),
>> + GPIO_GROUP(GPIOB_6),
>> + GPIO_GROUP(GPIOX_0),
>> + GPIO_GROUP(GPIOX_1),
>> + GPIO_GROUP(GPIOX_2),
>> + GPIO_GROUP(GPIOX_3),
>> + GPIO_GROUP(GPIOX_4),
>> + GPIO_GROUP(GPIOX_5),
>> + GPIO_GROUP(GPIOX_6),
>> + GPIO_GROUP(GPIOX_7),
>> + GPIO_GROUP(GPIOX_8),
>> + GPIO_GROUP(GPIOX_9),
>> + GPIO_GROUP(GPIOX_10),
>> + GPIO_GROUP(GPIOX_11),
>> + GPIO_GROUP(GPIOX_12),
>> + GPIO_GROUP(GPIOX_13),
>> + GPIO_GROUP(GPIOX_14),
>> + GPIO_GROUP(GPIOX_15),
>> + GPIO_GROUP(GPIOX_16),
>> + GPIO_GROUP(GPIOF_0),
>> + GPIO_GROUP(GPIOF_1),
>> + GPIO_GROUP(GPIOF_2),
>> + GPIO_GROUP(GPIOF_3),
>> + GPIO_GROUP(GPIOF_4),
>> + GPIO_GROUP(GPIOF_5),
>> + GPIO_GROUP(GPIOF_6),
>> + GPIO_GROUP(GPIOF_7),
>> + GPIO_GROUP(GPIOF_8),
>> + GPIO_GROUP(GPIOF_9),
>> + GPIO_GROUP(GPIOF_10),
>> + GPIO_GROUP(GPIOF_11),
>> + GPIO_GROUP(GPIOF_12),
>> + GPIO_GROUP(GPIOA_0),
>> + GPIO_GROUP(GPIOA_1),
>> + GPIO_GROUP(GPIOA_2),
>> + GPIO_GROUP(GPIOA_3),
>> + GPIO_GROUP(GPIOA_4),
>> + GPIO_GROUP(GPIOA_5),
>> + GPIO_GROUP(GPIOA_6),
>> + GPIO_GROUP(GPIOA_7),
>> + GPIO_GROUP(GPIOA_8),
>> + GPIO_GROUP(GPIOA_9),
>> + GPIO_GROUP(GPIOA_10),
>> + GPIO_GROUP(GPIOA_11),
>> +
>> + /* bank P func1 */
>> + GROUP(psram_clkn, 1),
>> + GROUP(psram_clkp, 1),
>> + GROUP(psram_ce_n, 1),
>> + GROUP(psram_rst_n, 1),
>> + GROUP(psram_adq0, 1),
>> + GROUP(psram_adq1, 1),
>> + GROUP(psram_adq2, 1),
>> + GROUP(psram_adq3, 1),
>> + GROUP(psram_adq4, 1),
>> + GROUP(psram_adq5, 1),
>> + GROUP(psram_adq6, 1),
>> + GROUP(psram_adq7, 1),
>> + GROUP(psram_dqs_dm, 1),
>> +
>> + /*bank P func2 */
>> + GROUP(pwm_e_p, 2),
>> +
>> + /*bank B func1 */
>> + GROUP(spif_mo, 1),
>> + GROUP(spif_mi, 1),
>> + GROUP(spif_wp_n, 1),
>> + GROUP(spif_hold_n, 1),
>> + GROUP(spif_clk, 1),
>> + GROUP(spif_cs, 1),
>> + GROUP(pwm_f_b, 1),
>> +
>> + /*bank B func2 */
>> + GROUP(sdcard_d0_b, 2),
>> + GROUP(sdcard_d1_b, 2),
>> + GROUP(sdcard_d2_b, 2),
>> + GROUP(sdcard_d3_b, 2),
>> + GROUP(sdcard_clk_b, 2),
>> + GROUP(sdcard_cmd_b, 2),
>> +
>> + /*bank X func1 */
>> + GROUP(sdcard_d0_x, 1),
>> + GROUP(sdcard_d1_x, 1),
>> + GROUP(sdcard_d2_x, 1),
>> + GROUP(sdcard_d3_x, 1),
>> + GROUP(sdcard_clk_x, 1),
>> + GROUP(sdcard_cmd_x, 1),
>> + GROUP(pwm_a_x6, 1),
>> + GROUP(tdm_a_dout1, 1),
>> + GROUP(tdm_a_dout0, 1),
>> + GROUP(tdm_a_fs, 1),
>> + GROUP(tdm_a_sclk, 1),
>> + GROUP(uart_a_tx, 1),
>> + GROUP(uart_a_rx, 1),
>> + GROUP(uart_a_cts, 1),
>> + GROUP(uart_a_rts, 1),
>> + GROUP(pwm_d_x15, 1),
>> + GROUP(pwm_e_x16, 1),
>> +
>> + /*bank X func2 */
>> + GROUP(i2c2_sck_x0, 2),
>> + GROUP(i2c2_sda_x1, 2),
>> + GROUP(spi_a_mosi_x2, 2),
>> + GROUP(spi_a_ss0_x3, 2),
>> + GROUP(spi_a_sclk_x4, 2),
>> + GROUP(spi_a_miso_x5, 2),
>> + GROUP(tdm_a_din1, 2),
>> + GROUP(tdm_a_din0, 2),
>> + GROUP(tdm_a_slv_fs, 2),
>> + GROUP(tdm_a_slv_sclk, 2),
>> + GROUP(i2c3_sck_x, 2),
>> + GROUP(i2c3_sda_x, 2),
>> + GROUP(pwm_d_x13, 2),
>> + GROUP(pwm_e_x14, 2),
>> + GROUP(i2c2_sck_x15, 2),
>> + GROUP(i2c2_sda_x16, 2),
>> +
>> + /*bank X func3 */
>> + GROUP(uart_c_tx_x0, 3),
>> + GROUP(uart_c_rx_x1, 3),
>> + GROUP(uart_c_cts, 3),
>> + GROUP(uart_c_rts, 3),
>> + GROUP(pdm_din0_x, 3),
>> + GROUP(pdm_din1_x, 3),
>> + GROUP(pdm_din2_x, 3),
>> + GROUP(pdm_dclk_x, 3),
>> + GROUP(uart_c_tx_x15, 3),
>> + GROUP(uart_c_rx_x16, 3),
>> +
>> + /*bank X func4 */
>> + GROUP(pwm_e_x2, 4),
>> + GROUP(pwm_f_x, 4),
>> + GROUP(spi_a_mosi_x7, 4),
>> + GROUP(spi_a_miso_x8, 4),
>> + GROUP(spi_a_ss0_x9, 4),
>> + GROUP(spi_a_sclk_x10, 4),
>> +
>> + /*bank X func5 */
>> + GROUP(uart_b_tx_x, 5),
>> + GROUP(uart_b_rx_x, 5),
>> + GROUP(i2c1_sda_x, 5),
>> + GROUP(i2c1_sck_x, 5),
>> +
>> + /*bank X func6 */
>> + GROUP(pwm_a_x7, 6),
>> + GROUP(pwm_b_x, 6),
>> + GROUP(pwm_c_x, 6),
>> + GROUP(pwm_d_x10, 6),
>> +
>> + /*bank X func7 */
>> + GROUP(gen_clk_x, 7),
>> +
>> + /*bank F func1 */
>> + GROUP(uart_b_tx_f, 1),
>> + GROUP(uart_b_rx_f, 1),
>> + GROUP(remote_input_f, 1),
>> + GROUP(jtag_a_clk, 1),
>> + GROUP(jtag_a_tms, 1),
>> + GROUP(jtag_a_tdi, 1),
>> + GROUP(jtag_a_tdo, 1),
>> + GROUP(gen_clk_f8, 1),
>> + GROUP(pwm_a_f10, 1),
>> + GROUP(i2c0_sck_f11, 1),
>> + GROUP(i2c0_sda_f12, 1),
>> +
>> + /*bank F func2 */
>> + GROUP(clk_32k_in, 2),
>> + GROUP(pwm_e_f, 2),
>> + GROUP(pwm_f_f4, 2),
>> + GROUP(remote_out, 2),
>> + GROUP(spdif_in_f6, 2),
>> + GROUP(spdif_in_f7, 2),
>> + GROUP(pwm_a_hiz_f8, 2),
>> + GROUP(pwm_a_hiz_f10, 2),
>> + GROUP(pwm_d_f, 2),
>> + GROUP(pwm_f_f12, 2),
>> +
>> + /*bank F func3 */
>> + GROUP(pwm_c_f3, 3),
>> + GROUP(swclk, 3),
>> + GROUP(swdio, 3),
>> + GROUP(pwm_a_f6, 3),
>> + GROUP(pwm_b_f, 3),
>> + GROUP(pwm_c_f8, 3),
>> + GROUP(clk25, 3),
>> + GROUP(i2c_slave_sck_f, 3),
>> + GROUP(i2c_slave_sda_f, 3),
>> +
>> + /*bank F func4 */
>> + GROUP(cec_a, 4),
>> + GROUP(i2c3_sck_f, 4),
>> + GROUP(i2c3_sda_f, 4),
>> + GROUP(pmw_a_hiz_f6, 4),
>> + GROUP(pwm_b_hiz, 4),
>> + GROUP(pwm_c_hiz, 4),
>> + GROUP(i2c0_sck_f9, 4),
>> + GROUP(i2c0_sda_f10, 4),
>> +
>> + /*bank F func5 */
>> + GROUP(cec_b, 5),
>> + GROUP(clk12_24, 5),
>> +
>> + /*bank F func7 */
>> + GROUP(gen_clk_f10, 7),
>> +
>> + /*bank A func1 */
>> + GROUP(mclk_0, 1),
>> + GROUP(tdm_b_sclk, 1),
>> + GROUP(tdm_b_fs, 1),
>> + GROUP(tdm_b_dout0, 1),
>> + GROUP(tdm_b_dout1, 1),
>> + GROUP(tdm_b_dout2, 1),
>> + GROUP(tdm_b_dout3, 1),
>> + GROUP(tdm_b_dout4, 1),
>> + GROUP(tdm_b_dout5, 1),
>> + GROUP(remote_input_a, 1),
>> +
>> + /*bank A func2 */
>> + GROUP(pwm_e_a, 2),
>> + GROUP(tdm_b_slv_sclk, 2),
>> + GROUP(tdm_b_slv_fs, 2),
>> + GROUP(tdm_b_din0, 2),
>> + GROUP(tdm_b_din1, 2),
>> + GROUP(tdm_b_din2, 2),
>> + GROUP(i2c1_sda_a, 2),
>> + GROUP(i2c1_sck_a, 2),
>> +
>> + /*bank A func3 */
>> + GROUP(i2c2_sck_a4, 3),
>> + GROUP(i2c2_sda_a5, 3),
>> + GROUP(pdm_din2_a, 3),
>> + GROUP(pdm_din1_a, 3),
>> + GROUP(pdm_din0_a, 3),
>> + GROUP(pdm_dclk, 3),
>> + GROUP(pwm_c_a, 3),
>> + GROUP(pwm_b_a, 3),
>> +
>> + /*bank A func4 */
>> + GROUP(pwm_a_a, 4),
>> + GROUP(spi_a_mosi_a, 4),
>> + GROUP(spi_a_miso_a, 4),
>> + GROUP(spi_a_ss0_a, 4),
>> + GROUP(spi_a_sclk_a, 4),
>> + GROUP(i2c_slave_sck_a, 4),
>> + GROUP(i2c_slave_sda_a, 4),
>> +
>> + /*bank A func5 */
>> + GROUP(mclk_vad, 5),
>> + GROUP(tdm_vad_sclk_a1, 5),
>> + GROUP(tdm_vad_fs_a2, 5),
>> + GROUP(tdm_vad_sclk_a5, 5),
>> + GROUP(tdm_vad_fs_a6, 5),
>> + GROUP(i2c2_sck_a8, 5),
>> + GROUP(i2c2_sda_a9, 5),
>> +
>> + /*bank A func6 */
>> + GROUP(tst_out0, 6),
>> + GROUP(tst_out1, 6),
>> + GROUP(tst_out2, 6),
>> + GROUP(tst_out3, 6),
>> + GROUP(tst_out4, 6),
>> + GROUP(tst_out5, 6),
>> + GROUP(tst_out6, 6),
>> + GROUP(tst_out7, 6),
>> + GROUP(tst_out8, 6),
>> + GROUP(tst_out9, 6),
>> + GROUP(tst_out10, 6),
>> + GROUP(tst_out11, 6),
>> +
>> + /*bank A func7 */
>> + GROUP(mute_key, 7),
>> + GROUP(mute_en, 7),
>> + GROUP(gen_clk_a, 7),
>> +};
>> +
>> +static const char * const gpio_periphs_groups[] = {
>> + "GPIOP_0", "GPIOP_1", "GPIOP_2", "GPIOP_3", "GPIOP_4",
>> + "GPIOP_5", "GPIOP_6", "GPIOP_7", "GPIOP_8", "GPIOP_9",
>> + "GPIOP_10", "GPIOP_11", "GPIOP_12",
>> +
>> + "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4",
>> + "GPIOB_5", "GPIOB_6",
>> +
>> + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
>> + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
>> + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
>> + "GPIOX_15", "GPIOX_16",
>> +
>> + "GPIOF_0", "GPIOF_1", "GPIOF_2", "GPIOF_3", "GPIOF_4",
>> + "GPIOF_5", "GPIOF_6", "GPIOF_7", "GPIOF_8", "GPIOF_9",
>> + "GPIOF_10", "GPIOF_11", "GPIOF_12",
>> +
>> + "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4",
>> + "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9",
>> + "GPIOA_10", "GPIOA_11",
>> +};
>> +
>> +static const char * const psram_groups[] = {
>> + "psram_clkn", "psram_clkp", "psram_ce_n", "psram_rst_n", "psram_adq0",
>> + "psram_adq1", "psram_adq2", "psram_adq3", "psram_adq4", "psram_adq5",
>> + "psram_adq6", "psram_adq7", "psram_dqs_dm",
>> +};
>> +
>> +static const char * const pwm_a_groups[] = {
>> + "pwm_a_x6", "pwm_a_x7", "pwm_a_f10", "pwm_a_f6", "pwm_a_a",
>> +};
>> +
>> +static const char * const pwm_b_groups[] = {
>> + "pwm_b_x", "pwm_b_f", "pwm_b_a",
>> +};
>> +
>> +static const char * const pwm_c_groups[] = {
>> + "pwm_c_x", "pwm_c_f3", "pwm_c_f8", "pwm_c_a",
>> +};
>> +
>> +static const char * const pwm_d_groups[] = {
>> + "pwm_d_x15", "pwm_d_x13", "pwm_d_x10", "pwm_d_f",
>> +};
>> +
>> +static const char * const pwm_e_groups[] = {
>> + "pwm_e_p", "pwm_e_x16", "pwm_e_x14", "pwm_e_x2", "pwm_e_f",
>> + "pwm_e_a",
>> +};
>> +
>> +static const char * const pwm_f_groups[] = {
>> + "pwm_f_b", "pwm_f_x", "pwm_f_f4", "pwm_f_f12",
>> +};
>> +
>> +static const char * const pwm_a_hiz_groups[] = {
>> + "pwm_a_hiz_f8", "pwm_a_hiz_f10", "pwm_a_hiz_f6",
>> +};
>> +
>> +static const char * const pwm_b_hiz_groups[] = {
>> + "pwm_b_hiz",
>> +};
>> +
>> +static const char * const pwm_c_hiz_groups[] = {
>> + "pwm_c_hiz",
>> +};
>> +
>> +static const char * const spif_groups[] = {
>> + "spif_mo", "spif_mi", "spif_wp_n", "spif_hold_n", "spif_clk",
>> + "spif_cs",
>> +};
>> +
>> +static const char * const sdcard_groups[] = {
>> + "sdcard_d0_b", "sdcard_d1_b", "sdcard_d2_b", "sdcard_d3_b",
>> + "sdcard_clk_b", "sdcard_cmd_b",
>> +
>> + "sdcard_d0_x", "sdcard_d1_x", "sdcard_d2_x", "sdcard_d3_x",
>> + "sdcard_clk_x", "sdcard_cmd_x",
>> +};
>> +
>> +static const char * const tdm_a_groups[] = {
>> + "tdm_a_din0", "tdm_a_din1", "tdm_a_fs", "tdm_a_sclk",
>> + "tdm_a_slv_fs", "tdm_a_slv_sclk", "tdm_a_dout0", "tdm_a_dout1",
>> +};
>> +
>> +static const char * const uart_a_groups[] = {
>> + "uart_a_tx", "uart_a_rx", "uart_a_cts", "uart_a_rts",
>> +};
>> +
>> +static const char * const uart_b_groups[] = {
>> + "uart_b_tx_x", "uart_b_rx_x", "uart_b_tx_f", "uart_b_rx_f",
>> +};
>> +
>> +static const char * const uart_c_groups[] = {
>> + "uart_c_tx_x0", "uart_c_rx_x1", "uart_c_cts", "uart_c_rts",
>> + "uart_c_tx_x15", "uart_c_rx_x16",
>> +};
>> +
>> +static const char * const i2c0_groups[] = {
>> + "i2c0_sck_f11", "i2c0_sda_f12", "i2c0_sck_f9", "i2c0_sda_f10",
>> +};
>> +
>> +static const char * const i2c1_groups[] = {
>> + "i2c1_sda_x", "i2c1_sck_x", "i2c1_sda_a", "i2c1_sck_a",
>> +};
>> +
>> +static const char * const i2c2_groups[] = {
>> + "i2c2_sck_x0", "i2c2_sda_x1", "i2c2_sck_x15", "i2c2_sda_x16",
>> + "i2c2_sck_a4", "i2c2_sda_a5", "i2c2_sck_a8", "i2c2_sda_a9",
>> +};
>> +
>> +static const char * const i2c3_groups[] = {
>> + "i2c3_sck_x", "i2c3_sda_x", "i2c3_sck_f", "i2c3_sda_f",
>> +};
>> +
>> +static const char * const i2c_slave_groups[] = {
>> + "i2c_slave_sda_a", "i2c_slave_sck_a",
>> + "i2c_slave_sda_f", "i2c_slave_sck_f",
>> +};
>> +
>> +static const char * const spi_a_groups[] = {
>> + "spi_a_mosi_x2", "spi_a_ss0_x3", "spi_a_sclk_x4", "spi_a_miso_x5",
>> + "spi_a_mosi_x7", "spi_a_miso_x8", "spi_a_ss0_x9", "spi_a_sclk_x10",
>> +
>> + "spi_a_mosi_a", "spi_a_miso_a", "spi_a_ss0_a", "spi_a_sclk_a",
>> +};
>> +
>> +static const char * const pdm_groups[] = {
>> + "pdm_din0_x", "pdm_din1_x", "pdm_din2_x", "pdm_dclk_x", "pdm_din2_a",
>> + "pdm_din1_a", "pdm_din0_a", "pdm_dclk",
>> +};
>> +
>> +static const char * const gen_clk_groups[] = {
>> + "gen_clk_x", "gen_clk_f8", "gen_clk_f10", "gen_clk_a",
>> +};
>> +
>> +static const char * const remote_input_groups[] = {
>> + "remote_input_f",
>> + "remote_input_a",
>> +};
>> +
>> +static const char * const jtag_a_groups[] = {
>> + "jtag_a_clk", "jtag_a_tms", "jtag_a_tdi", "jtag_a_tdo",
>> +};
>> +
>> +static const char * const clk_32k_in_groups[] = {
>> + "clk_32k_in",
>> +};
>> +
>> +static const char * const remote_out_groups[] = {
>> + "remote_out",
>> +};
>> +
>> +static const char * const spdif_in_groups[] = {
>> + "spdif_in_f6", "spdif_in_f7",
>> +};
>> +
>> +static const char * const sw_groups[] = {
>> + "swclk", "swdio",
>> +};
>> +
>> +static const char * const clk25_groups[] = {
>> + "clk_25",
>> +};
>> +
>> +static const char * const cec_a_groups[] = {
>> + "cec_a",
>> +};
>> +
>> +static const char * const cec_b_groups[] = {
>> + "cec_b",
>> +};
>> +
>> +static const char * const clk12_24_groups[] = {
>> + "clk12_24",
>> +};
>> +
>> +static const char * const mclk_0_groups[] = {
>> + "mclk_0",
>> +};
>> +
>> +static const char * const tdm_b_groups[] = {
>> + "tdm_b_din0", "tdm_b_din1", "tdm_b_din2",
>> + "tdm_b_sclk", "tdm_b_fs", "tdm_b_dout0", "tdm_b_dout1",
>> + "tdm_b_dout2", "tdm_b_dout3", "tdm_b_dout4", "tdm_b_dout5",
>> + "tdm_b_slv_sclk", "tdm_b_slv_fs",
>> +};
>> +
>> +static const char * const mclk_vad_groups[] = {
>> + "mclk_vad",
>> +};
>> +
>> +static const char * const tdm_vad_groups[] = {
>> + "tdm_vad_sclk_a1", "tdm_vad_fs_a2", "tdm_vad_sclk_a5", "tdm_vad_fs_a6",
>> +};
>> +
>> +static const char * const tst_out_groups[] = {
>> + "tst_out0", "tst_out1", "tst_out2", "tst_out3",
>> + "tst_out4", "tst_out5", "tst_out6", "tst_out7",
>> + "tst_out8", "tst_out9", "tst_out10", "tst_out11",
>> +};
>> +
>> +static const char * const mute_groups[] = {
>> + "mute_key", "mute_en",
>> +};
>> +
>> +static struct meson_pmx_func meson_a1_periphs_functions[] = {
>> + FUNCTION(gpio_periphs),
>> + FUNCTION(psram),
>> + FUNCTION(pwm_a),
>> + FUNCTION(pwm_b),
>> + FUNCTION(pwm_c),
>> + FUNCTION(pwm_d),
>> + FUNCTION(pwm_e),
>> + FUNCTION(pwm_f),
>> + FUNCTION(pwm_a_hiz),
>> + FUNCTION(pwm_b_hiz),
>> + FUNCTION(pwm_c_hiz),
>> + FUNCTION(spif),
>> + FUNCTION(sdcard),
>> + FUNCTION(tdm_a),
>> + FUNCTION(uart_a),
>> + FUNCTION(uart_b),
>> + FUNCTION(uart_c),
>> + FUNCTION(i2c0),
>> + FUNCTION(i2c1),
>> + FUNCTION(i2c2),
>> + FUNCTION(i2c3),
>> + FUNCTION(spi_a),
>> + FUNCTION(pdm),
>> + FUNCTION(gen_clk),
>> + FUNCTION(remote_input),
>> + FUNCTION(jtag_a),
>> + FUNCTION(clk_32k_in),
>> + FUNCTION(remote_out),
>> + FUNCTION(spdif_in),
>> + FUNCTION(sw),
>> + FUNCTION(clk25),
>> + FUNCTION(cec_a),
>> + FUNCTION(cec_b),
>> + FUNCTION(clk12_24),
>> + FUNCTION(mclk_0),
>> + FUNCTION(tdm_b),
>> + FUNCTION(mclk_vad),
>> + FUNCTION(tdm_vad),
>> + FUNCTION(tst_out),
>> + FUNCTION(mute),
>> +};
>> +
>> +static struct meson_bank meson_a1_periphs_banks[] = {
>> + /* name first last irq pullen pull dir out in ds*/
>> + BANK_DS("P", GPIOP_0, GPIOP_12, 0, 12, 0x3, 0, 0x4, 0,
>> + 0x2, 0, 0x1, 0, 0x0, 0, 0x5, 0),
>> + BANK_DS("B", GPIOB_0, GPIOB_6, 13, 19, 0x13, 0, 0x14, 0,
>> + 0x12, 0, 0x11, 0, 0x10, 0, 0x15, 0),
>> + BANK_DS("X", GPIOX_0, GPIOX_16, 20, 36, 0x23, 0, 0x24, 0,
>> + 0x22, 0, 0x21, 0, 0x20, 0, 0x25, 0),
>> + BANK_DS("F", GPIOF_0, GPIOF_12, 37, 49, 0x33, 0, 0x34, 0,
>> + 0x32, 0, 0x31, 0, 0x30, 0, 0x35, 0),
>> + BANK_DS("A", GPIOA_0, GPIOA_11, 50, 61, 0x43, 0, 0x44, 0,
>> + 0x42, 0, 0x41, 0, 0x40, 0, 0x45, 0),
>> +};
>> +
>> +static struct meson_pmx_bank meson_a1_periphs_pmx_banks[] = {
>> + /* name first lask reg offset */
>> + BANK_PMX("P", GPIOP_0, GPIOP_12, 0x0, 0),
>> + BANK_PMX("B", GPIOB_0, GPIOB_6, 0x2, 0),
>> + BANK_PMX("X", GPIOX_0, GPIOX_16, 0x3, 0),
>> + BANK_PMX("F", GPIOF_0, GPIOF_12, 0x6, 0),
>> + BANK_PMX("A", GPIOA_0, GPIOA_11, 0x8, 0),
>> +};
>> +
>> +static struct meson_axg_pmx_data meson_a1_periphs_pmx_banks_data = {
>> + .pmx_banks = meson_a1_periphs_pmx_banks,
>> + .num_pmx_banks = ARRAY_SIZE(meson_a1_periphs_pmx_banks),
>> +};
>> +
>> +static struct meson_pinctrl_data meson_a1_periphs_pinctrl_data = {
>> + .name = "periphs-banks",
>> + .pins = meson_a1_periphs_pins,
>> + .groups = meson_a1_periphs_groups,
>> + .funcs = meson_a1_periphs_functions,
>> + .banks = meson_a1_periphs_banks,
>> + .num_pins = ARRAY_SIZE(meson_a1_periphs_pins),
>> + .num_groups = ARRAY_SIZE(meson_a1_periphs_groups),
>> + .num_funcs = ARRAY_SIZE(meson_a1_periphs_functions),
>> + .num_banks = ARRAY_SIZE(meson_a1_periphs_banks),
>> + .pmx_ops = &meson_axg_pmx_ops,
>> + .pmx_data = &meson_a1_periphs_pmx_banks_data,
>> + .reg_layout = A1_LAYOUT,
>> +};
>> +
>> +static const struct of_device_id meson_a1_pinctrl_dt_match[] = {
>> + {
>> + .compatible = "amlogic,meson-a1-periphs-pinctrl",
>> + .data = &meson_a1_periphs_pinctrl_data,
>> + },
>> + { },
>> +};
>> +
>> +static struct platform_driver meson_a1_pinctrl_driver = {
>> + .probe = meson_pinctrl_probe,
>> + .driver = {
>> + .name = "meson-a1-pinctrl",
>> + .of_match_table = meson_a1_pinctrl_dt_match,
>> + },
>> +};
>> +
>> +builtin_platform_driver(meson_a1_pinctrl_driver);
>> diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
>> index 8bba9d0..885b89d 100644
>> --- a/drivers/pinctrl/meson/pinctrl-meson.c
>> +++ b/drivers/pinctrl/meson/pinctrl-meson.c
>> @@ -688,8 +688,12 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
>>
>> pc->reg_ds = meson_map_resource(pc, gpio_np, "ds");
>> if (IS_ERR(pc->reg_ds)) {
>> - dev_dbg(pc->dev, "ds registers not found - skipping\n");
>> - pc->reg_ds = NULL;
>> + if (pc->data->reg_layout == A1_LAYOUT) {
>> + pc->reg_ds = pc->reg_pullen;
>
> IMO, this kind of ID based init fixup is not going to scale and will
> lead to something difficult to maintain in the end.
>
> The way the different register sets interract with each other is already
> pretty complex to follow.
>
> You could rework this in 2 different ways:
> #1 - Have the generic function parse all the register sets and have all
> drivers provide a specific (as in gxbb, gxl, axg, etc ...) function to :
> - Verify the expected sets have been provided
> - Make assignement fixup as above if necessary
>
> #2 - Rework the driver to have only one single register region
> I think one of your colleague previously mentionned this was not
> possible. It is still unclear to me why ...
>
Appreciate your advice. I have an idea based on #1, how about providing
only two dt parse function, one is for chips before A1(the old one),
another is for A1 and later chips that share the same layout. Assign
these two functions to their own driver.
>> + } else {
>> + dev_dbg(pc->dev, "ds registers not found - skipping\n");
>> + pc->reg_ds = NULL;
>> + }
>> }
>>
>> return 0;
>> diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
>> index c696f32..3d0c58d 100644
>> --- a/drivers/pinctrl/meson/pinctrl-meson.h
>> +++ b/drivers/pinctrl/meson/pinctrl-meson.h
>> @@ -80,6 +80,14 @@ enum meson_pinconf_drv {
>> };
>>
>> /**
>> + * enum meson_reg_layout - identify two types of reg layout
>> + */
>> +enum meson_reg_layout {
>> + LEGACY_LAYOUT,
>> + A1_LAYOUT,
>> +};
>> +
>> +/**
>> * struct meson bank
>> *
>> * @name: bank name
>> @@ -114,6 +122,7 @@ struct meson_pinctrl_data {
>> unsigned int num_banks;
>> const struct pinmux_ops *pmx_ops;
>> void *pmx_data;
>> + unsigned int reg_layout;
>> };
>>
>> struct meson_pinctrl {
>
> .
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [REGRESSION] sdhci no longer detects SD cards on LX2160A
From: Russell King - ARM Linux admin @ 2019-09-17 11:42 UTC (permalink / raw)
To: Adrian Hunter, Will Deacon; +Cc: linux-mmc, Linux ARM
In-Reply-To: <20190917111631.GL25745@shell.armlinux.org.uk>
On Tue, Sep 17, 2019 at 12:16:31PM +0100, Russell King - ARM Linux admin wrote:
> On Tue, Sep 17, 2019 at 11:42:00AM +0100, Russell King - ARM Linux admin wrote:
> > On Tue, Sep 17, 2019 at 09:19:31AM +0100, Russell King - ARM Linux admin wrote:
> > > On Tue, Sep 17, 2019 at 10:06:12AM +0200, Marc Gonzalez wrote:
> > > > On 16/09/2019 19:15, Russell King - ARM Linux admin wrote:
> > > >
> > > > > The platform has an iommu, which is in pass-through mode, via
> > > > > arm_smmu.disable_bypass=0.
> > > >
> > > > Could be 954a03be033c7cef80ddc232e7cbdb17df735663
> > > > "iommu/arm-smmu: Break insecure users by disabling bypass by default"
> > > >
> > > > Although it had already landed in v5.2
> > >
> > > It is not - and the two lines that you quoted above are sufficient
> > > to negate that as a cause. (Please read the help for the option that
> > > the commit referrs to.)
> > >
> > > In fact, with bypass disabled, the SoC fails due to other masters.
> > > That's already been discussed privately between myself and Will
> > > Deacon.
> > >
> > > arm_smmu.disable_bypass=0 re-enables bypass mode irrespective of
> > > the default setting in the Kconfig.
> >
> > Adding some further debugging, and fixing the existing ADMA debugging
> > shows:
> >
> > mmc0: ADMA error: 0x02000000
> >
> > So this is an ADMA error without the transfer having completed.
> >
> > mmc0: sdhci: Blk size: 0x00000008 | Blk cnt: 0x00000001
> >
> > The block size is 8, with one block.
> >
> > mmc0: sdhci: ADMA Err: 0x00000009 | ADMA Ptr: 0x000000236df1d20c
> >
> > The ADMA error is a descriptor error at address 0x000000236df1d20c.
> > The descriptor table contains (including the following entry):
> >
> > mmc0: sdhci: 236df1d200: DMA 0x000000236d40e980, LEN 0x0008, Attr=0x23
> > mmc0: sdhci: 236df1d20c: DMA 0x0000000000000000, LEN 0x0000, Attr=0x00
> >
> > The descriptor table contains one descriptor of 8 bytes, is marked
> > as the last (END bit set) and is at DMA address 0x236df1d200. The
> > following descriptor is empty, with VALID=0.
> >
> > One may be tempted to blame it on the following descriptor, but having
> > had another example on eMMC while userspace was booting (rootfs on
> > eMMC):
> >
> > mmc1: ADMA error: 0x02000000
> > mmc1: sdhci: Blk size: 0x00000200 | Blk cnt: 0x00000099
> > mmc1: sdhci: ADMA Err: 0x00000006 | ADMA Ptr: 0x000000236dbfa26c
> > mmc1: sdhci: 236dbfa200: DMA 0x000000236c25c000, LEN 0x2000, Attr=0x21
> > mmc1: sdhci: 236dbfa20c: DMA 0x000000236938c000, LEN 0x0000, Attr=0x21
> > mmc1: sdhci: 236dbfa218: DMA 0x000000236939c000, LEN 0x5000, Attr=0x21
> > mmc1: sdhci: 236dbfa224: DMA 0x0000002368545000, LEN 0x1000, Attr=0x21
> > mmc1: sdhci: 236dbfa230: DMA 0x00000023684f1000, LEN 0x1000, Attr=0x21
> > mmc1: sdhci: 236dbfa23c: DMA 0x0000002368504000, LEN 0x2000, Attr=0x21
> > mmc1: sdhci: 236dbfa248: DMA 0x0000002368546000, LEN 0x2000, Attr=0x21
> > mmc1: sdhci: 236dbfa254: DMA 0x00000023684f2000, LEN 0x2000, Attr=0x21
> > mmc1: sdhci: 236dbfa260: DMA 0x0000002368500000, LEN 0x1000, Attr=0x23
> > mmc1: sdhci: 236dbfa26c: DMA 0x000000236b55d000, LEN 0x1000, Attr=0x21
> >
> > ... which is interesting for several reasons:
> > - The ADMA error register indicates a length mismatch error. The
> > transfer was for 0x99 blocks of 0x200, which is 0x13200 bytes.
> > Summing the ADMA lengths up to the last descriptor (length=0 is
> > 0x10000 bytes) gives 0x20000 bytes. So the DMA table contains more
> > bytes than the requested transfer.
> >
> > - The ADMA error register indicates ST_CADR, which is described as
> > "This state is never set because do not generate ADMA error in this
> > state."
> >
> > - The error descriptor is again after the descriptor with END=1, but
> > this time has VALID=1.
> >
> > This _feels_ like a coherency issue, where the SDHCI engine is not
> > correctly seeing the descriptor table, but then I would have expected
> > userspace (which is basically debian stable) to fail to boot every
> > time given that its rootfs is on eMMC.
> >
> > The other weird thing is if I wind the core MMC code back via:
> >
> > $ git diff -u 7559d612dff0..v5.3 drivers/mmc/core | patch -p1 -R
> >
> > and fix the lack of dma_max_pfn(), then SDHCI is more stable - not
> > completely stable, but way better than plain v5.3. I don't see
> > much in that diff which would be responsible for this - although it
> > does seem that hch's DMA changes do make the problem more likely.
> > (going from 1 in 3 boots with a problem to being not able to boot.)
> >
> > Note, with v5.2, I _never_ saw any ADMA errors, except if I disabled
> > bypass mode on the IOMMU (but then I saw global smmu errors right
> > from when the IOMMU had bypass disabled before MMC was probed - the
> > reason being is the SoC is not currently setup to have the MMU
> > bypass mode disabled.)
>
> This looks like an ARM64 coherency issue.
>
> I first tried adding a dma_wmb() to the end of sdhci_adma_table_pre(),
> which had no effect. I then tried adding:
>
> + __dma_flush_area(host->adma_table, desc - host->adma_table);
> + dma_wmb();
>
> and so far I haven't had any further ADMA errors. Adding Will Deacon
> to the thread.
These are the changes to sdhci that I'm currently running. I think
some of the debugging related changes are probably worth adding to
the driver, particularly printing the intmask on ADMA error (which
is not printed by the register dump, as the value is lost) and printing
the DMA addresses of the descriptor table entries which can be tied
up with the DMA address error register. Also, maybe printing the
DMA descriptor table with the register dump, rather than having to
resort to enabling debug would be a good idea?
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index a5dc5aae973e..884dcaa9cad5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -773,6 +773,8 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
/* Add a terminating entry - nop, end, valid */
__sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
}
+ __dma_flush_area(host->adma_table, desc - host->adma_table);
+ dma_wmb();
}
static void sdhci_adma_table_post(struct sdhci_host *host,
@@ -2855,6 +2857,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
static void sdhci_adma_show_error(struct sdhci_host *host)
{
void *desc = host->adma_table;
+ dma_addr_t dma = host->adma_addr;
+ bool end = false;
sdhci_dumpregs(host);
@@ -2862,21 +2866,26 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
struct sdhci_adma2_64_desc *dma_desc = desc;
if (host->flags & SDHCI_USE_64_BIT_DMA)
- DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
- desc, le32_to_cpu(dma_desc->addr_hi),
+ SDHCI_DUMP("%08llx: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ (unsigned long long)dma,
+ le32_to_cpu(dma_desc->addr_hi),
le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
else
- DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
- desc, le32_to_cpu(dma_desc->addr_lo),
+ SDHCI_DUMP("%08llx: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ (unsigned long long)dma,
+ le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
+ if (end) break;
+
desc += host->desc_sz;
+ dma += host->desc_sz;
if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
- break;
+ end = true;
}
}
@@ -2949,7 +2958,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
!= MMC_BUS_TEST_R)
host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) {
- pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
+ pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc), intmask);
sdhci_adma_show_error(host);
host->data->error = -EIO;
if (host->ops->adma_workaround)
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCHv8 1/7] PCI: mobiveil: Refactor Mobiveil PCIe Host Bridge IP driver
From: Andrew Murray @ 2019-09-17 11:36 UTC (permalink / raw)
To: Z.q. Hou
Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
lorenzo.pieralisi@arm.com, m.karthikeyan@mobiveil.co.in,
arnd@arndb.de, linux-pci@vger.kernel.org,
l.subrahmanya@mobiveil.co.in, will.deacon@arm.com,
linux-kernel@vger.kernel.org, Leo Li, M.h. Lian,
robh+dt@kernel.org, Mingkai Hu, Xiaowei Bao,
catalin.marinas@arm.com, bhelgaas@google.com, shawnguo@kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190813110557.45643-2-Zhiqiang.Hou@nxp.com>
Hi Hou Zhiqiang,
Apologies if I bring up any feedback that has previously been discussed as
I've only recently began reviewing controller patches.
On Tue, Aug 13, 2019 at 11:03:57AM +0000, Z.q. Hou wrote:
> From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
>
> Refactor the Mobiveil PCIe Host Bridge IP driver to make
> it easier to add support for both RC and EP mode driver.
> This patch moved the Mobiveil driver to an new directory
Rephase to "This patch moves the Mobiveil driver to a new directory"
Also with regards to the commit title: "Refactor Mobiveil PCIe Host
Bridge" - this is a very generic phrase and could mean anything. It would
be more helpful to be specific, e.g. "Move definitions to header file" or
"Split driver into host and platform parts" or similar.
> 'drivers/pci/controller/mobiveil' and refactor it according
> to the RC and EP abstraction.
>
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> Reviewed-by: Minghuan Lian <Minghuan.Lian@nxp.com>
> Reviewed-by: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> ---
> V8:
> - Re-generate the patch on the new code base.
>
> MAINTAINERS | 2 +-
> drivers/pci/controller/Kconfig | 11 +-
> drivers/pci/controller/Makefile | 2 +-
> drivers/pci/controller/mobiveil/Kconfig | 24 +
> drivers/pci/controller/mobiveil/Makefile | 4 +
> .../pcie-mobiveil-host.c} | 525 +++---------------
> .../controller/mobiveil/pcie-mobiveil-plat.c | 59 ++
> .../pci/controller/mobiveil/pcie-mobiveil.c | 227 ++++++++
> .../pci/controller/mobiveil/pcie-mobiveil.h | 189 +++++++
> 9 files changed, 592 insertions(+), 451 deletions(-)
> create mode 100644 drivers/pci/controller/mobiveil/Kconfig
> create mode 100644 drivers/pci/controller/mobiveil/Makefile
> rename drivers/pci/controller/{pcie-mobiveil.c => mobiveil/pcie-mobiveil-host.c} (54%)
> create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
> create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil.c
> create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index df85ee4dbdc7..0d88e0d3960b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -12367,7 +12367,7 @@ M: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> L: linux-pci@vger.kernel.org
> S: Supported
> F: Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
> -F: drivers/pci/controller/pcie-mobiveil.c
> +F: drivers/pci/controller/mobiveil/pcie-mobiveil*
>
> PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
> M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
> diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
> index fe9f9f13ce11..dec8e038cb17 100644
> --- a/drivers/pci/controller/Kconfig
> +++ b/drivers/pci/controller/Kconfig
> @@ -241,16 +241,6 @@ config PCIE_MEDIATEK
> Say Y here if you want to enable PCIe controller support on
> MediaTek SoCs.
>
> -config PCIE_MOBIVEIL
> - bool "Mobiveil AXI PCIe controller"
> - depends on ARCH_ZYNQMP || COMPILE_TEST
> - depends on OF
> - depends on PCI_MSI_IRQ_DOMAIN
> - help
> - Say Y here if you want to enable support for the Mobiveil AXI PCIe
> - Soft IP. It has up to 8 outbound and inbound windows
> - for address translation and it is a PCIe Gen4 IP.
> -
> config PCIE_TANGO_SMP8759
> bool "Tango SMP8759 PCIe controller (DANGEROUS)"
> depends on ARCH_TANGO && PCI_MSI && OF
> @@ -282,4 +272,5 @@ config VMD
> module will be called vmd.
>
> source "drivers/pci/controller/dwc/Kconfig"
> +source "drivers/pci/controller/mobiveil/Kconfig"
> endmenu
> diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
> index d56a507495c5..b79a615041a0 100644
> --- a/drivers/pci/controller/Makefile
> +++ b/drivers/pci/controller/Makefile
> @@ -26,11 +26,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
> obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o
> obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
> obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
> -obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
> obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
> obj-$(CONFIG_VMD) += vmd.o
> # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
> obj-y += dwc/
> +obj-y += mobiveil/
>
>
> # The following drivers are for devices that use the generic ACPI
> diff --git a/drivers/pci/controller/mobiveil/Kconfig b/drivers/pci/controller/mobiveil/Kconfig
> new file mode 100644
> index 000000000000..64343c07bfed
> --- /dev/null
> +++ b/drivers/pci/controller/mobiveil/Kconfig
> @@ -0,0 +1,24 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +menu "Mobiveil PCIe Core Support"
> + depends on PCI
> +
> +config PCIE_MOBIVEIL
> + bool
> +
> +config PCIE_MOBIVEIL_HOST
> + bool
> + depends on PCI_MSI_IRQ_DOMAIN
> + select PCIE_MOBIVEIL
This has the same inconsistent indentation as dwc/Kconfig - please you use
tabs here instead of spaces for the 'depends' line.
> +
> +config PCIE_MOBIVEIL_PLAT
> + bool "Mobiveil AXI PCIe controller"
> + depends on ARCH_ZYNQMP || COMPILE_TEST
> + depends on OF
> + select PCIE_MOBIVEIL_HOST
> + help
> + Say Y here if you want to enable support for the Mobiveil AXI PCIe
> + Soft IP. It has up to 8 outbound and inbound windows
> + for address translation and it is a PCIe Gen4 IP.
Does this description describe both host and EP?
There appears to be two existing in-tree approaches to sharing code between EP
and host:
The 'dwc' approach (the one you've taken) - this puts has its own directory,
vendor.c, vendor-ep.c, vendor-host.c and vendor-plat.c files.
The 'cadence','rockchip' approach - this uses the same directory and has a
vendor.c, vendor-ep.c and vendor-host.c
The 'dwc' approach is well suited for its own directory because there are
many DWC drivers and probably many more to come. Why have you chosen this
approach?
> +
> +endmenu
> diff --git a/drivers/pci/controller/mobiveil/Makefile b/drivers/pci/controller/mobiveil/Makefile
> new file mode 100644
> index 000000000000..9fb6d1c6504d
> --- /dev/null
> +++ b/drivers/pci/controller/mobiveil/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
> +obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
> +obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
> diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
> similarity index 54%
> rename from drivers/pci/controller/pcie-mobiveil.c
> rename to drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
> index a45a6447b01d..995487c4f760 100644
> --- a/drivers/pci/controller/pcie-mobiveil.c
> +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
> @@ -3,10 +3,12 @@
> * PCIe host controller driver for Mobiveil PCIe Host controller
> *
> * Copyright (c) 2018 Mobiveil Inc.
> + * Copyright 2019 NXP
> + *
> * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
I'm not sure the value of adding a 'Refactor:' tag here. It's not
a tag I've seen anywhere else in the kernel. I'd rather people rely
on git log to understand the revision history. Though I wouldn't have
any objection to you adding yourself alongside Subrahmanya as a
co-author.
> */
>
> -#include <linux/delay.h>
> #include <linux/init.h>
> #include <linux/interrupt.h>
> #include <linux/irq.h>
> @@ -23,274 +25,21 @@
> #include <linux/platform_device.h>
> #include <linux/slab.h>
>
> -#include "../pci.h"
> -
> -/* register offsets and bit positions */
> -
> -/*
> - * translation tables are grouped into windows, each window registers are
> - * grouped into blocks of 4 or 16 registers each
> - */
> -#define PAB_REG_BLOCK_SIZE 16
> -#define PAB_EXT_REG_BLOCK_SIZE 4
> -
> -#define PAB_REG_ADDR(offset, win) \
> - (offset + (win * PAB_REG_BLOCK_SIZE))
> -#define PAB_EXT_REG_ADDR(offset, win) \
> - (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
> -
> -#define LTSSM_STATUS 0x0404
> -#define LTSSM_STATUS_L0_MASK 0x3f
> -#define LTSSM_STATUS_L0 0x2d
> -
> -#define PAB_CTRL 0x0808
> -#define AMBA_PIO_ENABLE_SHIFT 0
> -#define PEX_PIO_ENABLE_SHIFT 1
> -#define PAGE_SEL_SHIFT 13
> -#define PAGE_SEL_MASK 0x3f
> -#define PAGE_LO_MASK 0x3ff
> -#define PAGE_SEL_OFFSET_SHIFT 10
> -
> -#define PAB_AXI_PIO_CTRL 0x0840
> -#define APIO_EN_MASK 0xf
> -
> -#define PAB_PEX_PIO_CTRL 0x08c0
> -#define PIO_ENABLE_SHIFT 0
> -
> -#define PAB_INTP_AMBA_MISC_ENB 0x0b0c
> -#define PAB_INTP_AMBA_MISC_STAT 0x0b1c
> -#define PAB_INTP_INTX_MASK 0x01e0
> -#define PAB_INTP_MSI_MASK 0x8
> -
> -#define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win)
> -#define WIN_ENABLE_SHIFT 0
> -#define WIN_TYPE_SHIFT 1
> -#define WIN_TYPE_MASK 0x3
> -#define WIN_SIZE_MASK 0xfffffc00
> -
> -#define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win)
> -
> -#define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
> -#define PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win)
> -#define AXI_WINDOW_ALIGN_MASK 3
> -
> -#define PAB_AXI_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x0ba8, win)
> -#define PAB_BUS_SHIFT 24
> -#define PAB_DEVICE_SHIFT 19
> -#define PAB_FUNCTION_SHIFT 16
> -
> -#define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win)
> -#define PAB_INTP_AXI_PIO_CLASS 0x474
> -
> -#define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win)
> -#define AMAP_CTRL_EN_SHIFT 0
> -#define AMAP_CTRL_TYPE_SHIFT 1
> -#define AMAP_CTRL_TYPE_MASK 3
> -
> -#define PAB_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win)
> -#define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win)
> -#define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win)
> -#define PAB_PEX_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x4ba8, win)
> -#define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win)
> -
> -/* starting offset of INTX bits in status register */
> -#define PAB_INTX_START 5
> -
> -/* supported number of MSI interrupts */
> -#define PCI_NUM_MSI 16
> -
> -/* MSI registers */
> -#define MSI_BASE_LO_OFFSET 0x04
> -#define MSI_BASE_HI_OFFSET 0x08
> -#define MSI_SIZE_OFFSET 0x0c
> -#define MSI_ENABLE_OFFSET 0x14
> -#define MSI_STATUS_OFFSET 0x18
> -#define MSI_DATA_OFFSET 0x20
> -#define MSI_ADDR_L_OFFSET 0x24
> -#define MSI_ADDR_H_OFFSET 0x28
> -
> -/* outbound and inbound window definitions */
> -#define WIN_NUM_0 0
> -#define WIN_NUM_1 1
> -#define CFG_WINDOW_TYPE 0
> -#define IO_WINDOW_TYPE 1
> -#define MEM_WINDOW_TYPE 2
> -#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024)
> -#define MAX_PIO_WINDOWS 8
> -
> -/* Parameters for the waiting for link up routine */
> -#define LINK_WAIT_MAX_RETRIES 10
> -#define LINK_WAIT_MIN 90000
> -#define LINK_WAIT_MAX 100000
> -
> -#define PAGED_ADDR_BNDRY 0xc00
> -#define OFFSET_TO_PAGE_ADDR(off) \
> - ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
> -#define OFFSET_TO_PAGE_IDX(off) \
> - ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
> -
> -struct mobiveil_msi { /* MSI information */
> - struct mutex lock; /* protect bitmap variable */
> - struct irq_domain *msi_domain;
> - struct irq_domain *dev_domain;
> - phys_addr_t msi_pages_phys;
> - int num_of_vectors;
> - DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
> -};
> -
> -struct mobiveil_pcie {
> - struct platform_device *pdev;
> - struct list_head resources;
> - void __iomem *config_axi_slave_base; /* endpoint config base */
> - void __iomem *csr_axi_slave_base; /* root port config base */
> - void __iomem *apb_csr_base; /* MSI register base */
> - phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base */
> - struct irq_domain *intx_domain;
> - raw_spinlock_t intx_mask_lock;
> - int irq;
> - int apio_wins;
> - int ppio_wins;
> - int ob_wins_configured; /* configured outbound windows */
> - int ib_wins_configured; /* configured inbound windows */
> - struct resource *ob_io_res;
> - char root_bus_nr;
> - struct mobiveil_msi msi;
> -};
> -
> -/*
> - * mobiveil_pcie_sel_page - routine to access paged register
> - *
> - * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
> - * for this scheme to work extracted higher 6 bits of the offset will be
> - * written to pg_sel field of PAB_CTRL register and rest of the lower 10
> - * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
> - */
> -static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
> -{
> - u32 val;
> -
> - val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
> - val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
> - val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
> -
> - writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
> -}
> -
> -static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
> -{
> - if (off < PAGED_ADDR_BNDRY) {
> - /* For directly accessed registers, clear the pg_sel field */
> - mobiveil_pcie_sel_page(pcie, 0);
> - return pcie->csr_axi_slave_base + off;
> - }
> -
> - mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
> - return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
> -}
> -
> -static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
> -{
> - if ((uintptr_t)addr & (size - 1)) {
> - *val = 0;
> - return PCIBIOS_BAD_REGISTER_NUMBER;
> - }
> -
> - switch (size) {
> - case 4:
> - *val = readl(addr);
> - break;
> - case 2:
> - *val = readw(addr);
> - break;
> - case 1:
> - *val = readb(addr);
> - break;
> - default:
> - *val = 0;
> - return PCIBIOS_BAD_REGISTER_NUMBER;
> - }
> -
> - return PCIBIOS_SUCCESSFUL;
> -}
> -
> -static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
> -{
> - if ((uintptr_t)addr & (size - 1))
> - return PCIBIOS_BAD_REGISTER_NUMBER;
> -
> - switch (size) {
> - case 4:
> - writel(val, addr);
> - break;
> - case 2:
> - writew(val, addr);
> - break;
> - case 1:
> - writeb(val, addr);
> - break;
> - default:
> - return PCIBIOS_BAD_REGISTER_NUMBER;
> - }
> -
> - return PCIBIOS_SUCCESSFUL;
> -}
> -
> -static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
> -{
> - void *addr;
> - u32 val;
> - int ret;
> -
> - addr = mobiveil_pcie_comp_addr(pcie, off);
> -
> - ret = mobiveil_pcie_read(addr, size, &val);
> - if (ret)
> - dev_err(&pcie->pdev->dev, "read CSR address failed\n");
> -
> - return val;
> -}
> -
> -static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
> -{
> - void *addr;
> - int ret;
> -
> - addr = mobiveil_pcie_comp_addr(pcie, off);
> -
> - ret = mobiveil_pcie_write(addr, size, val);
> - if (ret)
> - dev_err(&pcie->pdev->dev, "write CSR address failed\n");
> -}
> -
> -static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
> -{
> - return csr_read(pcie, off, 0x4);
> -}
> -
> -static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
> -{
> - csr_write(pcie, val, off, 0x4);
> -}
> -
> -static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
> -{
> - return (csr_readl(pcie, LTSSM_STATUS) &
> - LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
> -}
> +#include "pcie-mobiveil.h"
>
> static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
> {
> struct mobiveil_pcie *pcie = bus->sysdata;
>
> /* Only one device down on each root port */
> - if ((bus->number == pcie->root_bus_nr) && (devfn > 0))
> + if ((bus->number == pcie->rp.root_bus_nr) && (devfn > 0))
> return false;
>
> /*
> * Do not read more than one device on the bus directly
> * attached to RC
> */
> - if ((bus->primary == pcie->root_bus_nr) && (PCI_SLOT(devfn) > 0))
> + if ((bus->primary == pcie->rp.root_bus_nr) && (PCI_SLOT(devfn) > 0))
> return false;
>
> return true;
> @@ -310,7 +59,7 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
> return NULL;
>
> /* RC config access */
> - if (bus->number == pcie->root_bus_nr)
> + if (bus->number == pcie->rp.root_bus_nr)
> return pcie->csr_axi_slave_base + where;
>
> /*
> @@ -325,7 +74,7 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
>
> csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
>
> - return pcie->config_axi_slave_base + where;
> + return pcie->rp.config_axi_slave_base + where;
> }
>
> static struct pci_ops mobiveil_pcie_ops = {
> @@ -339,7 +88,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
> struct irq_chip *chip = irq_desc_get_chip(desc);
> struct mobiveil_pcie *pcie = irq_desc_get_handler_data(desc);
> struct device *dev = &pcie->pdev->dev;
> - struct mobiveil_msi *msi = &pcie->msi;
> + struct mobiveil_msi *msi = &pcie->rp.msi;
> u32 msi_data, msi_addr_lo, msi_addr_hi;
> u32 intr_status, msi_status;
> unsigned long shifted_status;
> @@ -364,7 +113,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
> shifted_status >>= PAB_INTX_START;
> do {
> for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
> - virq = irq_find_mapping(pcie->intx_domain,
> + virq = irq_find_mapping(pcie->rp.intx_domain,
> bit + 1);
> if (virq)
> generic_handle_irq(virq);
> @@ -427,10 +176,10 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
> /* map config resource */
> res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> "config_axi_slave");
> - pcie->config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
> - if (IS_ERR(pcie->config_axi_slave_base))
> - return PTR_ERR(pcie->config_axi_slave_base);
> - pcie->ob_io_res = res;
> + pcie->rp.config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
> + if (IS_ERR(pcie->rp.config_axi_slave_base))
> + return PTR_ERR(pcie->rp.config_axi_slave_base);
> + pcie->rp.ob_io_res = res;
>
The splitting up of this file into multiple file looks broadly consistent with
'dwc' - however it is tricky to review as in addition to moving code, we're also
changing it. For example you introduce the concept of a root_port along with
(mobiveil_rp_ops and mobiveil_pab_ops) - this changes the code that you are
moving. There are also differences with interrupt handling.
It would be helpful to split this up.
Thanks,
Andrew Murray
> /* map csr resource */
> res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> @@ -440,12 +189,6 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
> return PTR_ERR(pcie->csr_axi_slave_base);
> pcie->pcie_reg_base = res->start;
>
> - /* map MSI config resource */
> - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb_csr");
> - pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
> - if (IS_ERR(pcie->apb_csr_base))
> - return PTR_ERR(pcie->apb_csr_base);
> -
> /* read the number of windows requested */
> if (of_property_read_u32(node, "apio-wins", &pcie->apio_wins))
> pcie->apio_wins = MAX_PIO_WINDOWS;
> @@ -453,116 +196,15 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
> if (of_property_read_u32(node, "ppio-wins", &pcie->ppio_wins))
> pcie->ppio_wins = MAX_PIO_WINDOWS;
>
> - pcie->irq = platform_get_irq(pdev, 0);
> - if (pcie->irq <= 0) {
> - dev_err(dev, "failed to map IRQ: %d\n", pcie->irq);
> - return -ENODEV;
> - }
> -
> return 0;
> }
>
> -static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
> - u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
> -{
> - u32 value;
> - u64 size64 = ~(size - 1);
> -
> - if (win_num >= pcie->ppio_wins) {
> - dev_err(&pcie->pdev->dev,
> - "ERROR: max inbound windows reached !\n");
> - return;
> - }
> -
> - value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
> - value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
> - value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
> - (lower_32_bits(size64) & WIN_SIZE_MASK);
> - csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
> -
> - csr_writel(pcie, upper_32_bits(size64),
> - PAB_EXT_PEX_AMAP_SIZEN(win_num));
> -
> - csr_writel(pcie, lower_32_bits(cpu_addr),
> - PAB_PEX_AMAP_AXI_WIN(win_num));
> - csr_writel(pcie, upper_32_bits(cpu_addr),
> - PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
> -
> - csr_writel(pcie, lower_32_bits(pci_addr),
> - PAB_PEX_AMAP_PEX_WIN_L(win_num));
> - csr_writel(pcie, upper_32_bits(pci_addr),
> - PAB_PEX_AMAP_PEX_WIN_H(win_num));
> -
> - pcie->ib_wins_configured++;
> -}
> -
> -/*
> - * routine to program the outbound windows
> - */
> -static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
> - u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
> -{
> - u32 value;
> - u64 size64 = ~(size - 1);
> -
> - if (win_num >= pcie->apio_wins) {
> - dev_err(&pcie->pdev->dev,
> - "ERROR: max outbound windows reached !\n");
> - return;
> - }
> -
> - /*
> - * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
> - * to 4 KB in PAB_AXI_AMAP_CTRL register
> - */
> - value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
> - value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
> - value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
> - (lower_32_bits(size64) & WIN_SIZE_MASK);
> - csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
> -
> - csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
> -
> - /*
> - * program AXI window base with appropriate value in
> - * PAB_AXI_AMAP_AXI_WIN0 register
> - */
> - csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
> - PAB_AXI_AMAP_AXI_WIN(win_num));
> - csr_writel(pcie, upper_32_bits(cpu_addr),
> - PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
> -
> - csr_writel(pcie, lower_32_bits(pci_addr),
> - PAB_AXI_AMAP_PEX_WIN_L(win_num));
> - csr_writel(pcie, upper_32_bits(pci_addr),
> - PAB_AXI_AMAP_PEX_WIN_H(win_num));
> -
> - pcie->ob_wins_configured++;
> -}
> -
> -static int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
> -{
> - int retries;
> -
> - /* check if the link is up or not */
> - for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> - if (mobiveil_pcie_link_up(pcie))
> - return 0;
> -
> - usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
> - }
> -
> - dev_err(&pcie->pdev->dev, "link never came up\n");
> -
> - return -ETIMEDOUT;
> -}
> -
> static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
> {
> phys_addr_t msg_addr = pcie->pcie_reg_base;
> - struct mobiveil_msi *msi = &pcie->msi;
> + struct mobiveil_msi *msi = &pcie->rp.msi;
>
> - pcie->msi.num_of_vectors = PCI_NUM_MSI;
> + msi->num_of_vectors = PCI_NUM_MSI;
> msi->msi_pages_phys = (phys_addr_t)msg_addr;
>
> writel_relaxed(lower_32_bits(msg_addr),
> @@ -600,9 +242,6 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
> pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
> csr_writel(pcie, pab_ctrl, PAB_CTRL);
>
> - csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
> - PAB_INTP_AMBA_MISC_ENB);
> -
> /*
> * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
> * PAB_AXI_PIO_CTRL Register
> @@ -624,20 +263,24 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
> */
>
> /* config outbound translation window */
> - program_ob_windows(pcie, WIN_NUM_0, pcie->ob_io_res->start, 0,
> - CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));
> + program_ob_windows(pcie, WIN_NUM_0, pcie->rp.ob_io_res->start, 0,
> + CFG_WINDOW_TYPE, resource_size(pcie->rp.ob_io_res));
>
> /* memory inbound translation window */
> program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
>
> /* Get the I/O and memory ranges from DT */
> resource_list_for_each_entry(win, &pcie->resources) {
> - if (resource_type(win->res) == IORESOURCE_MEM)
> + if (resource_type(win->res) == IORESOURCE_MEM) {
> type = MEM_WINDOW_TYPE;
> - else if (resource_type(win->res) == IORESOURCE_IO)
> + } else if (resource_type(win->res) == IORESOURCE_IO) {
> type = IO_WINDOW_TYPE;
> - else
> + } else if (resource_type(win->res) == IORESOURCE_BUS) {
> + pcie->rp.root_bus_nr = win->res->start;
> continue;
> + } else {
> + continue;
> + }
>
> /* configure outbound translation window */
> program_ob_windows(pcie, pcie->ob_wins_configured,
> @@ -652,9 +295,6 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
> value |= (PCI_CLASS_BRIDGE_PCI << 16);
> csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
>
> - /* setup MSI hardware registers */
> - mobiveil_pcie_enable_msi(pcie);
> -
> return 0;
> }
>
> @@ -667,11 +307,11 @@ static void mobiveil_mask_intx_irq(struct irq_data *data)
>
> pcie = irq_desc_get_chip_data(desc);
> mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
> - raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
> + raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags);
> shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
> shifted_val &= ~mask;
> csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
> - raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
> + raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags);
> }
>
> static void mobiveil_unmask_intx_irq(struct irq_data *data)
> @@ -683,11 +323,11 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data)
>
> pcie = irq_desc_get_chip_data(desc);
> mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
> - raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
> + raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags);
> shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
> shifted_val |= mask;
> csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
> - raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
> + raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags);
> }
>
> static struct irq_chip intx_irq_chip = {
> @@ -755,7 +395,7 @@ static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
> unsigned int nr_irqs, void *args)
> {
> struct mobiveil_pcie *pcie = domain->host_data;
> - struct mobiveil_msi *msi = &pcie->msi;
> + struct mobiveil_msi *msi = &pcie->rp.msi;
> unsigned long bit;
>
> WARN_ON(nr_irqs != 1);
> @@ -782,7 +422,7 @@ static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
> {
> struct irq_data *d = irq_domain_get_irq_data(domain, virq);
> struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
> - struct mobiveil_msi *msi = &pcie->msi;
> + struct mobiveil_msi *msi = &pcie->rp.msi;
>
> mutex_lock(&msi->lock);
>
> @@ -803,9 +443,9 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
> {
> struct device *dev = &pcie->pdev->dev;
> struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
> - struct mobiveil_msi *msi = &pcie->msi;
> + struct mobiveil_msi *msi = &pcie->rp.msi;
>
> - mutex_init(&pcie->msi.lock);
> + mutex_init(&msi->lock);
> msi->dev_domain = irq_domain_add_linear(NULL, msi->num_of_vectors,
> &msi_domain_ops, pcie);
> if (!msi->dev_domain) {
> @@ -832,15 +472,15 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
> int ret;
>
> /* setup INTx */
> - pcie->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
> - &intx_domain_ops, pcie);
> + pcie->rp.intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
> + &intx_domain_ops, pcie);
>
> - if (!pcie->intx_domain) {
> + if (!pcie->rp.intx_domain) {
> dev_err(dev, "Failed to get a INTx IRQ domain\n");
> return -ENOMEM;
> }
>
> - raw_spin_lock_init(&pcie->intx_mask_lock);
> + raw_spin_lock_init(&pcie->rp.intx_mask_lock);
>
> /* setup MSI */
> ret = mobiveil_allocate_msi_domains(pcie);
> @@ -850,24 +490,58 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
> return 0;
> }
>
> -static int mobiveil_pcie_probe(struct platform_device *pdev)
> +static int mobiveil_pcie_interrupt_init(struct mobiveil_pcie *pcie)
> +{
> + struct device *dev = &pcie->pdev->dev;
> + struct resource *res;
> + int ret;
> +
> + if (pcie->rp.ops->interrupt_init)
> + return pcie->rp.ops->interrupt_init(pcie);
> +
> + /* map MSI config resource */
> + res = platform_get_resource_byname(pcie->pdev, IORESOURCE_MEM,
> + "apb_csr");
> + pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
> + if (IS_ERR(pcie->apb_csr_base))
> + return PTR_ERR(pcie->apb_csr_base);
> +
> + /* setup MSI hardware registers */
> + mobiveil_pcie_enable_msi(pcie);
> +
> + pcie->rp.irq = platform_get_irq(pcie->pdev, 0);
> + if (pcie->rp.irq <= 0) {
> + dev_err(dev, "failed to map IRQ: %d\n", pcie->rp.irq);
> + return -ENODEV;
> + }
> +
> + /* initialize the IRQ domains */
> + ret = mobiveil_pcie_init_irq_domain(pcie);
> + if (ret) {
> + dev_err(dev, "Failed creating IRQ Domain\n");
> + return ret;
> + }
> +
> + irq_set_chained_handler_and_data(pcie->rp.irq,
> + mobiveil_pcie_isr, pcie);
> +
> + /* Enable interrupts */
> + csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
> + PAB_INTP_AMBA_MISC_ENB);
> +
> + return 0;
> +}
> +
> +int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
> {
> - struct mobiveil_pcie *pcie;
> struct pci_bus *bus;
> struct pci_bus *child;
> - struct pci_host_bridge *bridge;
> - struct device *dev = &pdev->dev;
> + struct pci_host_bridge *bridge = pcie->bridge;
> + struct device *dev = &pcie->pdev->dev;
> resource_size_t iobase;
> int ret;
>
> - /* allocate the PCIe port */
> - bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
> - if (!bridge)
> - return -ENOMEM;
> -
> - pcie = pci_host_bridge_priv(bridge);
> -
> - pcie->pdev = pdev;
> + INIT_LIST_HEAD(&pcie->resources);
>
> ret = mobiveil_pcie_parse_dt(pcie);
> if (ret) {
> @@ -875,8 +549,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> return ret;
> }
>
> - INIT_LIST_HEAD(&pcie->resources);
> -
> /* parse the host bridge base addresses from the device tree file */
> ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
> &pcie->resources, &iobase);
> @@ -895,15 +567,12 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> goto error;
> }
>
> - /* initialize the IRQ domains */
> - ret = mobiveil_pcie_init_irq_domain(pcie);
> + ret = mobiveil_pcie_interrupt_init(pcie);
> if (ret) {
> - dev_err(dev, "Failed creating IRQ Domain\n");
> + dev_err(dev, "Interrupt init failed\n");
> goto error;
> }
>
> - irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
> -
> ret = devm_request_pci_bus_resources(dev, &pcie->resources);
> if (ret)
> goto error;
> @@ -912,7 +581,7 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> list_splice_init(&pcie->resources, &bridge->windows);
> bridge->dev.parent = dev;
> bridge->sysdata = pcie;
> - bridge->busnr = pcie->root_bus_nr;
> + bridge->busnr = pcie->rp.root_bus_nr;
> bridge->ops = &mobiveil_pcie_ops;
> bridge->map_irq = of_irq_parse_and_map_pci;
> bridge->swizzle_irq = pci_common_swizzle;
> @@ -940,25 +609,3 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> pci_free_resource_list(&pcie->resources);
> return ret;
> }
> -
> -static const struct of_device_id mobiveil_pcie_of_match[] = {
> - {.compatible = "mbvl,gpex40-pcie",},
> - {},
> -};
> -
> -MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
> -
> -static struct platform_driver mobiveil_pcie_driver = {
> - .probe = mobiveil_pcie_probe,
> - .driver = {
> - .name = "mobiveil-pcie",
> - .of_match_table = mobiveil_pcie_of_match,
> - .suppress_bind_attrs = true,
> - },
> -};
> -
> -builtin_platform_driver(mobiveil_pcie_driver);
> -
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
> -MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
> diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
> new file mode 100644
> index 000000000000..9c62fc58530c
> --- /dev/null
> +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
> @@ -0,0 +1,59 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCIe host controller driver for Mobiveil PCIe Host controller
> + *
> + * Copyright (c) 2018 Mobiveil Inc.
> + * Copyright 2019 NXP
> + *
> + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_pci.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include "pcie-mobiveil.h"
> +
> +static int mobiveil_pcie_probe(struct platform_device *pdev)
> +{
> + struct mobiveil_pcie *pcie;
> + struct pci_host_bridge *bridge;
> + struct device *dev = &pdev->dev;
> +
> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
> + if (!bridge)
> + return -ENOMEM;
> +
> + pcie = pci_host_bridge_priv(bridge);
> +
> + pcie->pdev = pdev;
> +
> + return mobiveil_pcie_host_probe(pcie);
> +}
> +
> +static const struct of_device_id mobiveil_pcie_of_match[] = {
> + {.compatible = "mbvl,gpex40-pcie",},
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
> +
> +static struct platform_driver mobiveil_pcie_driver = {
> + .probe = mobiveil_pcie_probe,
> + .driver = {
> + .name = "mobiveil-pcie",
> + .of_match_table = mobiveil_pcie_of_match,
> + .suppress_bind_attrs = true,
> + },
> +};
> +
> +builtin_platform_driver(mobiveil_pcie_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
> +MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
> diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.c b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
> new file mode 100644
> index 000000000000..94b23be1a06f
> --- /dev/null
> +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
> @@ -0,0 +1,227 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCIe host controller driver for Mobiveil PCIe Host controller
> + *
> + * Copyright (c) 2018 Mobiveil Inc.
> + * Copyright 2019 NXP
> + *
> + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +
> +#include "pcie-mobiveil.h"
> +
> +/*
> + * mobiveil_pcie_sel_page - routine to access paged register
> + *
> + * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
> + * for this scheme to work extracted higher 6 bits of the offset will be
> + * written to pg_sel field of PAB_CTRL register and rest of the lower 10
> + * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
> + */
> +static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
> +{
> + u32 val;
> +
> + val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
> + val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
> + val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
> +
> + writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
> +}
> +
> +static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
> +{
> + if (off < PAGED_ADDR_BNDRY) {
> + /* For directly accessed registers, clear the pg_sel field */
> + mobiveil_pcie_sel_page(pcie, 0);
> + return pcie->csr_axi_slave_base + off;
> + }
> +
> + mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
> + return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
> +}
> +
> +static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
> +{
> + if ((uintptr_t)addr & (size - 1)) {
> + *val = 0;
> + return PCIBIOS_BAD_REGISTER_NUMBER;
> + }
> +
> + switch (size) {
> + case 4:
> + *val = readl(addr);
> + break;
> + case 2:
> + *val = readw(addr);
> + break;
> + case 1:
> + *val = readb(addr);
> + break;
> + default:
> + *val = 0;
> + return PCIBIOS_BAD_REGISTER_NUMBER;
> + }
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
> +{
> + if ((uintptr_t)addr & (size - 1))
> + return PCIBIOS_BAD_REGISTER_NUMBER;
> +
> + switch (size) {
> + case 4:
> + writel(val, addr);
> + break;
> + case 2:
> + writew(val, addr);
> + break;
> + case 1:
> + writeb(val, addr);
> + break;
> + default:
> + return PCIBIOS_BAD_REGISTER_NUMBER;
> + }
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
> +{
> + void *addr;
> + u32 val;
> + int ret;
> +
> + addr = mobiveil_pcie_comp_addr(pcie, off);
> +
> + ret = mobiveil_pcie_read(addr, size, &val);
> + if (ret)
> + dev_err(&pcie->pdev->dev, "read CSR address failed\n");
> +
> + return val;
> +}
> +
> +void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
> +{
> + void *addr;
> + int ret;
> +
> + addr = mobiveil_pcie_comp_addr(pcie, off);
> +
> + ret = mobiveil_pcie_write(addr, size, val);
> + if (ret)
> + dev_err(&pcie->pdev->dev, "write CSR address failed\n");
> +}
> +
> +bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
> +{
> + if (pcie->ops->link_up)
> + return pcie->ops->link_up(pcie);
> +
> + return (csr_readl(pcie, LTSSM_STATUS) &
> + LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
> +}
> +
> +void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> + u64 pci_addr, u32 type, u64 size)
> +{
> + u32 value;
> + u64 size64 = ~(size - 1);
> +
> + if (win_num >= pcie->ppio_wins) {
> + dev_err(&pcie->pdev->dev,
> + "ERROR: max inbound windows reached !\n");
> + return;
> + }
> +
> + value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
> + value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
> + value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
> + (lower_32_bits(size64) & WIN_SIZE_MASK);
> + csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
> +
> + csr_writel(pcie, upper_32_bits(size64),
> + PAB_EXT_PEX_AMAP_SIZEN(win_num));
> +
> + csr_writel(pcie, lower_32_bits(cpu_addr),
> + PAB_PEX_AMAP_AXI_WIN(win_num));
> + csr_writel(pcie, upper_32_bits(cpu_addr),
> + PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
> +
> + csr_writel(pcie, lower_32_bits(pci_addr),
> + PAB_PEX_AMAP_PEX_WIN_L(win_num));
> + csr_writel(pcie, upper_32_bits(pci_addr),
> + PAB_PEX_AMAP_PEX_WIN_H(win_num));
> +
> + pcie->ib_wins_configured++;
> +}
> +
> +/*
> + * routine to program the outbound windows
> + */
> +void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> + u64 pci_addr, u32 type, u64 size)
> +{
> + u32 value;
> + u64 size64 = ~(size - 1);
> +
> + if (win_num >= pcie->apio_wins) {
> + dev_err(&pcie->pdev->dev,
> + "ERROR: max outbound windows reached !\n");
> + return;
> + }
> +
> + /*
> + * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
> + * to 4 KB in PAB_AXI_AMAP_CTRL register
> + */
> + value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
> + value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
> + value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
> + (lower_32_bits(size64) & WIN_SIZE_MASK);
> + csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
> +
> + csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
> +
> + /*
> + * program AXI window base with appropriate value in
> + * PAB_AXI_AMAP_AXI_WIN0 register
> + */
> + csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
> + PAB_AXI_AMAP_AXI_WIN(win_num));
> + csr_writel(pcie, upper_32_bits(cpu_addr),
> + PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
> +
> + csr_writel(pcie, lower_32_bits(pci_addr),
> + PAB_AXI_AMAP_PEX_WIN_L(win_num));
> + csr_writel(pcie, upper_32_bits(pci_addr),
> + PAB_AXI_AMAP_PEX_WIN_H(win_num));
> +
> + pcie->ob_wins_configured++;
> +}
> +
> +int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
> +{
> + int retries;
> +
> + /* check if the link is up or not */
> + for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> + if (mobiveil_pcie_link_up(pcie))
> + return 0;
> +
> + usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
> + }
> +
> + dev_err(&pcie->pdev->dev, "link never came up\n");
> +
> + return -ETIMEDOUT;
> +}
> diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
> new file mode 100644
> index 000000000000..4825e30030cd
> --- /dev/null
> +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
> @@ -0,0 +1,189 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * PCIe host controller driver for Mobiveil PCIe Host controller
> + *
> + * Copyright (c) 2018 Mobiveil Inc.
> + * Copyright 2019 NXP
> + *
> + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> + */
> +
> +#ifndef _PCIE_MOBIVEIL_H
> +#define _PCIE_MOBIVEIL_H
> +
> +#include <linux/pci.h>
> +#include <linux/irq.h>
> +#include <linux/msi.h>
> +#include "../../pci.h"
> +
> +/* register offsets and bit positions */
> +
> +/*
> + * translation tables are grouped into windows, each window registers are
> + * grouped into blocks of 4 or 16 registers each
> + */
> +#define PAB_REG_BLOCK_SIZE 16
> +#define PAB_EXT_REG_BLOCK_SIZE 4
> +
> +#define PAB_REG_ADDR(offset, win) \
> + (offset + (win * PAB_REG_BLOCK_SIZE))
> +#define PAB_EXT_REG_ADDR(offset, win) \
> + (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
> +
> +#define LTSSM_STATUS 0x0404
> +#define LTSSM_STATUS_L0_MASK 0x3f
> +#define LTSSM_STATUS_L0 0x2d
> +
> +#define PAB_CTRL 0x0808
> +#define AMBA_PIO_ENABLE_SHIFT 0
> +#define PEX_PIO_ENABLE_SHIFT 1
> +#define PAGE_SEL_SHIFT 13
> +#define PAGE_SEL_MASK 0x3f
> +#define PAGE_LO_MASK 0x3ff
> +#define PAGE_SEL_OFFSET_SHIFT 10
> +
> +#define PAB_AXI_PIO_CTRL 0x0840
> +#define APIO_EN_MASK 0xf
> +
> +#define PAB_PEX_PIO_CTRL 0x08c0
> +#define PIO_ENABLE_SHIFT 0
> +
> +#define PAB_INTP_AMBA_MISC_ENB 0x0b0c
> +#define PAB_INTP_AMBA_MISC_STAT 0x0b1c
> +#define PAB_INTP_INTX_MASK 0x01e0
> +#define PAB_INTP_MSI_MASK 0x8
> +
> +#define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win)
> +#define WIN_ENABLE_SHIFT 0
> +#define WIN_TYPE_SHIFT 1
> +#define WIN_TYPE_MASK 0x3
> +#define WIN_SIZE_MASK 0xfffffc00
> +
> +#define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win)
> +
> +#define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
> +#define PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win)
> +#define AXI_WINDOW_ALIGN_MASK 3
> +
> +#define PAB_AXI_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x0ba8, win)
> +#define PAB_BUS_SHIFT 24
> +#define PAB_DEVICE_SHIFT 19
> +#define PAB_FUNCTION_SHIFT 16
> +
> +#define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win)
> +#define PAB_INTP_AXI_PIO_CLASS 0x474
> +
> +#define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win)
> +#define AMAP_CTRL_EN_SHIFT 0
> +#define AMAP_CTRL_TYPE_SHIFT 1
> +#define AMAP_CTRL_TYPE_MASK 3
> +
> +#define PAB_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win)
> +#define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win)
> +#define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win)
> +#define PAB_PEX_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x4ba8, win)
> +#define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win)
> +
> +/* starting offset of INTX bits in status register */
> +#define PAB_INTX_START 5
> +
> +/* supported number of MSI interrupts */
> +#define PCI_NUM_MSI 16
> +
> +/* MSI registers */
> +#define MSI_BASE_LO_OFFSET 0x04
> +#define MSI_BASE_HI_OFFSET 0x08
> +#define MSI_SIZE_OFFSET 0x0c
> +#define MSI_ENABLE_OFFSET 0x14
> +#define MSI_STATUS_OFFSET 0x18
> +#define MSI_DATA_OFFSET 0x20
> +#define MSI_ADDR_L_OFFSET 0x24
> +#define MSI_ADDR_H_OFFSET 0x28
> +
> +/* outbound and inbound window definitions */
> +#define WIN_NUM_0 0
> +#define WIN_NUM_1 1
> +#define CFG_WINDOW_TYPE 0
> +#define IO_WINDOW_TYPE 1
> +#define MEM_WINDOW_TYPE 2
> +#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024)
> +#define MAX_PIO_WINDOWS 8
> +
> +/* Parameters for the waiting for link up routine */
> +#define LINK_WAIT_MAX_RETRIES 10
> +#define LINK_WAIT_MIN 90000
> +#define LINK_WAIT_MAX 100000
> +
> +#define PAGED_ADDR_BNDRY 0xc00
> +#define OFFSET_TO_PAGE_ADDR(off) \
> + ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
> +#define OFFSET_TO_PAGE_IDX(off) \
> + ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
> +
> +struct mobiveil_pcie;
> +
> +struct mobiveil_msi { /* MSI information */
> + struct mutex lock; /* protect bitmap variable */
> + struct irq_domain *msi_domain;
> + struct irq_domain *dev_domain;
> + phys_addr_t msi_pages_phys;
> + int num_of_vectors;
> + DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
> +};
> +
> +struct mobiveil_rp_ops {
> + int (*interrupt_init)(struct mobiveil_pcie *pcie);
> +};
> +
> +struct root_port {
> + u8 root_bus_nr;
> + void __iomem *config_axi_slave_base; /* endpoint config base */
> + struct resource *ob_io_res;
> + struct mobiveil_rp_ops *ops;
> + int irq;
> + raw_spinlock_t intx_mask_lock;
> + struct irq_domain *intx_domain;
> + struct mobiveil_msi msi;
> +};
> +
> +struct mobiveil_pab_ops {
> + int (*link_up)(struct mobiveil_pcie *pcie);
> +};
> +
> +struct mobiveil_pcie {
> + struct platform_device *pdev;
> + struct list_head resources;
> + void __iomem *csr_axi_slave_base; /* PAB registers base */
> + phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base */
> + void __iomem *apb_csr_base; /* MSI register base */
> + u32 apio_wins;
> + u32 ppio_wins;
> + u32 ob_wins_configured; /* configured outbound windows */
> + u32 ib_wins_configured; /* configured inbound windows */
> + const struct mobiveil_pab_ops *ops;
> + struct root_port rp;
> + struct pci_host_bridge *bridge;
> +};
> +
> +int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
> +bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
> +int mobiveil_bringup_link(struct mobiveil_pcie *pcie);
> +void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> + u64 pci_addr, u32 type, u64 size);
> +void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> + u64 pci_addr, u32 type, u64 size);
> +u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size);
> +void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size);
> +
> +static inline u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
> +{
> + return csr_read(pcie, off, 0x4);
> +}
> +
> +static inline void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
> +{
> + csr_write(pcie, val, off, 0x4);
> +}
> +
> +#endif /* _PCIE_MOBIVEIL_H */
> --
> 2.17.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v1 2/2] of: Let of_for_each_phandle fallback to non-negative cell_count
From: Peter Rosin @ 2019-09-17 11:25 UTC (permalink / raw)
To: Uwe Kleine-König, Geert Uytterhoeven
Cc: Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Frank Rowand, Joerg Roedel, Linux Kernel Mailing List,
Linux-Renesas, Wolfram Sang, Linux IOMMU,
linux-mediatek@lists.infradead.org, Linux I2C, Sascha Hauer,
Matthias Brugger, Will Deacon, Linux ARM, Robin Murphy
In-Reply-To: <20190917101303.t5otztdus7y3ayau@pengutronix.de>
On 2019-09-17 12:13, Uwe Kleine-König wrote:
> Hello Geert,
>
> On Tue, Sep 17, 2019 at 11:40:25AM +0200, Geert Uytterhoeven wrote:
>> Hi Rob, Uwe,
>>
>> On Fri, Sep 13, 2019 at 11:58 PM Rob Herring <robh@kernel.org> wrote:
>>> On Sat, 24 Aug 2019 15:28:46 +0200, =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= wrote:
>>>> Referencing device tree nodes from a property allows to pass arguments.
>>>> This is for example used for referencing gpios. This looks as follows:
>>>>
>>>> gpio_ctrl: gpio-controller {
>>>> #gpio-cells = <2>
>>>> ...
>>>> }
>>>>
>>>> someothernode {
>>>> gpios = <&gpio_ctrl 5 0 &gpio_ctrl 3 0>;
>>>> ...
>>>> }
>>>>
>>>> To know the number of arguments this must be either fixed, or the
>>>> referenced node is checked for a $cells_name (here: "#gpio-cells")
>>>> property and with this information the start of the second reference can
>>>> be determined.
>>>>
>>>> Currently regulators are referenced with no additional arguments. To
>>>> allow some optional arguments without having to change all referenced
>>>> nodes this change introduces a way to specify a default cell_count. So
>>>> when a phandle is parsed we check for the $cells_name property and use
>>>> it as before if present. If it is not present we fall back to
>>>> cells_count if non-negative and only fail if cells_count is smaller than
>>>> zero.
>>>>
>>>> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
>>
>> This is now commit e42ee61017f58cd9 ("of: Let of_for_each_phandle fallback
>> to non-negative cell_count") in robh/for-next, which causes a lock-up when
>> booting a shmobile_defconfig kernel on r8a7791/koelsch:
>>
>> rcu: INFO: rcu_sched self-detected stall on CPU
>> rcu: 0-....: (2099 ticks this GP) idle=6fe/1/0x40000002
>> softirq=29/29 fqs=1050
>> (t=2100 jiffies g=-1131 q=0)
>> NMI backtrace for cpu 0
>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>> 5.3.0-rc2-shmobile-00050-ge42ee61017f58cd9 #376
>> Hardware name: Generic R-Car Gen2 (Flattened Device Tree)
>> [<c010f8ac>] (unwind_backtrace) from [<c010b620>] (show_stack+0x10/0x14)
>> [<c010b620>] (show_stack) from [<c073d038>] (dump_stack+0x7c/0x9c)
>> [<c073d038>] (dump_stack) from [<c0742e80>] (nmi_cpu_backtrace+0xa0/0xb8)
>> [<c0742e80>] (nmi_cpu_backtrace) from [<c0742f1c>] (nmi_trigger_cpumask_backtrace+0x84/0x114)
>> [<c0742f1c>] (nmi_trigger_cpumask_backtrace) from [<c017d684>] (rcu_dump_cpu_stacks+0xac/0xc8)
>> [<c017d684>] (rcu_dump_cpu_stacks) from [<c017a598>] (rcu_sched_clock_irq+0x2ac/0x6b4)
>> [<c017a598>] (rcu_sched_clock_irq) from [<c0183980>] (update_process_times+0x30/0x5c)
>> [<c0183980>] (update_process_times) from [<c01941a8>] (tick_nohz_handler+0xcc/0x120)
>> [<c01941a8>] (tick_nohz_handler) from [<c05b1d40>] (arch_timer_handler_virt+0x28/0x30)
>> [<c05b1d40>] (arch_timer_handler_virt) from [<c016c9e0>] (handle_percpu_devid_irq+0xe8/0x21c)
>> [<c016c9e0>] (handle_percpu_devid_irq) from [<c0167a8c>] (generic_handle_irq+0x18/0x28)
>> [<c0167a8c>] (generic_handle_irq) from [<c0167b3c>] (__handle_domain_irq+0xa0/0xb4)
>> [<c0167b3c>] (__handle_domain_irq) from [<c03673ec>] (gic_handle_irq+0x58/0x90)
>> [<c03673ec>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
>> Exception stack(0xeb08dd30 to 0xeb08dd78)
>> dd20: c0cc7514 20000013 00000005 00003b27
>> dd40: eb7c4020 c0cc750c 00000051 00000051 20000013 c0c66b08 eb1cdc00 00000018
>> dd60: 00000000 eb08dd80 c05c1a38 c0756c00 20000013 ffffffff
>> [<c0101a8c>] (__irq_svc) from [<c0756c00>] (_raw_spin_unlock_irqrestore+0x1c/0x20)
>> [<c0756c00>] (_raw_spin_unlock_irqrestore) from [<c05c1a38>] (of_find_node_by_phandle+0xcc/0xf0)
>> [<c05c1a38>] (of_find_node_by_phandle) from [<c05c1bb8>] (of_phandle_iterator_next+0x68/0x178)
>> [<c05c1bb8>] (of_phandle_iterator_next) from [<c05c22bc>] (of_count_phandle_with_args+0x5c/0x7c)
>> [<c05c22bc>] (of_count_phandle_with_args) from [<c053fc38>] (i2c_demux_pinctrl_probe+0x24/0x1fc)
>> [<c053fc38>] (i2c_demux_pinctrl_probe) from [<c04463c4>] (platform_drv_probe+0x48/0x94)
>> [<c04463c4>] (platform_drv_probe) from [<c0444a20>] (really_probe+0x1f0/0x2b8)
>> [<c0444a20>] (really_probe) from [<c0444e68>] (driver_probe_device+0x140/0x158)
>> [<c0444e68>] (driver_probe_device) from [<c0444ff0>] (device_driver_attach+0x44/0x5c)
>> [<c0444ff0>] (device_driver_attach) from [<c04450b4>] (__driver_attach+0xac/0xb4)
>> [<c04450b4>] (__driver_attach) from [<c0443178>] (bus_for_each_dev+0x64/0xa0)
>> [<c0443178>] (bus_for_each_dev) from [<c04438a8>] (bus_add_driver+0x148/0x1a8)
>> [<c04438a8>] (bus_add_driver) from [<c0445ad0>] (driver_register+0xac/0xf0)
>> [<c0445ad0>] (driver_register) from [<c0b010b0>] (do_one_initcall+0xa8/0x1d4)
>> [<c0b010b0>] (do_one_initcall) from [<c0b01448>] (kernel_init_freeable+0x26c/0x2c8)
>> [<c0b01448>] (kernel_init_freeable) from [<c0751c70>] (kernel_init+0x8/0x10c)
>> [<c0751c70>] (kernel_init) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
>> Exception stack(0xeb08dfb0 to 0xeb08dff8)
>> dfa0: 00000000 00000000 00000000 00000000
>> dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
>> dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
>>
>> Presumably it loops forever, due to a conversion of -1 to unsigned
>> somewhere?
>
> Hmm, I fail to see the culprit. i2c_demux_pinctrl_probe calls
> of_count_phandle_with_args with cells_name=NULL. With that I don't see
> how my patch changes anything as the only change is in an if
> (it->cells_name) block that shouldn't be relevant in your case.
>
> Can you please verify that the loop in of_count_phandle_with_args is
> indeed not terminating, e.g. with
The below indicated else-branch was not touched by e42ee61017f58cd9,
which ends up setting the count to -1 (aka 0xff...ff in this case).
No?
int of_phandle_iterator_next(struct of_phandle_iterator *it)
{
...
if (it->cells_name) {
...
} else {
count = it->cell_count; /* <---- SUSPECT!!! */
}
...
}
...
}
Cheers,
Peter
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 6/6] kvm: add kvm ptp capability extension for arm64
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190917112430.45680-1-jianyong.wu@arm.com>
Let userspace check if there is kvm ptp service in host.
before VMs migrate to a another host, VMM may check if this
cap is available to determine the migration behaviour.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
Suggested-by: Marc Zyngier <maz@kernel.org>
---
include/uapi/linux/kvm.h | 1 +
virt/kvm/arm/arm.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 2fe12b40d503..a0bff6002bd9 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -993,6 +993,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_SVE 170
#define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
#define KVM_CAP_ARM_PTRAUTH_GENERIC 172
+#define KVM_CAP_ARM_KVM_PTP 173
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index bd5c55916d0d..80999985160b 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -201,6 +201,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_MP_STATE:
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_VCPU_EVENTS:
+ case KVM_CAP_ARM_KVM_PTP:
r = 1;
break;
case KVM_CAP_ARM_SET_DEVICE_ADDR:
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH V2 5/6] Enable ptp_kvm for arm64
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190917112430.45680-1-jianyong.wu@arm.com>
Currently in arm64 virtualization environment, there is no mechanism to
keep time sync between guest and host. Time in guest will drift compared
with host after boot up as they may both use third party time sources
to correct their time respectively. The time deviation will be in order
of milliseconds but some scenarios ask for higher time precision, like
in cloud envirenment, we want all the VMs running in the host aquire the
same level accuracy from host clock.
Use of kvm ptp clock, which choose the host clock source clock as a
reference clock to sync time clock between guest and host has been adopted
by x86 which makes the time sync order from milliseconds to nanoseconds.
This patch enable kvm ptp on arm64 and we get the similar clock drift as
found with x86 with kvm ptp.
Test result comparison between with kvm ptp and without it in arm64 are
as follows. This test derived from the result of command 'chronyc
sources'. we should take more cure of the last sample column which shows
the offset between the local clock and the source at the last measurement.
no kvm ptp in guest:
MS Name/IP address Stratum Poll Reach LastRx Last sample
========================================================================
^* dns1.synet.edu.cn 2 6 377 13 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 21 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 29 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 37 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 45 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 53 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 61 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 4 -130us[ +796us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 12 -130us[ +796us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 20 -130us[ +796us] +/- 21ms
in host:
MS Name/IP address Stratum Poll Reach LastRx Last sample
========================================================================
^* 120.25.115.20 2 7 377 72 -470us[ -603us] +/- 18ms
^* 120.25.115.20 2 7 377 92 -470us[ -603us] +/- 18ms
^* 120.25.115.20 2 7 377 112 -470us[ -603us] +/- 18ms
^* 120.25.115.20 2 7 377 2 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 22 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 43 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 63 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 83 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 103 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 123 +872ns[-6808ns] +/- 17ms
The dns1.synet.edu.cn is the network reference clock for guest and
120.25.115.20 is the network reference clock for host. we can't get the
clock error between guest and host directly, but a roughly estimated value
will be in order of hundreds of us to ms.
with kvm ptp in guest:
chrony has been disabled in host to remove the disturb by network clock.
MS Name/IP address Stratum Poll Reach LastRx Last sample
========================================================================
* PHC0 0 3 377 8 -7ns[ +1ns] +/- 3ns
* PHC0 0 3 377 8 +1ns[ +16ns] +/- 3ns
* PHC0 0 3 377 6 -4ns[ -0ns] +/- 6ns
* PHC0 0 3 377 6 -8ns[ -12ns] +/- 5ns
* PHC0 0 3 377 5 +2ns[ +4ns] +/- 4ns
* PHC0 0 3 377 13 +2ns[ +4ns] +/- 4ns
* PHC0 0 3 377 12 -4ns[ -6ns] +/- 4ns
* PHC0 0 3 377 11 -8ns[ -11ns] +/- 6ns
* PHC0 0 3 377 10 -14ns[ -20ns] +/- 4ns
* PHC0 0 3 377 8 +4ns[ +5ns] +/- 4ns
The PHC0 is the ptp clock which choose the host clock as its source
clock. So we can be sure to say that the clock error between host and guest
is in order of ns.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
drivers/ptp/Kconfig | 2 +-
drivers/ptp/kvm_ptp.c | 2 +-
drivers/ptp/ptp_kvm_arm64.c | 82 +++++++++++++++++++++++++++++++++++++
3 files changed, 84 insertions(+), 2 deletions(-)
create mode 100644 drivers/ptp/ptp_kvm_arm64.c
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 9b8fee5178e8..e032fafdafa7 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -110,7 +110,7 @@ config PTP_1588_CLOCK_PCH
config PTP_1588_CLOCK_KVM
tristate "KVM virtual PTP clock"
depends on PTP_1588_CLOCK
- depends on KVM_GUEST && X86
+ depends on KVM_GUEST && X86 || ARM64
default y
help
This driver adds support for using kvm infrastructure as a PTP
diff --git a/drivers/ptp/kvm_ptp.c b/drivers/ptp/kvm_ptp.c
index d8f215186904..c0b445fa6144 100644
--- a/drivers/ptp/kvm_ptp.c
+++ b/drivers/ptp/kvm_ptp.c
@@ -138,7 +138,7 @@ static int __init ptp_kvm_init(void)
int ret;
ret = kvm_arch_ptp_init();
- if (!ret)
+ if (ret)
return -EOPNOTSUPP;
kvm_ptp_clock.caps = ptp_kvm_caps;
diff --git a/drivers/ptp/ptp_kvm_arm64.c b/drivers/ptp/ptp_kvm_arm64.c
new file mode 100644
index 000000000000..630144186c08
--- /dev/null
+++ b/drivers/ptp/ptp_kvm_arm64.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ * Copyright (C) 2019 ARM Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <asm/hypervisor.h>
+#include <linux/module.h>
+#include <linux/psci.h>
+#include <linux/arm-smccc.h>
+#include <linux/timecounter.h>
+#include <linux/sched/clock.h>
+#include <asm/arch_timer.h>
+
+struct system_counterval_t ptp_sc;
+
+/*
+ * as trap call cause delay, this function will return the delay in nanosecond
+ */
+static u64 arm_smccc_1_1_invoke_delay(u32 id, struct arm_smccc_res *res)
+{
+ u64 t1, t2;
+
+ t1 = sched_clock();
+ arm_smccc_1_1_invoke(id, res);
+ t2 = sched_clock();
+ t2 -= t1;
+
+ return t2;
+}
+
+int kvm_arch_ptp_init(void)
+{
+ if (!kvm_arm_hyp_service_available(
+ ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID)) {
+ return -EOPNOTSUPP;
+ }
+ get_current_counterval(&ptp_sc);
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock_generic(struct timespec64 *ts,
+ struct arm_smccc_res *hvc_res)
+{
+ u64 ns;
+
+ ns = arm_smccc_1_1_invoke_delay(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID,
+ hvc_res);
+ if ((long)(hvc_res->a0) < 0)
+ return -EOPNOTSUPP;
+
+ ts->tv_sec = hvc_res->a0;
+ ts->tv_nsec = hvc_res->a1;
+ timespec64_add_ns(ts, ns);
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock(struct timespec64 *ts)
+{
+ struct arm_smccc_res hvc_res;
+
+ kvm_arch_ptp_get_clock_generic(ts, &hvc_res);
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock_fn(long *cycle, struct timespec64 *ts,
+ struct clocksource **cs)
+{
+ struct arm_smccc_res hvc_res;
+
+ kvm_arch_ptp_get_clock_generic(ts, &hvc_res);
+ *cycle = hvc_res.a2;
+ *cs = ptp_sc.cs;
+
+ return 0;
+}
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v2 4/6] arm64: Add hvc call service for ptp_kvm.
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190917112430.45680-1-jianyong.wu@arm.com>
This patch is the base of ptp_kvm for arm64.
ptp_kvm modules will call hvc to get this service.
The service offers real time and counter cycle of host for guest.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
include/linux/arm-smccc.h | 12 ++++++++++++
virt/kvm/arm/psci.c | 17 +++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index a6e4d3e3d10a..bc0cdad10f35 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -94,6 +94,7 @@
/* KVM "vendor specific" services */
#define ARM_SMCCC_KVM_FUNC_FEATURES 0
+#define ARM_SMCCC_KVM_PTP 1
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
#define ARM_SMCCC_KVM_NUM_FUNCS 128
@@ -103,6 +104,17 @@
ARM_SMCCC_OWNER_VENDOR_HYP, \
ARM_SMCCC_KVM_FUNC_FEATURES)
+/*
+ * This ID used for virtual ptp kvm clock and it will pass second value
+ * and nanosecond value of host real time and system counter by vcpu
+ * register to guest.
+ */
+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_VENDOR_HYP, \
+ ARM_SMCCC_KVM_PTP)
+
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 0debf49bf259..2c5d53817a28 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -392,6 +392,8 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
u32 func_id = smccc_get_function(vcpu);
u32 val[4] = {};
u32 option;
+ struct timespec *ts;
+ struct system_counterval_t sc;
val[0] = SMCCC_RET_NOT_SUPPORTED;
@@ -431,6 +433,21 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
break;
+ /*
+ * This will used for virtual ptp kvm clock. three
+ * values will be passed back.
+ * reg0 stores seconds of host real time;
+ * reg1 stores nanoseconds of host real time;
+ * reg2 stores system counter cycle value.
+ */
+ case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+ getnstimeofday(ts);
+ get_current_counterval(&sc);
+ val[0] = ts->tv_sec;
+ val[1] = ts->tv_nsec;
+ val[2] = sc.cycles;
+ val[3] = 0;
+ break;
default:
return kvm_psci_call(vcpu);
}
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 3/6] Timer: expose monotonic clock and counter value
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190917112430.45680-1-jianyong.wu@arm.com>
A number of PTP drivers (such as ptp-kvm) are assuming what the
current clock source is, which could lead to interesting effects on
systems where the clocksource can change depending on external events.
For this purpose, add a new API that retrives both the current
monotonic clock as well as its counter value.
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
include/linux/timekeeping.h | 3 +++
kernel/time/timekeeping.c | 13 +++++++++++++
2 files changed, 16 insertions(+)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index a8ab0f143ac4..a5389adaa8bc 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -247,6 +247,9 @@ extern int get_device_system_crosststamp(
struct system_time_snapshot *history,
struct system_device_crosststamp *xtstamp);
+/* Obtain current monotonic clock and its counter value */
+extern void get_current_counterval(struct system_counterval_t *sc);
+
/*
* Simultaneously snapshot realtime and monotonic raw clocks
*/
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 44b726bab4bd..07a0969625b1 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1098,6 +1098,19 @@ static bool cycle_between(u64 before, u64 test, u64 after)
return false;
}
+/**
+ * get_current_counterval - Snapshot the current clocksource and counter value
+ * @sc: Pointer to a struct containing the current clocksource and its value
+ */
+void get_current_counterval(struct system_counterval_t *sc)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+
+ sc->cs = READ_ONCE(tk->tkr_mono.clock);
+ sc->cycles = sc->cs->read(sc->cs);
+}
+EXPORT_SYMBOL_GPL(get_current_counterval);
+
/**
* get_device_system_crosststamp - Synchronously capture system/device timestamp
* @get_time_fn: Callback to get simultaneous device time and
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v2 2/6] reorganize ptp_kvm modules to make it arch-independent.
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190917112430.45680-1-jianyong.wu@arm.com>
Currently, ptp_kvm modules implementation is only for x86 which includs
large part of arch-specific code. This patch move all of those code
into related arch directory.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
drivers/ptp/Makefile | 1 +
drivers/ptp/{ptp_kvm.c => kvm_ptp.c} | 77 ++++++------------------
drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++++++++++++++++
include/asm-generic/ptp_kvm.h | 12 ++++
4 files changed, 118 insertions(+), 59 deletions(-)
rename drivers/ptp/{ptp_kvm.c => kvm_ptp.c} (63%)
create mode 100644 drivers/ptp/ptp_kvm_x86.c
create mode 100644 include/asm-generic/ptp_kvm.h
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 677d1d178a3e..8f27ba302e31 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -4,6 +4,7 @@
#
ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+ptp_kvm-y := ptp_kvm_$(ARCH).o kvm_ptp.o
obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o
obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o
obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o
diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/kvm_ptp.c
similarity index 63%
rename from drivers/ptp/ptp_kvm.c
rename to drivers/ptp/kvm_ptp.c
index fc7d0b77e118..d8f215186904 100644
--- a/drivers/ptp/ptp_kvm.c
+++ b/drivers/ptp/kvm_ptp.c
@@ -8,12 +8,12 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <uapi/linux/kvm_para.h>
#include <asm/kvm_para.h>
-#include <asm/pvclock.h>
-#include <asm/kvmclock.h>
#include <uapi/asm/kvm_para.h>
+#include <asm-generic/ptp_kvm.h>
#include <linux/ptp_clock_kernel.h>
@@ -24,56 +24,29 @@ struct kvm_ptp_clock {
DEFINE_SPINLOCK(kvm_ptp_lock);
-static struct pvclock_vsyscall_time_info *hv_clock;
-
-static struct kvm_clock_pairing clock_pair;
-static phys_addr_t clock_pair_gpa;
-
static int ptp_kvm_get_time_fn(ktime_t *device_time,
struct system_counterval_t *system_counter,
void *ctx)
{
- unsigned long ret;
+ unsigned long ret, cycle;
struct timespec64 tspec;
- unsigned version;
- int cpu;
- struct pvclock_vcpu_time_info *src;
+ struct clocksource *cs;
spin_lock(&kvm_ptp_lock);
preempt_disable_notrace();
- cpu = smp_processor_id();
- src = &hv_clock[cpu].pvti;
-
- do {
- /*
- * We are using a TSC value read in the hosts
- * kvm_hc_clock_pairing handling.
- * So any changes to tsc_to_system_mul
- * and tsc_shift or any other pvclock
- * data invalidate that measurement.
- */
- version = pvclock_read_begin(src);
-
- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
- clock_pair_gpa,
- KVM_CLOCK_PAIRING_WALLCLOCK);
- if (ret != 0) {
- pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
- spin_unlock(&kvm_ptp_lock);
- preempt_enable_notrace();
- return -EOPNOTSUPP;
- }
-
- tspec.tv_sec = clock_pair.sec;
- tspec.tv_nsec = clock_pair.nsec;
- ret = __pvclock_read_cycles(src, clock_pair.tsc);
- } while (pvclock_read_retry(src, version));
+ ret = kvm_arch_ptp_get_clock_fn(&cycle, &tspec, &cs);
+ if (ret != 0) {
+ pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
+ spin_unlock(&kvm_ptp_lock);
+ preempt_enable_notrace();
+ return -EOPNOTSUPP;
+ }
preempt_enable_notrace();
- system_counter->cycles = ret;
- system_counter->cs = &kvm_clock;
+ system_counter->cycles = cycle;
+ system_counter->cs = cs;
*device_time = timespec64_to_ktime(tspec);
@@ -116,17 +89,13 @@ static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
spin_lock(&kvm_ptp_lock);
- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
- clock_pair_gpa,
- KVM_CLOCK_PAIRING_WALLCLOCK);
+ ret = kvm_arch_ptp_get_clock(&tspec);
if (ret != 0) {
pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
spin_unlock(&kvm_ptp_lock);
return -EOPNOTSUPP;
}
- tspec.tv_sec = clock_pair.sec;
- tspec.tv_nsec = clock_pair.nsec;
spin_unlock(&kvm_ptp_lock);
memcpy(ts, &tspec, sizeof(struct timespec64));
@@ -166,21 +135,11 @@ static void __exit ptp_kvm_exit(void)
static int __init ptp_kvm_init(void)
{
- long ret;
-
- if (!kvm_para_available())
- return -ENODEV;
-
- clock_pair_gpa = slow_virt_to_phys(&clock_pair);
- hv_clock = pvclock_get_pvti_cpu0_va();
+ int ret;
- if (!hv_clock)
- return -ENODEV;
-
- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
- KVM_CLOCK_PAIRING_WALLCLOCK);
- if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
- return -ENODEV;
+ ret = kvm_arch_ptp_init();
+ if (!ret)
+ return -EOPNOTSUPP;
kvm_ptp_clock.caps = ptp_kvm_caps;
diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c
new file mode 100644
index 000000000000..632733989d59
--- /dev/null
+++ b/drivers/ptp/ptp_kvm_x86.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ */
+
+#include <asm/pvclock.h>
+#include <asm/kvmclock.h>
+#include <linux/module.h>
+#include <uapi/asm/kvm_para.h>
+#include <uapi/linux/kvm_para.h>
+#include <linux/ptp_clock_kernel.h>
+
+phys_addr_t clock_pair_gpa;
+struct kvm_clock_pairing clock_pair;
+struct pvclock_vsyscall_time_info *hv_clock;
+
+int kvm_arch_ptp_init(void)
+{
+ int ret;
+
+ if (!kvm_para_available())
+ return -ENODEV;
+
+ clock_pair_gpa = slow_virt_to_phys(&clock_pair);
+ hv_clock = pvclock_get_pvti_cpu0_va();
+ if (!hv_clock)
+ return -ENODEV;
+
+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
+ KVM_CLOCK_PAIRING_WALLCLOCK);
+ if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
+ return -ENODEV;
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock(struct timespec64 *ts)
+{
+ long ret;
+
+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
+ clock_pair_gpa,
+ KVM_CLOCK_PAIRING_WALLCLOCK);
+ if (ret != 0)
+ return -EOPNOTSUPP;
+
+ ts->tv_sec = clock_pair.sec;
+ ts->tv_nsec = clock_pair.nsec;
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock_fn(long *cycle, struct timespec64 *tspec,
+ struct clocksource **cs)
+{
+ unsigned long ret;
+ unsigned int version;
+ int cpu;
+ struct pvclock_vcpu_time_info *src;
+
+ cpu = smp_processor_id();
+ src = &hv_clock[cpu].pvti;
+
+ do {
+ /*
+ * We are using a TSC value read in the hosts
+ * kvm_hc_clock_pairing handling.
+ * So any changes to tsc_to_system_mul
+ * and tsc_shift or any other pvclock
+ * data invalidate that measurement.
+ */
+ version = pvclock_read_begin(src);
+
+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
+ clock_pair_gpa,
+ KVM_CLOCK_PAIRING_WALLCLOCK);
+ tspec->tv_sec = clock_pair.sec;
+ tspec->tv_nsec = clock_pair.nsec;
+ *cycle = __pvclock_read_cycles(src, clock_pair.tsc);
+ } while (pvclock_read_retry(src, version));
+
+ *cs = &kvm_clock;
+
+ return 0;
+}
diff --git a/include/asm-generic/ptp_kvm.h b/include/asm-generic/ptp_kvm.h
new file mode 100644
index 000000000000..208e842bfa64
--- /dev/null
+++ b/include/asm-generic/ptp_kvm.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2019 ARM Ltd.
+ * All Rights Reserved
+ */
+
+int kvm_arch_ptp_init(void);
+int kvm_arch_ptp_get_clock(struct timespec64 *ts);
+int kvm_arch_ptp_get_clock_fn(long *cycle,
+ struct timespec64 *tspec, void *cs);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v2 1/6] Export psci_ops.conduit symbol as modules will use it.
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190917112430.45680-1-jianyong.wu@arm.com>
If arm_smccc_1_1_invoke used in modules, psci_ops.conduit should
be export.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
drivers/firmware/psci/psci.c | 6 ++++++
include/linux/arm-smccc.h | 2 +-
include/linux/psci.h | 1 +
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index f82ccd39a913..35c4eaab1451 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -212,6 +212,12 @@ static unsigned long psci_migrate_info_up_cpu(void)
0, 0, 0);
}
+enum psci_conduit psci_get_conduit(void)
+{
+ return psci_ops.conduit;
+}
+EXPORT_SYMBOL(psci_get_conduit);
+
static void set_conduit(enum psci_conduit conduit)
{
switch (conduit) {
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 552cbd49abe8..a6e4d3e3d10a 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -357,7 +357,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
* The return value also provides the conduit that was used.
*/
#define arm_smccc_1_1_invoke(...) ({ \
- int method = psci_ops.conduit; \
+ int method = psci_get_conduit(); \
switch (method) { \
case PSCI_CONDUIT_HVC: \
arm_smccc_1_1_hvc(__VA_ARGS__); \
diff --git a/include/linux/psci.h b/include/linux/psci.h
index a8a15613c157..e5cedc986049 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -42,6 +42,7 @@ struct psci_operations {
enum smccc_version smccc_version;
};
+extern enum psci_conduit psci_get_conduit(void);
extern struct psci_operations psci_ops;
#if defined(CONFIG_ARM_PSCI_FW)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v2 0/6] Enable ptp_kvm for arm64
From: Jianyong Wu @ 2019-09-17 11:24 UTC (permalink / raw)
To: netdev, pbonzini, sean.j.christopherson, maz, richardcochran,
Mark.Rutland, Will.Deacon, suzuki.poulose
Cc: justin.he, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
kvm ptp targets to provide high precision time sync between guest
and host in virtualization environment. This patch enable kvm ptp
for arm64.
This patch set base on [1][2][3]
change log:
from v1 to v2:
(1) move arch-specific code from arch/ to driver/ptp/
(2) offer mechanism to inform userspace if ptp_kvm service is
available.
(3) separate ptp_kvm code for arm64 into hypervisor part and
guest part.
(4) add API to expose monotonic clock and counter value.
(5) refine code: remove no necessary part and reconsitution.
[1]https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/
commit/?h=kvm/hvc&id=125ea89e4a21e2fc5235410f966a996a1a7148bf
[2]https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/
commit/?h=kvm/hvc&id=464f5a1741e5959c3e4d2be1966ae0093b4dce06
[3]https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/
commit/?h=kvm/hvc&id=6597490e005d0eeca8ed8c1c1d7b4318ee014681
Jianyong Wu (6):
Export psci_ops.conduit symbol as modules will use it.
reorganize ptp_kvm modules to make it arch-independent.
Timer: expose monotonic clock and counter value
arm64: Add hvc call service for ptp_kvm.
Enable ptp_kvm for arm64
kvm: add kvm ptp capability extension for arm64
drivers/firmware/psci/psci.c | 6 ++
drivers/ptp/Kconfig | 2 +-
drivers/ptp/Makefile | 1 +
drivers/ptp/{ptp_kvm.c => kvm_ptp.c} | 77 ++++++------------------
drivers/ptp/ptp_kvm_arm64.c | 82 ++++++++++++++++++++++++++
drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++++++++++++++++
include/asm-generic/ptp_kvm.h | 12 ++++
include/linux/arm-smccc.h | 14 ++++-
include/linux/psci.h | 1 +
include/linux/timekeeping.h | 3 +
include/uapi/linux/kvm.h | 1 +
kernel/time/timekeeping.c | 13 +++++
virt/kvm/arm/arm.c | 1 +
virt/kvm/arm/psci.c | 17 ++++++
14 files changed, 256 insertions(+), 61 deletions(-)
rename drivers/ptp/{ptp_kvm.c => kvm_ptp.c} (63%)
create mode 100644 drivers/ptp/ptp_kvm_arm64.c
create mode 100644 drivers/ptp/ptp_kvm_x86.c
create mode 100644 include/asm-generic/ptp_kvm.h
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [REGRESSION] sdhci no longer detects SD cards on LX2160A
From: Russell King - ARM Linux admin @ 2019-09-17 11:16 UTC (permalink / raw)
To: Adrian Hunter, Will Deacon; +Cc: linux-mmc, Linux ARM
In-Reply-To: <20190917104200.GJ25745@shell.armlinux.org.uk>
On Tue, Sep 17, 2019 at 11:42:00AM +0100, Russell King - ARM Linux admin wrote:
> On Tue, Sep 17, 2019 at 09:19:31AM +0100, Russell King - ARM Linux admin wrote:
> > On Tue, Sep 17, 2019 at 10:06:12AM +0200, Marc Gonzalez wrote:
> > > On 16/09/2019 19:15, Russell King - ARM Linux admin wrote:
> > >
> > > > The platform has an iommu, which is in pass-through mode, via
> > > > arm_smmu.disable_bypass=0.
> > >
> > > Could be 954a03be033c7cef80ddc232e7cbdb17df735663
> > > "iommu/arm-smmu: Break insecure users by disabling bypass by default"
> > >
> > > Although it had already landed in v5.2
> >
> > It is not - and the two lines that you quoted above are sufficient
> > to negate that as a cause. (Please read the help for the option that
> > the commit referrs to.)
> >
> > In fact, with bypass disabled, the SoC fails due to other masters.
> > That's already been discussed privately between myself and Will
> > Deacon.
> >
> > arm_smmu.disable_bypass=0 re-enables bypass mode irrespective of
> > the default setting in the Kconfig.
>
> Adding some further debugging, and fixing the existing ADMA debugging
> shows:
>
> mmc0: ADMA error: 0x02000000
>
> So this is an ADMA error without the transfer having completed.
>
> mmc0: sdhci: Blk size: 0x00000008 | Blk cnt: 0x00000001
>
> The block size is 8, with one block.
>
> mmc0: sdhci: ADMA Err: 0x00000009 | ADMA Ptr: 0x000000236df1d20c
>
> The ADMA error is a descriptor error at address 0x000000236df1d20c.
> The descriptor table contains (including the following entry):
>
> mmc0: sdhci: 236df1d200: DMA 0x000000236d40e980, LEN 0x0008, Attr=0x23
> mmc0: sdhci: 236df1d20c: DMA 0x0000000000000000, LEN 0x0000, Attr=0x00
>
> The descriptor table contains one descriptor of 8 bytes, is marked
> as the last (END bit set) and is at DMA address 0x236df1d200. The
> following descriptor is empty, with VALID=0.
>
> One may be tempted to blame it on the following descriptor, but having
> had another example on eMMC while userspace was booting (rootfs on
> eMMC):
>
> mmc1: ADMA error: 0x02000000
> mmc1: sdhci: Blk size: 0x00000200 | Blk cnt: 0x00000099
> mmc1: sdhci: ADMA Err: 0x00000006 | ADMA Ptr: 0x000000236dbfa26c
> mmc1: sdhci: 236dbfa200: DMA 0x000000236c25c000, LEN 0x2000, Attr=0x21
> mmc1: sdhci: 236dbfa20c: DMA 0x000000236938c000, LEN 0x0000, Attr=0x21
> mmc1: sdhci: 236dbfa218: DMA 0x000000236939c000, LEN 0x5000, Attr=0x21
> mmc1: sdhci: 236dbfa224: DMA 0x0000002368545000, LEN 0x1000, Attr=0x21
> mmc1: sdhci: 236dbfa230: DMA 0x00000023684f1000, LEN 0x1000, Attr=0x21
> mmc1: sdhci: 236dbfa23c: DMA 0x0000002368504000, LEN 0x2000, Attr=0x21
> mmc1: sdhci: 236dbfa248: DMA 0x0000002368546000, LEN 0x2000, Attr=0x21
> mmc1: sdhci: 236dbfa254: DMA 0x00000023684f2000, LEN 0x2000, Attr=0x21
> mmc1: sdhci: 236dbfa260: DMA 0x0000002368500000, LEN 0x1000, Attr=0x23
> mmc1: sdhci: 236dbfa26c: DMA 0x000000236b55d000, LEN 0x1000, Attr=0x21
>
> ... which is interesting for several reasons:
> - The ADMA error register indicates a length mismatch error. The
> transfer was for 0x99 blocks of 0x200, which is 0x13200 bytes.
> Summing the ADMA lengths up to the last descriptor (length=0 is
> 0x10000 bytes) gives 0x20000 bytes. So the DMA table contains more
> bytes than the requested transfer.
>
> - The ADMA error register indicates ST_CADR, which is described as
> "This state is never set because do not generate ADMA error in this
> state."
>
> - The error descriptor is again after the descriptor with END=1, but
> this time has VALID=1.
>
> This _feels_ like a coherency issue, where the SDHCI engine is not
> correctly seeing the descriptor table, but then I would have expected
> userspace (which is basically debian stable) to fail to boot every
> time given that its rootfs is on eMMC.
>
> The other weird thing is if I wind the core MMC code back via:
>
> $ git diff -u 7559d612dff0..v5.3 drivers/mmc/core | patch -p1 -R
>
> and fix the lack of dma_max_pfn(), then SDHCI is more stable - not
> completely stable, but way better than plain v5.3. I don't see
> much in that diff which would be responsible for this - although it
> does seem that hch's DMA changes do make the problem more likely.
> (going from 1 in 3 boots with a problem to being not able to boot.)
>
> Note, with v5.2, I _never_ saw any ADMA errors, except if I disabled
> bypass mode on the IOMMU (but then I saw global smmu errors right
> from when the IOMMU had bypass disabled before MMC was probed - the
> reason being is the SoC is not currently setup to have the MMU
> bypass mode disabled.)
This looks like an ARM64 coherency issue.
I first tried adding a dma_wmb() to the end of sdhci_adma_table_pre(),
which had no effect. I then tried adding:
+ __dma_flush_area(host->adma_table, desc - host->adma_table);
+ dma_wmb();
and so far I haven't had any further ADMA errors. Adding Will Deacon
to the thread.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [breakage] panic() does not halt arm64 systems under certain conditions
From: Will Deacon @ 2019-09-17 11:05 UTC (permalink / raw)
To: Russell King - ARM Linux admin
Cc: linux-arch, gregkh, Xogium, linux-kernel, mingo, bp, tglx,
linux-arm-kernel
In-Reply-To: <20190917105136.GK25745@shell.armlinux.org.uk>
On Tue, Sep 17, 2019 at 11:51:36AM +0100, Russell King - ARM Linux admin wrote:
> On Tue, Sep 17, 2019 at 11:45:19AM +0100, Will Deacon wrote:
> > [Expanding CC list; original message is here:
> > https://lore.kernel.org/linux-arm-kernel/BX1W47JXPMR8.58IYW53H6M5N@dragonstone/]
> >
> > On Mon, Sep 16, 2019 at 09:35:36PM -0400, Xogium wrote:
> > > On arm64 in some situations userspace will continue running even after a
> > > panic. This means any userspace watchdog daemon will continue pinging,
> > > that service managers will keep running and displaying messages in certain
> > > cases, and that it is possible to enter via ssh in the now unstable system
> > > and to do almost anything except reboot/power off and etc. If
> > > CONFIG_PREEMPT=n is set in the kernel's configuration, the issue is fixed.
> > > I have reproduced the very same behavior with linux 4.19, 5.2 and 5.3. On
> > > x86/x86_64 the issue does not seem to be present at all.
> >
> > I've managed to reproduce this under both 32-bit and 64-bit ARM kernels.
> > The issue is that the infinite loop at the end of panic() can run with
> > preemption enabled (particularly when invoking by echoing 'c' to
> > /proc/sysrq-trigger), so we end up rescheduling user tasks. On x86, this
> > doesn't happen because smp_send_stop() disables the local APIC in
> > native_stop_other_cpus() and so interrupts are effectively masked while
> > spinning.
> >
> > A straightforward fix is to disable preemption explicitly on the panic()
> > path (diff below), but I've expanded the cc list to see both what others
> > think,
>
> Yep, and it looks like this bug goes back into the dim and distant past.
> At least to the start of modern git history, 2.6.12-rc2.
>
> > but also in case smp_send_stop() is supposed to have the side-effect
> > of disabling interrupt delivery for the local CPU.
>
> That can't fix it. Consider a preemptive non-SMP kernel.
> smp_send_stop() becomes a no-op there.
>
> I'd suggest that a preemptive UP kernel on x86 hardware will suffer
> this same issue - it will be able to preempt out of this loop and
> continue running userspace.
You're right; I managed to reproduce this locally on my xeon box.
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/3] pinctrl: meson-a1: add pinctrl driver for Meson A1 Soc
From: Qianggui Song @ 2019-09-17 10:59 UTC (permalink / raw)
To: Neil Armstrong, Linus Walleij, linux-gpio
Cc: Mark Rutland, Hanjie Lin, Jianxin Pan, Martin Blumenstingl,
Kevin Hilman, linux-kernel, Rob Herring, linux-arm-kernel,
Carlo Caione, linux-amlogic, Xingyu Chen, Jerome Brunet
In-Reply-To: <ffd2aa02-5269-9c7a-149e-99bda3439457@baylibre.com>
On 2019/9/17 15:15, Neil Armstrong wrote:
> Hi,
>
> On 17/09/2019 08:07, Qianggui Song wrote:
>> Add pinctrl driver for Meson A1 Soc which share the same register layout of
>> pinmux with previous Meson-G12A, however there is difference for gpio
>> and pin config register in A1. The register layout is as below:
>>
>> /* first bank */ /* addr */
>> - P_PADCTRL_GPIOP_I base + 0x00 << 2
>> - P_PADCTRL_GPIOP_O base + 0x01 << 2
>> - P_PADCTRL_GPIOP_OEN base + 0x02 << 2
>> - P_PADCTRL_GPIOP_PULL_EN base + 0x03 << 2
>> - P_PADCTRL_GPIOP_PULL_UP base + 0x04 << 2
>> - P_PADCTRL_GPIOP_DS base + 0x05 << 2
>>
>> /* second bank */
>> - P_PADCTRL_GPIOB_I base + 0x10 << 2
>> - P_PADCTRL_GPIOB_O base + 0x11 << 2
>> - P_PADCTRL_GPIOB_OEN base + 0x12 << 2
>> - P_PADCTRL_GPIOB_PULL_EN base + 0x13 << 2
>> - P_PADCTRL_GPIOB_PULL_UP base + 0x14 << 2
>> - P_PADCTRL_GPIOB_DS base + 0x15 << 2
>>
>> Each bank contains at least 6 registers to be configured, if one bank has
>> more than 16 gpios, an extra P_PADCTRL_GPIO[X]_DS_EXT is included. Between
>> two adjacent P_PADCTRL_GPIO[X]_I, there is an offset 0x10, that is to say,
>> for third bank, the offsets will be 0x20,0x21,0x22,0x23,0x24,0x25 according
>> to above register layout.
>
> Sorry but the explanation is not very clear, could you show the G12A mapping
> in comparison to explain your point and how reg_ds = reg_pullen solves the issue
> here ?
>
For G12A EE groups, register layout is like:
- PREG_PAD_GPIO[N]_EN_N
- PREG_PAD_GPIO[N]_O
- PREG_PAD_GPIO[N]_I
------address not continue----
- PAD_PULL_UP_REG[N]
...
------address not continue----
- PAD_PULL_UP_EN_REG[N]
...
------address not continue----
- PAD_DS_REG[N][M]
where N=0~5, M=A or B
So for G12A EE groups , to calculate other register, we have five
register bases in dts:
"gpio"(reg_gpio), "mux"(reg_mux), "pull(reg_pull)",
"pull_enable(reg_pull)", "ds(reg_ds)",
For G12A AO groups
- AO_PAD_DS_A
- AO_PAD_DS_B
- AO_GPIO_O_EN_N
- AO_GPIO_I
- AO_RTI_PULL_UP_REG
- AO_RTI_PULL_UP_EN_REG
- AO_GPIO_O
we only need three register bases in dts: "mux"(reg_mux), "ds"(reg_ds),
"gpio"(reg_gpio).
To do that "reg_pull = reg_gpio", "reg_pullen = reg_pull" have done by
previous work.
In A1, there are no EE and AO groups, register layout depicted in commit
log shows that we just use one register base (for A1 here is
P_PADCTRL_GPIOP_I), other register bases can be easily calculated for
simple rule. Since we just use one register base,reg_ds should be
equaled to reg_pullen.
G12A gpio and pin config registers is grouped according to function,
while A1 is according to bank.
>>
>> Current Meson pinctrl driver can cover such change by using base address of
>> GPIO as that of drive-strength. While simply giving reg_ds = reg_pullen
>> make wrong value to reg_ds for Soc that not support drive-strength like AXG
>> . Here a private data used to identify register layout is introduced.
>
> Could you also precise there is no AO pinctrl bank on A1.
>
will add description in the next patch
>>
>> Signed-off-by: Qianggui Song <qianggui.song@amlogic.com>
>> Signed-off-by: Xingyu Chen <xingyu.chen@amlogic.com>
>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>> ---
>> drivers/pinctrl/meson/Kconfig | 6 +
>> drivers/pinctrl/meson/Makefile | 1 +
>> drivers/pinctrl/meson/pinctrl-meson-a1.c | 942 +++++++++++++++++++++++++++++++
>> drivers/pinctrl/meson/pinctrl-meson.c | 8 +-
>> drivers/pinctrl/meson/pinctrl-meson.h | 9 +
>> 5 files changed, 964 insertions(+), 2 deletions(-)
>> create mode 100644 drivers/pinctrl/meson/pinctrl-meson-a1.c
>>
>> diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig
>> index df55f61..3cb1191 100644
>> --- a/drivers/pinctrl/meson/Kconfig
>> +++ b/drivers/pinctrl/meson/Kconfig
>> @@ -54,4 +54,10 @@ config PINCTRL_MESON_G12A
>> select PINCTRL_MESON_AXG_PMX
>> default y
>>
>> +config PINCTRL_MESON_A1
>> + bool "Meson a1 Soc pinctrl driver"
>> + depends on ARM64
>> + select PINCTRL_MESON_AXG_PMX
>> + default y
>> +
>> endif
>> diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
>> index a69c565..1a5bffe 100644
>> --- a/drivers/pinctrl/meson/Makefile
>> +++ b/drivers/pinctrl/meson/Makefile
>> @@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o
>> obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o
>> obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o
>> obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o
>> +obj-$(CONFIG_PINCTRL_MESON_A1) += pinctrl-meson-a1.o
>> diff --git a/drivers/pinctrl/meson/pinctrl-meson-a1.c b/drivers/pinctrl/meson/pinctrl-meson-a1.c
>> new file mode 100644
>> index 0000000..f3a88f1
>> --- /dev/null
>> +++ b/drivers/pinctrl/meson/pinctrl-meson-a1.c
>> @@ -0,0 +1,942 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Pin controller and GPIO driver for Amlogic Meson A1 SoC.
>> + *
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + * Author: Qianggui Song <qianggui.song@amlogic.com>
>> + */
>> +
>> +#include <dt-bindings/gpio/meson-a1-gpio.h>
>> +#include "pinctrl-meson.h"
>> +#include "pinctrl-meson-axg-pmx.h"
>> +
>> +static const struct pinctrl_pin_desc meson_a1_periphs_pins[] = {
>> + MESON_PIN(GPIOP_0),
>> + MESON_PIN(GPIOP_1),
>> + MESON_PIN(GPIOP_2),
>> + MESON_PIN(GPIOP_3),
>> + MESON_PIN(GPIOP_4),
>> + MESON_PIN(GPIOP_5),
>> + MESON_PIN(GPIOP_6),
>> + MESON_PIN(GPIOP_7),
>> + MESON_PIN(GPIOP_8),
>> + MESON_PIN(GPIOP_9),
>> + MESON_PIN(GPIOP_10),
>> + MESON_PIN(GPIOP_11),
>> + MESON_PIN(GPIOP_12),
>> + MESON_PIN(GPIOB_0),
>> + MESON_PIN(GPIOB_1),
>> + MESON_PIN(GPIOB_2),
>> + MESON_PIN(GPIOB_3),
>> + MESON_PIN(GPIOB_4),
>> + MESON_PIN(GPIOB_5),
>> + MESON_PIN(GPIOB_6),
>> + MESON_PIN(GPIOX_0),
>> + MESON_PIN(GPIOX_1),
>> + MESON_PIN(GPIOX_2),
>> + MESON_PIN(GPIOX_3),
>> + MESON_PIN(GPIOX_4),
>> + MESON_PIN(GPIOX_5),
>> + MESON_PIN(GPIOX_6),
>> + MESON_PIN(GPIOX_7),
>> + MESON_PIN(GPIOX_8),
>> + MESON_PIN(GPIOX_9),
>> + MESON_PIN(GPIOX_10),
>> + MESON_PIN(GPIOX_11),
>> + MESON_PIN(GPIOX_12),
>> + MESON_PIN(GPIOX_13),
>> + MESON_PIN(GPIOX_14),
>> + MESON_PIN(GPIOX_15),
>> + MESON_PIN(GPIOX_16),
>> + MESON_PIN(GPIOF_0),
>> + MESON_PIN(GPIOF_1),
>> + MESON_PIN(GPIOF_2),
>> + MESON_PIN(GPIOF_3),
>> + MESON_PIN(GPIOF_4),
>> + MESON_PIN(GPIOF_5),
>> + MESON_PIN(GPIOF_6),
>> + MESON_PIN(GPIOF_7),
>> + MESON_PIN(GPIOF_8),
>> + MESON_PIN(GPIOF_9),
>> + MESON_PIN(GPIOF_10),
>> + MESON_PIN(GPIOF_11),
>> + MESON_PIN(GPIOF_12),
>> + MESON_PIN(GPIOA_0),
>> + MESON_PIN(GPIOA_1),
>> + MESON_PIN(GPIOA_2),
>> + MESON_PIN(GPIOA_3),
>> + MESON_PIN(GPIOA_4),
>> + MESON_PIN(GPIOA_5),
>> + MESON_PIN(GPIOA_6),
>> + MESON_PIN(GPIOA_7),
>> + MESON_PIN(GPIOA_8),
>> + MESON_PIN(GPIOA_9),
>> + MESON_PIN(GPIOA_10),
>> + MESON_PIN(GPIOA_11),
>> +};
>> +
>> +/* psram */
>> +static const unsigned int psram_clkn_pins[] = { GPIOP_0 };
>> +static const unsigned int psram_clkp_pins[] = { GPIOP_1 };
>> +static const unsigned int psram_ce_n_pins[] = { GPIOP_2 };
>> +static const unsigned int psram_rst_n_pins[] = { GPIOP_3 };
>> +static const unsigned int psram_adq0_pins[] = { GPIOP_4 };
>> +static const unsigned int psram_adq1_pins[] = { GPIOP_5 };
>> +static const unsigned int psram_adq2_pins[] = { GPIOP_6 };
>> +static const unsigned int psram_adq3_pins[] = { GPIOP_7 };
>> +static const unsigned int psram_adq4_pins[] = { GPIOP_8 };
>> +static const unsigned int psram_adq5_pins[] = { GPIOP_9 };
>> +static const unsigned int psram_adq6_pins[] = { GPIOP_10 };
>> +static const unsigned int psram_adq7_pins[] = { GPIOP_11 };
>> +static const unsigned int psram_dqs_dm_pins[] = { GPIOP_12 };
>> +
>> +/* sdcard */
>> +static const unsigned int sdcard_d0_b_pins[] = { GPIOB_0 };
>> +static const unsigned int sdcard_d1_b_pins[] = { GPIOB_1 };
>> +static const unsigned int sdcard_d2_b_pins[] = { GPIOB_2 };
>> +static const unsigned int sdcard_d3_b_pins[] = { GPIOB_3 };
>> +static const unsigned int sdcard_clk_b_pins[] = { GPIOB_4 };
>> +static const unsigned int sdcard_cmd_b_pins[] = { GPIOB_5 };
>> +
>> +static const unsigned int sdcard_d0_x_pins[] = { GPIOX_0 };
>> +static const unsigned int sdcard_d1_x_pins[] = { GPIOX_1 };
>> +static const unsigned int sdcard_d2_x_pins[] = { GPIOX_2 };
>> +static const unsigned int sdcard_d3_x_pins[] = { GPIOX_3 };
>> +static const unsigned int sdcard_clk_x_pins[] = { GPIOX_4 };
>> +static const unsigned int sdcard_cmd_x_pins[] = { GPIOX_5 };
>> +
>> +/* spif */
>> +static const unsigned int spif_mo_pins[] = { GPIOB_0 };
>> +static const unsigned int spif_mi_pins[] = { GPIOB_1 };
>> +static const unsigned int spif_wp_n_pins[] = { GPIOB_2 };
>> +static const unsigned int spif_hold_n_pins[] = { GPIOB_3 };
>> +static const unsigned int spif_clk_pins[] = { GPIOB_4 };
>> +static const unsigned int spif_cs_pins[] = { GPIOB_5 };
>> +
>> +/* i2c0 */
>> +static const unsigned int i2c0_sck_f9_pins[] = { GPIOF_9 };
>> +static const unsigned int i2c0_sda_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int i2c0_sck_f11_pins[] = { GPIOF_11 };
>> +static const unsigned int i2c0_sda_f12_pins[] = { GPIOF_12 };
>> +
>> +/* i2c1 */
>> +static const unsigned int i2c1_sda_x_pins[] = { GPIOX_9 };
>> +static const unsigned int i2c1_sck_x_pins[] = { GPIOX_10 };
>> +static const unsigned int i2c1_sda_a_pins[] = { GPIOA_10 };
>> +static const unsigned int i2c1_sck_a_pins[] = { GPIOA_11 };
>> +
>> +/* i2c2 */
>> +static const unsigned int i2c2_sck_x0_pins[] = { GPIOX_0 };
>> +static const unsigned int i2c2_sda_x1_pins[] = { GPIOX_1 };
>> +static const unsigned int i2c2_sck_x15_pins[] = { GPIOX_15 };
>> +static const unsigned int i2c2_sda_x16_pins[] = { GPIOX_16 };
>> +static const unsigned int i2c2_sck_a4_pins[] = { GPIOA_4 };
>> +static const unsigned int i2c2_sda_a5_pins[] = { GPIOA_5 };
>> +static const unsigned int i2c2_sck_a8_pins[] = { GPIOA_8 };
>> +static const unsigned int i2c2_sda_a9_pins[] = { GPIOA_9 };
>> +
>> +/* i2c3 */
>> +static const unsigned int i2c3_sck_f_pins[] = { GPIOF_4 };
>> +static const unsigned int i2c3_sda_f_pins[] = { GPIOF_5 };
>> +static const unsigned int i2c3_sck_x_pins[] = { GPIOX_11 };
>> +static const unsigned int i2c3_sda_x_pins[] = { GPIOX_12 };
>> +
>> +/* i2c slave */
>> +static const unsigned int i2c_slave_sck_a_pins[] = { GPIOA_10 };
>> +static const unsigned int i2c_slave_sda_a_pins[] = { GPIOA_11 };
>> +static const unsigned int i2c_slave_sck_f_pins[] = { GPIOF_11 };
>> +static const unsigned int i2c_slave_sda_f_pins[] = { GPIOF_12 };
>> +
>> +/* uart_a */
>> +static const unsigned int uart_a_tx_pins[] = { GPIOX_11 };
>> +static const unsigned int uart_a_rx_pins[] = { GPIOX_12 };
>> +static const unsigned int uart_a_cts_pins[] = { GPIOX_13 };
>> +static const unsigned int uart_a_rts_pins[] = { GPIOX_14 };
>> +
>> +/* uart_b */
>> +static const unsigned int uart_b_tx_x_pins[] = { GPIOX_7 };
>> +static const unsigned int uart_b_rx_x_pins[] = { GPIOX_8 };
>> +static const unsigned int uart_b_tx_f_pins[] = { GPIOF_0 };
>> +static const unsigned int uart_b_rx_f_pins[] = { GPIOF_1 };
>> +
>> +/* uart_c */
>> +static const unsigned int uart_c_tx_x0_pins[] = { GPIOX_0 };
>> +static const unsigned int uart_c_rx_x1_pins[] = { GPIOX_1 };
>> +static const unsigned int uart_c_cts_pins[] = { GPIOX_2 };
>> +static const unsigned int uart_c_rts_pins[] = { GPIOX_3 };
>> +static const unsigned int uart_c_tx_x15_pins[] = { GPIOX_15 };
>> +static const unsigned int uart_c_rx_x16_pins[] = { GPIOX_16 };
>> +
>> +/* pmw_a */
>> +static const unsigned int pwm_a_x6_pins[] = { GPIOX_6 };
>> +static const unsigned int pwm_a_x7_pins[] = { GPIOX_7 };
>> +static const unsigned int pwm_a_f6_pins[] = { GPIOF_6 };
>> +static const unsigned int pwm_a_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int pwm_a_a_pins[] = { GPIOA_5 };
>> +
>> +/* pmw_b */
>> +static const unsigned int pwm_b_x_pins[] = { GPIOX_8 };
>> +static const unsigned int pwm_b_f_pins[] = { GPIOF_7 };
>> +static const unsigned int pwm_b_a_pins[] = { GPIOA_11 };
>> +
>> +/* pmw_c */
>> +static const unsigned int pwm_c_x_pins[] = { GPIOX_9 };
>> +static const unsigned int pwm_c_f3_pins[] = { GPIOF_3 };
>> +static const unsigned int pwm_c_f8_pins[] = { GPIOF_8 };
>> +static const unsigned int pwm_c_a_pins[] = { GPIOA_10 };
>> +
>> +/* pwm_d */
>> +static const unsigned int pwm_d_x10_pins[] = { GPIOX_10 };
>> +static const unsigned int pwm_d_x13_pins[] = { GPIOX_13 };
>> +static const unsigned int pwm_d_x15_pins[] = { GPIOX_15 };
>> +static const unsigned int pwm_d_f_pins[] = { GPIOF_11 };
>> +
>> +/* pwm_e */
>> +static const unsigned int pwm_e_p_pins[] = { GPIOP_3 };
>> +static const unsigned int pwm_e_x2_pins[] = { GPIOX_2 };
>> +static const unsigned int pwm_e_x14_pins[] = { GPIOX_14 };
>> +static const unsigned int pwm_e_x16_pins[] = { GPIOX_16 };
>> +static const unsigned int pwm_e_f_pins[] = { GPIOF_3 };
>> +static const unsigned int pwm_e_a_pins[] = { GPIOA_0 };
>> +
>> +/* pwm_f */
>> +static const unsigned int pwm_f_b_pins[] = { GPIOB_6 };
>> +static const unsigned int pwm_f_x_pins[] = { GPIOX_3 };
>> +static const unsigned int pwm_f_f4_pins[] = { GPIOF_4 };
>> +static const unsigned int pwm_f_f12_pins[] = { GPIOF_12 };
>> +
>> +/* pwm_a_hiz */
>> +static const unsigned int pwm_a_hiz_f8_pins[] = { GPIOF_8 };
>> +static const unsigned int pwm_a_hiz_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int pmw_a_hiz_f6_pins[] = { GPIOF_6 };
>> +
>> +/* pwm_b_hiz */
>> +static const unsigned int pwm_b_hiz_pins[] = { GPIOF_7 };
>> +
>> +/* pmw_c_hiz */
>> +static const unsigned int pwm_c_hiz_pins[] = { GPIOF_8 };
>> +
>> +/* tdm_a */
>> +static const unsigned int tdm_a_dout1_pins[] = { GPIOX_7 };
>> +static const unsigned int tdm_a_dout0_pins[] = { GPIOX_8 };
>> +static const unsigned int tdm_a_fs_pins[] = { GPIOX_9 };
>> +static const unsigned int tdm_a_sclk_pins[] = { GPIOX_10 };
>> +static const unsigned int tdm_a_din1_pins[] = { GPIOX_7 };
>> +static const unsigned int tdm_a_din0_pins[] = { GPIOX_8 };
>> +static const unsigned int tdm_a_slv_fs_pins[] = { GPIOX_9 };
>> +static const unsigned int tdm_a_slv_sclk_pins[] = { GPIOX_10 };
>> +
>> +/* spi_a */
>> +static const unsigned int spi_a_mosi_x2_pins[] = { GPIOX_2 };
>> +static const unsigned int spi_a_ss0_x3_pins[] = { GPIOX_3 };
>> +static const unsigned int spi_a_sclk_x4_pins[] = { GPIOX_4 };
>> +static const unsigned int spi_a_miso_x5_pins[] = { GPIOX_5 };
>> +static const unsigned int spi_a_mosi_x7_pins[] = { GPIOX_7 };
>> +static const unsigned int spi_a_miso_x8_pins[] = { GPIOX_8 };
>> +static const unsigned int spi_a_ss0_x9_pins[] = { GPIOX_9 };
>> +static const unsigned int spi_a_sclk_x10_pins[] = { GPIOX_10 };
>> +
>> +static const unsigned int spi_a_mosi_a_pins[] = { GPIOA_6 };
>> +static const unsigned int spi_a_miso_a_pins[] = { GPIOA_7 };
>> +static const unsigned int spi_a_ss0_a_pins[] = { GPIOA_8 };
>> +static const unsigned int spi_a_sclk_a_pins[] = { GPIOA_9 };
>> +
>> +/* pdm */
>> +static const unsigned int pdm_din0_x_pins[] = { GPIOX_7 };
>> +static const unsigned int pdm_din1_x_pins[] = { GPIOX_8 };
>> +static const unsigned int pdm_din2_x_pins[] = { GPIOX_9 };
>> +static const unsigned int pdm_dclk_x_pins[] = { GPIOX_10 };
>> +
>> +static const unsigned int pdm_din2_a_pins[] = { GPIOA_6 };
>> +static const unsigned int pdm_din1_a_pins[] = { GPIOA_7 };
>> +static const unsigned int pdm_din0_a_pins[] = { GPIOA_8 };
>> +static const unsigned int pdm_dclk_pins[] = { GPIOA_9 };
>> +
>> +/* gen_clk */
>> +static const unsigned int gen_clk_x_pins[] = { GPIOX_7 };
>> +static const unsigned int gen_clk_f8_pins[] = { GPIOF_8 };
>> +static const unsigned int gen_clk_f10_pins[] = { GPIOF_10 };
>> +static const unsigned int gen_clk_a_pins[] = { GPIOA_11 };
>> +
>> +/* jtag_a */
>> +static const unsigned int jtag_a_clk_pins[] = { GPIOF_4 };
>> +static const unsigned int jtag_a_tms_pins[] = { GPIOF_5 };
>> +static const unsigned int jtag_a_tdi_pins[] = { GPIOF_6 };
>> +static const unsigned int jtag_a_tdo_pins[] = { GPIOF_7 };
>> +
>> +/* clk_32_in */
>> +static const unsigned int clk_32k_in_pins[] = { GPIOF_2 };
>> +
>> +/* ir in */
>> +static const unsigned int remote_input_f_pins[] = { GPIOF_3 };
>> +static const unsigned int remote_input_a_pins[] = { GPIOA_11 };
>> +
>> +/* ir out */
>> +static const unsigned int remote_out_pins[] = { GPIOF_5 };
>> +
>> +/* spdif */
>> +static const unsigned int spdif_in_f6_pins[] = { GPIOF_6 };
>> +static const unsigned int spdif_in_f7_pins[] = { GPIOF_7 };
>> +
>> +/* sw */
>> +static const unsigned int swclk_pins[] = { GPIOF_4 };
>> +static const unsigned int swdio_pins[] = { GPIOF_5 };
>> +
>> +/* clk_25 */
>> +static const unsigned int clk25_pins[] = { GPIOF_10 };
>> +
>> +/* cec_a */
>> +static const unsigned int cec_a_pins[] = { GPIOF_2 };
>> +
>> +/* cec_b */
>> +static const unsigned int cec_b_pins[] = { GPIOF_2 };
>> +
>> +/* clk12_24 */
>> +static const unsigned int clk12_24_pins[] = { GPIOF_10 };
>> +
>> +/* mclk_0 */
>> +static const unsigned int mclk_0_pins[] = { GPIOA_0 };
>> +
>> +/* tdm_b */
>> +static const unsigned int tdm_b_sclk_pins[] = { GPIOA_1 };
>> +static const unsigned int tdm_b_fs_pins[] = { GPIOA_2 };
>> +static const unsigned int tdm_b_dout0_pins[] = { GPIOA_3 };
>> +static const unsigned int tdm_b_dout1_pins[] = { GPIOA_4 };
>> +static const unsigned int tdm_b_dout2_pins[] = { GPIOA_5 };
>> +static const unsigned int tdm_b_dout3_pins[] = { GPIOA_6 };
>> +static const unsigned int tdm_b_dout4_pins[] = { GPIOA_7 };
>> +static const unsigned int tdm_b_dout5_pins[] = { GPIOA_8 };
>> +static const unsigned int tdm_b_slv_sclk_pins[] = { GPIOA_5 };
>> +static const unsigned int tdm_b_slv_fs_pins[] = { GPIOA_6 };
>> +static const unsigned int tdm_b_din0_pins[] = { GPIOA_7 };
>> +static const unsigned int tdm_b_din1_pins[] = { GPIOA_8 };
>> +static const unsigned int tdm_b_din2_pins[] = { GPIOA_9 };
>> +
>> +/* mclk_vad */
>> +static const unsigned int mclk_vad_pins[] = { GPIOA_0 };
>> +
>> +/* tdm_vad */
>> +static const unsigned int tdm_vad_sclk_a1_pins[] = { GPIOA_1 };
>> +static const unsigned int tdm_vad_fs_a2_pins[] = { GPIOA_2 };
>> +static const unsigned int tdm_vad_sclk_a5_pins[] = { GPIOA_5 };
>> +static const unsigned int tdm_vad_fs_a6_pins[] = { GPIOA_6 };
>> +
>> +/* tst_out */
>> +static const unsigned int tst_out0_pins[] = { GPIOA_0 };
>> +static const unsigned int tst_out1_pins[] = { GPIOA_1 };
>> +static const unsigned int tst_out2_pins[] = { GPIOA_2 };
>> +static const unsigned int tst_out3_pins[] = { GPIOA_3 };
>> +static const unsigned int tst_out4_pins[] = { GPIOA_4 };
>> +static const unsigned int tst_out5_pins[] = { GPIOA_5 };
>> +static const unsigned int tst_out6_pins[] = { GPIOA_6 };
>> +static const unsigned int tst_out7_pins[] = { GPIOA_7 };
>> +static const unsigned int tst_out8_pins[] = { GPIOA_8 };
>> +static const unsigned int tst_out9_pins[] = { GPIOA_9 };
>> +static const unsigned int tst_out10_pins[] = { GPIOA_10 };
>> +static const unsigned int tst_out11_pins[] = { GPIOA_11 };
>> +
>> +/* mute */
>> +static const unsigned int mute_key_pins[] = { GPIOA_4 };
>> +static const unsigned int mute_en_pins[] = { GPIOA_5 };
>> +
>> +static struct meson_pmx_group meson_a1_periphs_groups[] = {
>> + GPIO_GROUP(GPIOP_0),
>> + GPIO_GROUP(GPIOP_1),
>> + GPIO_GROUP(GPIOP_2),
>> + GPIO_GROUP(GPIOP_3),
>> + GPIO_GROUP(GPIOP_4),
>> + GPIO_GROUP(GPIOP_5),
>> + GPIO_GROUP(GPIOP_6),
>> + GPIO_GROUP(GPIOP_7),
>> + GPIO_GROUP(GPIOP_8),
>> + GPIO_GROUP(GPIOP_9),
>> + GPIO_GROUP(GPIOP_10),
>> + GPIO_GROUP(GPIOP_11),
>> + GPIO_GROUP(GPIOP_12),
>> + GPIO_GROUP(GPIOB_0),
>> + GPIO_GROUP(GPIOB_1),
>> + GPIO_GROUP(GPIOB_2),
>> + GPIO_GROUP(GPIOB_3),
>> + GPIO_GROUP(GPIOB_4),
>> + GPIO_GROUP(GPIOB_5),
>> + GPIO_GROUP(GPIOB_6),
>> + GPIO_GROUP(GPIOX_0),
>> + GPIO_GROUP(GPIOX_1),
>> + GPIO_GROUP(GPIOX_2),
>> + GPIO_GROUP(GPIOX_3),
>> + GPIO_GROUP(GPIOX_4),
>> + GPIO_GROUP(GPIOX_5),
>> + GPIO_GROUP(GPIOX_6),
>> + GPIO_GROUP(GPIOX_7),
>> + GPIO_GROUP(GPIOX_8),
>> + GPIO_GROUP(GPIOX_9),
>> + GPIO_GROUP(GPIOX_10),
>> + GPIO_GROUP(GPIOX_11),
>> + GPIO_GROUP(GPIOX_12),
>> + GPIO_GROUP(GPIOX_13),
>> + GPIO_GROUP(GPIOX_14),
>> + GPIO_GROUP(GPIOX_15),
>> + GPIO_GROUP(GPIOX_16),
>> + GPIO_GROUP(GPIOF_0),
>> + GPIO_GROUP(GPIOF_1),
>> + GPIO_GROUP(GPIOF_2),
>> + GPIO_GROUP(GPIOF_3),
>> + GPIO_GROUP(GPIOF_4),
>> + GPIO_GROUP(GPIOF_5),
>> + GPIO_GROUP(GPIOF_6),
>> + GPIO_GROUP(GPIOF_7),
>> + GPIO_GROUP(GPIOF_8),
>> + GPIO_GROUP(GPIOF_9),
>> + GPIO_GROUP(GPIOF_10),
>> + GPIO_GROUP(GPIOF_11),
>> + GPIO_GROUP(GPIOF_12),
>> + GPIO_GROUP(GPIOA_0),
>> + GPIO_GROUP(GPIOA_1),
>> + GPIO_GROUP(GPIOA_2),
>> + GPIO_GROUP(GPIOA_3),
>> + GPIO_GROUP(GPIOA_4),
>> + GPIO_GROUP(GPIOA_5),
>> + GPIO_GROUP(GPIOA_6),
>> + GPIO_GROUP(GPIOA_7),
>> + GPIO_GROUP(GPIOA_8),
>> + GPIO_GROUP(GPIOA_9),
>> + GPIO_GROUP(GPIOA_10),
>> + GPIO_GROUP(GPIOA_11),
>> +
>> + /* bank P func1 */
>> + GROUP(psram_clkn, 1),
>> + GROUP(psram_clkp, 1),
>> + GROUP(psram_ce_n, 1),
>> + GROUP(psram_rst_n, 1),
>> + GROUP(psram_adq0, 1),
>> + GROUP(psram_adq1, 1),
>> + GROUP(psram_adq2, 1),
>> + GROUP(psram_adq3, 1),
>> + GROUP(psram_adq4, 1),
>> + GROUP(psram_adq5, 1),
>> + GROUP(psram_adq6, 1),
>> + GROUP(psram_adq7, 1),
>> + GROUP(psram_dqs_dm, 1),
>> +
>> + /*bank P func2 */
>> + GROUP(pwm_e_p, 2),
>> +
>> + /*bank B func1 */
>> + GROUP(spif_mo, 1),
>> + GROUP(spif_mi, 1),
>> + GROUP(spif_wp_n, 1),
>> + GROUP(spif_hold_n, 1),
>> + GROUP(spif_clk, 1),
>> + GROUP(spif_cs, 1),
>> + GROUP(pwm_f_b, 1),
>> +
>> + /*bank B func2 */
>> + GROUP(sdcard_d0_b, 2),
>> + GROUP(sdcard_d1_b, 2),
>> + GROUP(sdcard_d2_b, 2),
>> + GROUP(sdcard_d3_b, 2),
>> + GROUP(sdcard_clk_b, 2),
>> + GROUP(sdcard_cmd_b, 2),
>> +
>> + /*bank X func1 */
>> + GROUP(sdcard_d0_x, 1),
>> + GROUP(sdcard_d1_x, 1),
>> + GROUP(sdcard_d2_x, 1),
>> + GROUP(sdcard_d3_x, 1),
>> + GROUP(sdcard_clk_x, 1),
>> + GROUP(sdcard_cmd_x, 1),
>> + GROUP(pwm_a_x6, 1),
>> + GROUP(tdm_a_dout1, 1),
>> + GROUP(tdm_a_dout0, 1),
>> + GROUP(tdm_a_fs, 1),
>> + GROUP(tdm_a_sclk, 1),
>> + GROUP(uart_a_tx, 1),
>> + GROUP(uart_a_rx, 1),
>> + GROUP(uart_a_cts, 1),
>> + GROUP(uart_a_rts, 1),
>> + GROUP(pwm_d_x15, 1),
>> + GROUP(pwm_e_x16, 1),
>> +
>> + /*bank X func2 */
>> + GROUP(i2c2_sck_x0, 2),
>> + GROUP(i2c2_sda_x1, 2),
>> + GROUP(spi_a_mosi_x2, 2),
>> + GROUP(spi_a_ss0_x3, 2),
>> + GROUP(spi_a_sclk_x4, 2),
>> + GROUP(spi_a_miso_x5, 2),
>> + GROUP(tdm_a_din1, 2),
>> + GROUP(tdm_a_din0, 2),
>> + GROUP(tdm_a_slv_fs, 2),
>> + GROUP(tdm_a_slv_sclk, 2),
>> + GROUP(i2c3_sck_x, 2),
>> + GROUP(i2c3_sda_x, 2),
>> + GROUP(pwm_d_x13, 2),
>> + GROUP(pwm_e_x14, 2),
>> + GROUP(i2c2_sck_x15, 2),
>> + GROUP(i2c2_sda_x16, 2),
>> +
>> + /*bank X func3 */
>> + GROUP(uart_c_tx_x0, 3),
>> + GROUP(uart_c_rx_x1, 3),
>> + GROUP(uart_c_cts, 3),
>> + GROUP(uart_c_rts, 3),
>> + GROUP(pdm_din0_x, 3),
>> + GROUP(pdm_din1_x, 3),
>> + GROUP(pdm_din2_x, 3),
>> + GROUP(pdm_dclk_x, 3),
>> + GROUP(uart_c_tx_x15, 3),
>> + GROUP(uart_c_rx_x16, 3),
>> +
>> + /*bank X func4 */
>> + GROUP(pwm_e_x2, 4),
>> + GROUP(pwm_f_x, 4),
>> + GROUP(spi_a_mosi_x7, 4),
>> + GROUP(spi_a_miso_x8, 4),
>> + GROUP(spi_a_ss0_x9, 4),
>> + GROUP(spi_a_sclk_x10, 4),
>> +
>> + /*bank X func5 */
>> + GROUP(uart_b_tx_x, 5),
>> + GROUP(uart_b_rx_x, 5),
>> + GROUP(i2c1_sda_x, 5),
>> + GROUP(i2c1_sck_x, 5),
>> +
>> + /*bank X func6 */
>> + GROUP(pwm_a_x7, 6),
>> + GROUP(pwm_b_x, 6),
>> + GROUP(pwm_c_x, 6),
>> + GROUP(pwm_d_x10, 6),
>> +
>> + /*bank X func7 */
>> + GROUP(gen_clk_x, 7),
>> +
>> + /*bank F func1 */
>> + GROUP(uart_b_tx_f, 1),
>> + GROUP(uart_b_rx_f, 1),
>> + GROUP(remote_input_f, 1),
>> + GROUP(jtag_a_clk, 1),
>> + GROUP(jtag_a_tms, 1),
>> + GROUP(jtag_a_tdi, 1),
>> + GROUP(jtag_a_tdo, 1),
>> + GROUP(gen_clk_f8, 1),
>> + GROUP(pwm_a_f10, 1),
>> + GROUP(i2c0_sck_f11, 1),
>> + GROUP(i2c0_sda_f12, 1),
>> +
>> + /*bank F func2 */
>> + GROUP(clk_32k_in, 2),
>> + GROUP(pwm_e_f, 2),
>> + GROUP(pwm_f_f4, 2),
>> + GROUP(remote_out, 2),
>> + GROUP(spdif_in_f6, 2),
>> + GROUP(spdif_in_f7, 2),
>> + GROUP(pwm_a_hiz_f8, 2),
>> + GROUP(pwm_a_hiz_f10, 2),
>> + GROUP(pwm_d_f, 2),
>> + GROUP(pwm_f_f12, 2),
>> +
>> + /*bank F func3 */
>> + GROUP(pwm_c_f3, 3),
>> + GROUP(swclk, 3),
>> + GROUP(swdio, 3),
>> + GROUP(pwm_a_f6, 3),
>> + GROUP(pwm_b_f, 3),
>> + GROUP(pwm_c_f8, 3),
>> + GROUP(clk25, 3),
>> + GROUP(i2c_slave_sck_f, 3),
>> + GROUP(i2c_slave_sda_f, 3),
>> +
>> + /*bank F func4 */
>> + GROUP(cec_a, 4),
>> + GROUP(i2c3_sck_f, 4),
>> + GROUP(i2c3_sda_f, 4),
>> + GROUP(pmw_a_hiz_f6, 4),
>> + GROUP(pwm_b_hiz, 4),
>> + GROUP(pwm_c_hiz, 4),
>> + GROUP(i2c0_sck_f9, 4),
>> + GROUP(i2c0_sda_f10, 4),
>> +
>> + /*bank F func5 */
>> + GROUP(cec_b, 5),
>> + GROUP(clk12_24, 5),
>> +
>> + /*bank F func7 */
>> + GROUP(gen_clk_f10, 7),
>> +
>> + /*bank A func1 */
>> + GROUP(mclk_0, 1),
>> + GROUP(tdm_b_sclk, 1),
>> + GROUP(tdm_b_fs, 1),
>> + GROUP(tdm_b_dout0, 1),
>> + GROUP(tdm_b_dout1, 1),
>> + GROUP(tdm_b_dout2, 1),
>> + GROUP(tdm_b_dout3, 1),
>> + GROUP(tdm_b_dout4, 1),
>> + GROUP(tdm_b_dout5, 1),
>> + GROUP(remote_input_a, 1),
>> +
>> + /*bank A func2 */
>> + GROUP(pwm_e_a, 2),
>> + GROUP(tdm_b_slv_sclk, 2),
>> + GROUP(tdm_b_slv_fs, 2),
>> + GROUP(tdm_b_din0, 2),
>> + GROUP(tdm_b_din1, 2),
>> + GROUP(tdm_b_din2, 2),
>> + GROUP(i2c1_sda_a, 2),
>> + GROUP(i2c1_sck_a, 2),
>> +
>> + /*bank A func3 */
>> + GROUP(i2c2_sck_a4, 3),
>> + GROUP(i2c2_sda_a5, 3),
>> + GROUP(pdm_din2_a, 3),
>> + GROUP(pdm_din1_a, 3),
>> + GROUP(pdm_din0_a, 3),
>> + GROUP(pdm_dclk, 3),
>> + GROUP(pwm_c_a, 3),
>> + GROUP(pwm_b_a, 3),
>> +
>> + /*bank A func4 */
>> + GROUP(pwm_a_a, 4),
>> + GROUP(spi_a_mosi_a, 4),
>> + GROUP(spi_a_miso_a, 4),
>> + GROUP(spi_a_ss0_a, 4),
>> + GROUP(spi_a_sclk_a, 4),
>> + GROUP(i2c_slave_sck_a, 4),
>> + GROUP(i2c_slave_sda_a, 4),
>> +
>> + /*bank A func5 */
>> + GROUP(mclk_vad, 5),
>> + GROUP(tdm_vad_sclk_a1, 5),
>> + GROUP(tdm_vad_fs_a2, 5),
>> + GROUP(tdm_vad_sclk_a5, 5),
>> + GROUP(tdm_vad_fs_a6, 5),
>> + GROUP(i2c2_sck_a8, 5),
>> + GROUP(i2c2_sda_a9, 5),
>> +
>> + /*bank A func6 */
>> + GROUP(tst_out0, 6),
>> + GROUP(tst_out1, 6),
>> + GROUP(tst_out2, 6),
>> + GROUP(tst_out3, 6),
>> + GROUP(tst_out4, 6),
>> + GROUP(tst_out5, 6),
>> + GROUP(tst_out6, 6),
>> + GROUP(tst_out7, 6),
>> + GROUP(tst_out8, 6),
>> + GROUP(tst_out9, 6),
>> + GROUP(tst_out10, 6),
>> + GROUP(tst_out11, 6),
>> +
>> + /*bank A func7 */
>> + GROUP(mute_key, 7),
>> + GROUP(mute_en, 7),
>> + GROUP(gen_clk_a, 7),
>> +};
>> +
>> +static const char * const gpio_periphs_groups[] = {
>> + "GPIOP_0", "GPIOP_1", "GPIOP_2", "GPIOP_3", "GPIOP_4",
>> + "GPIOP_5", "GPIOP_6", "GPIOP_7", "GPIOP_8", "GPIOP_9",
>> + "GPIOP_10", "GPIOP_11", "GPIOP_12",
>> +
>> + "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4",
>> + "GPIOB_5", "GPIOB_6",
>> +
>> + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
>> + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
>> + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
>> + "GPIOX_15", "GPIOX_16",
>> +
>> + "GPIOF_0", "GPIOF_1", "GPIOF_2", "GPIOF_3", "GPIOF_4",
>> + "GPIOF_5", "GPIOF_6", "GPIOF_7", "GPIOF_8", "GPIOF_9",
>> + "GPIOF_10", "GPIOF_11", "GPIOF_12",
>> +
>> + "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4",
>> + "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9",
>> + "GPIOA_10", "GPIOA_11",
>> +};
>> +
>> +static const char * const psram_groups[] = {
>> + "psram_clkn", "psram_clkp", "psram_ce_n", "psram_rst_n", "psram_adq0",
>> + "psram_adq1", "psram_adq2", "psram_adq3", "psram_adq4", "psram_adq5",
>> + "psram_adq6", "psram_adq7", "psram_dqs_dm",
>> +};
>> +
>> +static const char * const pwm_a_groups[] = {
>> + "pwm_a_x6", "pwm_a_x7", "pwm_a_f10", "pwm_a_f6", "pwm_a_a",
>> +};
>> +
>> +static const char * const pwm_b_groups[] = {
>> + "pwm_b_x", "pwm_b_f", "pwm_b_a",
>> +};
>> +
>> +static const char * const pwm_c_groups[] = {
>> + "pwm_c_x", "pwm_c_f3", "pwm_c_f8", "pwm_c_a",
>> +};
>> +
>> +static const char * const pwm_d_groups[] = {
>> + "pwm_d_x15", "pwm_d_x13", "pwm_d_x10", "pwm_d_f",
>> +};
>> +
>> +static const char * const pwm_e_groups[] = {
>> + "pwm_e_p", "pwm_e_x16", "pwm_e_x14", "pwm_e_x2", "pwm_e_f",
>> + "pwm_e_a",
>> +};
>> +
>> +static const char * const pwm_f_groups[] = {
>> + "pwm_f_b", "pwm_f_x", "pwm_f_f4", "pwm_f_f12",
>> +};
>> +
>> +static const char * const pwm_a_hiz_groups[] = {
>> + "pwm_a_hiz_f8", "pwm_a_hiz_f10", "pwm_a_hiz_f6",
>> +};
>> +
>> +static const char * const pwm_b_hiz_groups[] = {
>> + "pwm_b_hiz",
>> +};
>> +
>> +static const char * const pwm_c_hiz_groups[] = {
>> + "pwm_c_hiz",
>> +};
>> +
>> +static const char * const spif_groups[] = {
>> + "spif_mo", "spif_mi", "spif_wp_n", "spif_hold_n", "spif_clk",
>> + "spif_cs",
>> +};
>> +
>> +static const char * const sdcard_groups[] = {
>> + "sdcard_d0_b", "sdcard_d1_b", "sdcard_d2_b", "sdcard_d3_b",
>> + "sdcard_clk_b", "sdcard_cmd_b",
>> +
>> + "sdcard_d0_x", "sdcard_d1_x", "sdcard_d2_x", "sdcard_d3_x",
>> + "sdcard_clk_x", "sdcard_cmd_x",
>> +};
>> +
>> +static const char * const tdm_a_groups[] = {
>> + "tdm_a_din0", "tdm_a_din1", "tdm_a_fs", "tdm_a_sclk",
>> + "tdm_a_slv_fs", "tdm_a_slv_sclk", "tdm_a_dout0", "tdm_a_dout1",
>> +};
>> +
>> +static const char * const uart_a_groups[] = {
>> + "uart_a_tx", "uart_a_rx", "uart_a_cts", "uart_a_rts",
>> +};
>> +
>> +static const char * const uart_b_groups[] = {
>> + "uart_b_tx_x", "uart_b_rx_x", "uart_b_tx_f", "uart_b_rx_f",
>> +};
>> +
>> +static const char * const uart_c_groups[] = {
>> + "uart_c_tx_x0", "uart_c_rx_x1", "uart_c_cts", "uart_c_rts",
>> + "uart_c_tx_x15", "uart_c_rx_x16",
>> +};
>> +
>> +static const char * const i2c0_groups[] = {
>> + "i2c0_sck_f11", "i2c0_sda_f12", "i2c0_sck_f9", "i2c0_sda_f10",
>> +};
>> +
>> +static const char * const i2c1_groups[] = {
>> + "i2c1_sda_x", "i2c1_sck_x", "i2c1_sda_a", "i2c1_sck_a",
>> +};
>> +
>> +static const char * const i2c2_groups[] = {
>> + "i2c2_sck_x0", "i2c2_sda_x1", "i2c2_sck_x15", "i2c2_sda_x16",
>> + "i2c2_sck_a4", "i2c2_sda_a5", "i2c2_sck_a8", "i2c2_sda_a9",
>> +};
>> +
>> +static const char * const i2c3_groups[] = {
>> + "i2c3_sck_x", "i2c3_sda_x", "i2c3_sck_f", "i2c3_sda_f",
>> +};
>> +
>> +static const char * const i2c_slave_groups[] = {
>> + "i2c_slave_sda_a", "i2c_slave_sck_a",
>> + "i2c_slave_sda_f", "i2c_slave_sck_f",
>> +};
>> +
>> +static const char * const spi_a_groups[] = {
>> + "spi_a_mosi_x2", "spi_a_ss0_x3", "spi_a_sclk_x4", "spi_a_miso_x5",
>> + "spi_a_mosi_x7", "spi_a_miso_x8", "spi_a_ss0_x9", "spi_a_sclk_x10",
>> +
>> + "spi_a_mosi_a", "spi_a_miso_a", "spi_a_ss0_a", "spi_a_sclk_a",
>> +};
>> +
>> +static const char * const pdm_groups[] = {
>> + "pdm_din0_x", "pdm_din1_x", "pdm_din2_x", "pdm_dclk_x", "pdm_din2_a",
>> + "pdm_din1_a", "pdm_din0_a", "pdm_dclk",
>> +};
>> +
>> +static const char * const gen_clk_groups[] = {
>> + "gen_clk_x", "gen_clk_f8", "gen_clk_f10", "gen_clk_a",
>> +};
>> +
>> +static const char * const remote_input_groups[] = {
>> + "remote_input_f",
>> + "remote_input_a",
>> +};
>> +
>> +static const char * const jtag_a_groups[] = {
>> + "jtag_a_clk", "jtag_a_tms", "jtag_a_tdi", "jtag_a_tdo",
>> +};
>> +
>> +static const char * const clk_32k_in_groups[] = {
>> + "clk_32k_in",
>> +};
>> +
>> +static const char * const remote_out_groups[] = {
>> + "remote_out",
>> +};
>> +
>> +static const char * const spdif_in_groups[] = {
>> + "spdif_in_f6", "spdif_in_f7",
>> +};
>> +
>> +static const char * const sw_groups[] = {
>> + "swclk", "swdio",
>> +};
>> +
>> +static const char * const clk25_groups[] = {
>> + "clk_25",
>> +};
>> +
>> +static const char * const cec_a_groups[] = {
>> + "cec_a",
>> +};
>> +
>> +static const char * const cec_b_groups[] = {
>> + "cec_b",
>> +};
>> +
>> +static const char * const clk12_24_groups[] = {
>> + "clk12_24",
>> +};
>> +
>> +static const char * const mclk_0_groups[] = {
>> + "mclk_0",
>> +};
>> +
>> +static const char * const tdm_b_groups[] = {
>> + "tdm_b_din0", "tdm_b_din1", "tdm_b_din2",
>> + "tdm_b_sclk", "tdm_b_fs", "tdm_b_dout0", "tdm_b_dout1",
>> + "tdm_b_dout2", "tdm_b_dout3", "tdm_b_dout4", "tdm_b_dout5",
>> + "tdm_b_slv_sclk", "tdm_b_slv_fs",
>> +};
>> +
>> +static const char * const mclk_vad_groups[] = {
>> + "mclk_vad",
>> +};
>> +
>> +static const char * const tdm_vad_groups[] = {
>> + "tdm_vad_sclk_a1", "tdm_vad_fs_a2", "tdm_vad_sclk_a5", "tdm_vad_fs_a6",
>> +};
>> +
>> +static const char * const tst_out_groups[] = {
>> + "tst_out0", "tst_out1", "tst_out2", "tst_out3",
>> + "tst_out4", "tst_out5", "tst_out6", "tst_out7",
>> + "tst_out8", "tst_out9", "tst_out10", "tst_out11",
>> +};
>> +
>> +static const char * const mute_groups[] = {
>> + "mute_key", "mute_en",
>> +};
>> +
>> +static struct meson_pmx_func meson_a1_periphs_functions[] = {
>> + FUNCTION(gpio_periphs),
>> + FUNCTION(psram),
>> + FUNCTION(pwm_a),
>> + FUNCTION(pwm_b),
>> + FUNCTION(pwm_c),
>> + FUNCTION(pwm_d),
>> + FUNCTION(pwm_e),
>> + FUNCTION(pwm_f),
>> + FUNCTION(pwm_a_hiz),
>> + FUNCTION(pwm_b_hiz),
>> + FUNCTION(pwm_c_hiz),
>> + FUNCTION(spif),
>> + FUNCTION(sdcard),
>> + FUNCTION(tdm_a),
>> + FUNCTION(uart_a),
>> + FUNCTION(uart_b),
>> + FUNCTION(uart_c),
>> + FUNCTION(i2c0),
>> + FUNCTION(i2c1),
>> + FUNCTION(i2c2),
>> + FUNCTION(i2c3),
>> + FUNCTION(spi_a),
>> + FUNCTION(pdm),
>> + FUNCTION(gen_clk),
>> + FUNCTION(remote_input),
>> + FUNCTION(jtag_a),
>> + FUNCTION(clk_32k_in),
>> + FUNCTION(remote_out),
>> + FUNCTION(spdif_in),
>> + FUNCTION(sw),
>> + FUNCTION(clk25),
>> + FUNCTION(cec_a),
>> + FUNCTION(cec_b),
>> + FUNCTION(clk12_24),
>> + FUNCTION(mclk_0),
>> + FUNCTION(tdm_b),
>> + FUNCTION(mclk_vad),
>> + FUNCTION(tdm_vad),
>> + FUNCTION(tst_out),
>> + FUNCTION(mute),
>> +};
>> +
>> +static struct meson_bank meson_a1_periphs_banks[] = {
>> + /* name first last irq pullen pull dir out in ds*/
>> + BANK_DS("P", GPIOP_0, GPIOP_12, 0, 12, 0x3, 0, 0x4, 0,
>> + 0x2, 0, 0x1, 0, 0x0, 0, 0x5, 0),
>> + BANK_DS("B", GPIOB_0, GPIOB_6, 13, 19, 0x13, 0, 0x14, 0,
>> + 0x12, 0, 0x11, 0, 0x10, 0, 0x15, 0),
>> + BANK_DS("X", GPIOX_0, GPIOX_16, 20, 36, 0x23, 0, 0x24, 0,
>> + 0x22, 0, 0x21, 0, 0x20, 0, 0x25, 0),
>> + BANK_DS("F", GPIOF_0, GPIOF_12, 37, 49, 0x33, 0, 0x34, 0,
>> + 0x32, 0, 0x31, 0, 0x30, 0, 0x35, 0),
>> + BANK_DS("A", GPIOA_0, GPIOA_11, 50, 61, 0x43, 0, 0x44, 0,
>> + 0x42, 0, 0x41, 0, 0x40, 0, 0x45, 0),
>> +};
>> +
>> +static struct meson_pmx_bank meson_a1_periphs_pmx_banks[] = {
>> + /* name first lask reg offset */
>> + BANK_PMX("P", GPIOP_0, GPIOP_12, 0x0, 0),
>> + BANK_PMX("B", GPIOB_0, GPIOB_6, 0x2, 0),
>> + BANK_PMX("X", GPIOX_0, GPIOX_16, 0x3, 0),
>> + BANK_PMX("F", GPIOF_0, GPIOF_12, 0x6, 0),
>> + BANK_PMX("A", GPIOA_0, GPIOA_11, 0x8, 0),
>> +};
>> +
>> +static struct meson_axg_pmx_data meson_a1_periphs_pmx_banks_data = {
>> + .pmx_banks = meson_a1_periphs_pmx_banks,
>> + .num_pmx_banks = ARRAY_SIZE(meson_a1_periphs_pmx_banks),
>> +};
>> +
>> +static struct meson_pinctrl_data meson_a1_periphs_pinctrl_data = {
>> + .name = "periphs-banks",
>> + .pins = meson_a1_periphs_pins,
>> + .groups = meson_a1_periphs_groups,
>> + .funcs = meson_a1_periphs_functions,
>> + .banks = meson_a1_periphs_banks,
>> + .num_pins = ARRAY_SIZE(meson_a1_periphs_pins),
>> + .num_groups = ARRAY_SIZE(meson_a1_periphs_groups),
>> + .num_funcs = ARRAY_SIZE(meson_a1_periphs_functions),
>> + .num_banks = ARRAY_SIZE(meson_a1_periphs_banks),
>> + .pmx_ops = &meson_axg_pmx_ops,
>> + .pmx_data = &meson_a1_periphs_pmx_banks_data,
>> + .reg_layout = A1_LAYOUT,
>> +};
>> +
>> +static const struct of_device_id meson_a1_pinctrl_dt_match[] = {
>> + {
>> + .compatible = "amlogic,meson-a1-periphs-pinctrl",
>> + .data = &meson_a1_periphs_pinctrl_data,
>> + },
>> + { },
>> +};
>> +
>> +static struct platform_driver meson_a1_pinctrl_driver = {
>> + .probe = meson_pinctrl_probe,
>> + .driver = {
>> + .name = "meson-a1-pinctrl",
>> + .of_match_table = meson_a1_pinctrl_dt_match,
>> + },
>> +};
>> +
>> +builtin_platform_driver(meson_a1_pinctrl_driver);
>> diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
>> index 8bba9d0..885b89d 100644
>> --- a/drivers/pinctrl/meson/pinctrl-meson.c
>> +++ b/drivers/pinctrl/meson/pinctrl-meson.c
>> @@ -688,8 +688,12 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
>>
>> pc->reg_ds = meson_map_resource(pc, gpio_np, "ds");
>> if (IS_ERR(pc->reg_ds)) {
>> - dev_dbg(pc->dev, "ds registers not found - skipping\n");
>> - pc->reg_ds = NULL;
>> + if (pc->data->reg_layout == A1_LAYOUT) {
>
> If the ds_reg is not used in A1_LAYOUT, simply avoid mapping it and mark
> it unneeded for A1 SoCs in the bindings instead.
>
>> + pc->reg_ds = pc->reg_pullen;
>> + } else {
>> + dev_dbg(pc->dev, "ds registers not found - skipping\n");
>> + pc->reg_ds = NULL;
>> + }
>> }
>>
>> return 0;
>> diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
>> index c696f32..3d0c58d 100644
>> --- a/drivers/pinctrl/meson/pinctrl-meson.h
>> +++ b/drivers/pinctrl/meson/pinctrl-meson.h
>> @@ -80,6 +80,14 @@ enum meson_pinconf_drv {
>> };
>>
>> /**
>> + * enum meson_reg_layout - identify two types of reg layout
>> + */
>> +enum meson_reg_layout {
>> + LEGACY_LAYOUT,
>> + A1_LAYOUT,
>> +};
>> +
>> +/**
>> * struct meson bank
>> *
>> * @name: bank name
>> @@ -114,6 +122,7 @@ struct meson_pinctrl_data {
>> unsigned int num_banks;
>> const struct pinmux_ops *pmx_ops;
>> void *pmx_data;
>> + unsigned int reg_layout;
>> };
>>
>> struct meson_pinctrl {
>>
>
> Apart that look good to me,
>
> Neil
>
> .
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [breakage] panic() does not halt arm64 systems under certain conditions
From: Russell King - ARM Linux admin @ 2019-09-17 10:51 UTC (permalink / raw)
To: Will Deacon
Cc: linux-arch, gregkh, Xogium, linux-kernel, mingo, bp, tglx,
linux-arm-kernel
In-Reply-To: <20190917104518.ovg6ivadyst7h76o@willie-the-truck>
On Tue, Sep 17, 2019 at 11:45:19AM +0100, Will Deacon wrote:
> Hi,
>
> [Expanding CC list; original message is here:
> https://lore.kernel.org/linux-arm-kernel/BX1W47JXPMR8.58IYW53H6M5N@dragonstone/]
>
> On Mon, Sep 16, 2019 at 09:35:36PM -0400, Xogium wrote:
> > On arm64 in some situations userspace will continue running even after a
> > panic. This means any userspace watchdog daemon will continue pinging,
> > that service managers will keep running and displaying messages in certain
> > cases, and that it is possible to enter via ssh in the now unstable system
> > and to do almost anything except reboot/power off and etc. If
> > CONFIG_PREEMPT=n is set in the kernel's configuration, the issue is fixed.
> > I have reproduced the very same behavior with linux 4.19, 5.2 and 5.3. On
> > x86/x86_64 the issue does not seem to be present at all.
>
> I've managed to reproduce this under both 32-bit and 64-bit ARM kernels.
> The issue is that the infinite loop at the end of panic() can run with
> preemption enabled (particularly when invoking by echoing 'c' to
> /proc/sysrq-trigger), so we end up rescheduling user tasks. On x86, this
> doesn't happen because smp_send_stop() disables the local APIC in
> native_stop_other_cpus() and so interrupts are effectively masked while
> spinning.
>
> A straightforward fix is to disable preemption explicitly on the panic()
> path (diff below), but I've expanded the cc list to see both what others
> think,
Yep, and it looks like this bug goes back into the dim and distant past.
At least to the start of modern git history, 2.6.12-rc2.
> but also in case smp_send_stop() is supposed to have the side-effect
> of disabling interrupt delivery for the local CPU.
That can't fix it. Consider a preemptive non-SMP kernel.
smp_send_stop() becomes a no-op there.
I'd suggest that a preemptive UP kernel on x86 hardware will suffer
this same issue - it will be able to preempt out of this loop and
continue running userspace.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [breakage] panic() does not halt arm64 systems under certain conditions
From: Will Deacon @ 2019-09-17 10:45 UTC (permalink / raw)
To: Xogium
Cc: linux-arch, gregkh, linux-kernel, linux, mingo, bp, tglx,
linux-arm-kernel
In-Reply-To: <BX1W47JXPMR8.58IYW53H6M5N@dragonstone>
Hi,
[Expanding CC list; original message is here:
https://lore.kernel.org/linux-arm-kernel/BX1W47JXPMR8.58IYW53H6M5N@dragonstone/]
On Mon, Sep 16, 2019 at 09:35:36PM -0400, Xogium wrote:
> On arm64 in some situations userspace will continue running even after a
> panic. This means any userspace watchdog daemon will continue pinging,
> that service managers will keep running and displaying messages in certain
> cases, and that it is possible to enter via ssh in the now unstable system
> and to do almost anything except reboot/power off and etc. If
> CONFIG_PREEMPT=n is set in the kernel's configuration, the issue is fixed.
> I have reproduced the very same behavior with linux 4.19, 5.2 and 5.3. On
> x86/x86_64 the issue does not seem to be present at all.
I've managed to reproduce this under both 32-bit and 64-bit ARM kernels.
The issue is that the infinite loop at the end of panic() can run with
preemption enabled (particularly when invoking by echoing 'c' to
/proc/sysrq-trigger), so we end up rescheduling user tasks. On x86, this
doesn't happen because smp_send_stop() disables the local APIC in
native_stop_other_cpus() and so interrupts are effectively masked while
spinning.
A straightforward fix is to disable preemption explicitly on the panic()
path (diff below), but I've expanded the cc list to see both what others
think, but also in case smp_send_stop() is supposed to have the side-effect
of disabling interrupt delivery for the local CPU.
Will
--->8
diff --git a/kernel/panic.c b/kernel/panic.c
index 057540b6eee9..02d0de31c42d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -179,6 +179,7 @@ void panic(const char *fmt, ...)
* after setting panic_cpu) from invoking panic() again.
*/
local_irq_disable();
+ preempt_disable_notrace();
/*
* It's possible to come here directly from a panic-assertion and
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox