Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] ARM: dts: add Raspberry Pi Compute Module and IO board
From: Stefan Wahren @ 2018-05-21 19:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87d0xouapx.fsf@anholt.net>

> Eric Anholt <eric@anholt.net> hat am 21. Mai 2018 um 20:26 geschrieben:
> 
> 
> Stefan Wahren <stefan.wahren@i2se.com> writes:
> 
> > The Raspberry Pi Compute Module (CM1) is a SoM which contains a
> > BCM2835 processor, 512 MB RAM and a 4 GB eMMC. There is also a carrier
> > board which is called Compute Module IO Board.
> >
> > Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
> > ---
> >  arch/arm/boot/dts/Makefile                |  1 +
> >  arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 92 +++++++++++++++++++++++++++++++
> >  arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi    | 34 ++++++++++++
> >  3 files changed, 127 insertions(+)
> >  create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
> >  create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
> >
> > diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> > index ec2024e..a9883e8 100644
> > --- a/arch/arm/boot/dts/Makefile
> > +++ b/arch/arm/boot/dts/Makefile
> > @@ -73,6 +73,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
> >  	bcm2835-rpi-b-rev2.dtb \
> >  	bcm2835-rpi-b-plus.dtb \
> >  	bcm2835-rpi-a-plus.dtb \
> > +	bcm2835-rpi-cm1-io1.dtb \
> >  	bcm2836-rpi-2-b.dtb \
> >  	bcm2837-rpi-3-b.dtb \
> >  	bcm2837-rpi-3-b-plus.dtb \
> > diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
> > new file mode 100644
> > index 0000000..4d9aa22
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
> > @@ -0,0 +1,92 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/dts-v1/;
> > +#include "bcm2835-rpi-cm1.dtsi"
> > +#include "bcm283x-rpi-usb-host.dtsi"
> > +
> > +/ {
> > +	compatible = "raspberrypi,compute-module", "brcm,bcm2835";
> > +	model = "Raspberry Pi Compute Module IO board rev1";
> > +};
> > +
> > +&dsi1 {
> > +	status = "okay";
> > +};
> > +
> > +&gpio {
> > +	/*
> > +	 * This is based on the official GPU firmware DT blob.
> > +	 *
> > +	 * Legend:
> > +	 * "NC" = not connected (no rail from the SoC)
> > +	 * "FOO" = GPIO line named "FOO" on the schematic
> > +	 * "FOO_N" = GPIO line named "FOO" on schematic, active low
> > +	 */
> > +	gpio-line-names = "GPIO0",
> > +			  "GPIO1",
> > +			  "GPIO2",
> > +			  "GPIO3",
> > +			  "GPIO4",
> > +			  "GPIO5",
> > +			  "GPIO6",
> > +			  "GPIO7",
> > +			  "GPIO8",
> > +			  "GPIO9",
> > +			  "GPIO10",
> > +			  "GPIO11",
> > +			  "GPIO12",
> > +			  "GPIO13",
> > +			  "GPIO14",
> > +			  "GPIO15",
> > +			  "GPIO16",
> > +			  "GPIO17",
> > +			  "GPIO18",
> > +			  "GPIO19",
> > +			  "GPIO20",
> > +			  "GPIO21",
> > +			  "GPIO22",
> > +			  "GPIO23",
> > +			  "GPIO24",
> > +			  "GPIO25",
> > +			  "GPIO26",
> > +			  "GPIO27",
> > +			  "GPIO28",
> > +			  "GPIO29",
> > +			  "GPIO30",
> > +			  "GPIO31",
> > +			  "GPIO32",
> > +			  "GPIO33",
> > +			  "GPIO34",
> > +			  "GPIO35",
> > +			  "GPIO36",
> > +			  "GPIO37",
> > +			  "GPIO38",
> > +			  "GPIO39",
> > +			  "GPIO40",
> > +			  "GPIO41",
> > +			  "GPIO42",
> > +			  "GPIO43",
> > +			  "GPIO44",
> > +			  "GPIO45",
> > +			  "HDMI_HPD_N",
> > +			  /* Also used as ACT LED */
> > +			  "EMMC_EN_N",
> > +			  /* Used by eMMC */
> > +			  "SD_CLK_R",
> > +			  "SD_CMD_R",
> > +			  "SD_DATA0_R",
> > +			  "SD_DATA1_R",
> > +			  "SD_DATA2_R",
> > +			  "SD_DATA3_R";
> > +
> > +	pinctrl-0 = <&gpioout &alt0>;
> > +};
> > +
> > +&hdmi {
> > +	hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
> > +};
> 
> I think this should be ACTIVE_LOW, since it's "HDMI_HPD_N_1V8", right?

I just copy & paste from the rpi-4.14/bcm2708-rpi-cm.dts. I thought the HDMI interface on my IO board is broken, but maybe this is a downstream issue.

> 
> > +
> > +&uart0 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&uart0_gpio14>;
> > +	status = "okay";
> > +};
> > diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
> > new file mode 100644
> > index 0000000..ef22c2d
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
> > @@ -0,0 +1,34 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/dts-v1/;
> > +#include "bcm2835.dtsi"
> > +#include "bcm2835-rpi.dtsi"
> > +
> > +/ {
> > +	leds {
> > +		act {
> > +			gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
> > +		};
> > +	};
> > +
> > +	reg_3v3: fixed-regulator {
> > +		compatible = "regulator-fixed";
> > +		regulator-name = "3V3";
> > +		regulator-min-microvolt = <3300000>;
> > +		regulator-max-microvolt = <3300000>;
> > +		regulator-always-on;
> > +	};
> > +
> > +	reg_1v8: fixed-regulator {
> > +		compatible = "regulator-fixed";
> > +		regulator-name = "1V8";
> > +		regulator-min-microvolt = <1800000>;
> > +		regulator-max-microvolt = <1800000>;
> > +		regulator-always-on;
> > +	};
> > +};
> > +
> > +&sdhost {
> > +	non-removable;
> > +	vmmc-supply = <&reg_3v3>;
> > +	vqmmc-supply = <&reg_1v8>;
> > +};
> 
> Also, looking at some datasheets I have laying around, it says "eMMC I/O
> Voltage fixed at 1V8" -- is this regulator setup right, in that case?

Usually an eMMC has 2 different voltage sources:
vqmmc-supply -> supply node for IO line power (usually switchable, but fixed on Compute Module)
vmmc-supply -> supply node for card's power (usually fixed)

Do you have a specific concern (voltage, naming)?

Does this conversation help [1]?

Please also look at the CM schematics page 1 and 3.

[1] - https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=213772

> 
> With answers for these two issues, it will be:
> 
> Reviewed-by: Eric Anholt <eric@anholt.net>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 2/2] rtc: brcmstb-waketimer: add range
From: Florian Fainelli @ 2018-05-21 19:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180520202730.28172-2-alexandre.belloni@bootlin.com>

On 05/20/2018 01:27 PM, Alexandre Belloni wrote:
> Let the core handle the range.
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
-- 
Florian

^ permalink raw reply

* [PATCH 1/2] rtc: brcmstb-waketimer: switch to rtc_register_device
From: Florian Fainelli @ 2018-05-21 19:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180520202730.28172-1-alexandre.belloni@bootlin.com>

On 05/20/2018 01:27 PM, Alexandre Belloni wrote:
> Switch to devm_rtc_allocate_device/rtc_register_device.
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply

* [PATCH v2] arm: bcm2835: Add the PMU to the devicetree.
From: Stefan Wahren @ 2018-05-21 18:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521183907.27563-1-eric@anholt.net>


> Eric Anholt <eric@anholt.net> hat am 21. Mai 2018 um 20:39 geschrieben:
> 
> 
> This only probes on arm64 so far, but hopefully that driver will be
> generalized soon.
> 
> Signed-off-by: Eric Anholt <eric@anholt.net>

Acked-by: Stefan Wahren <stefan.wahren@i2se.com>

^ permalink raw reply

* [PATCHv2] drivers/perf: arm-ccn: don't log to dmesg in event_init
From: Kim Phillips @ 2018-05-21 18:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521171949.31412-1-mark.rutland@arm.com>

[adding LKML, linux-perf-users.  Please do so from now on]

On Mon, 21 May 2018 18:19:49 +0100
Mark Rutland <mark.rutland@arm.com> wrote:

> The ARM CCN PMU driver uses dev_warn() to complain about parameters in
> the user-provided perf_event_attr. This means that under normal
> operation (e.g. a single invocation of the perf tool), a number of
> messages warnings may be logged to dmesg.
> 
> Tools may issue multiple syscalls to probe for feature support, and
> multiple applications (from multiple users) can attempt to open events
> simultaneously, so this is not very helpful, even if a user happens to
> have access to dmesg. Worse, this can push important information out of
> the dmesg ring buffer, and can significantly slow down syscall fuzzers,
> vastly increasing the time it takes to find critical bugs.
> 
> Demote the dev_warn() instances to dev_dbg(), as is the case for all
> other PMU drivers under drivers/perf/. Users who wish to debug PMU event
> initialisation can enable dynamic debug to receive these messages.
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> ---

Care to address my comments to the rationale?:

https://marc.info/?l=linux-arm-kernel&m=152582291919277&w=2

Thanks,

Kim

^ permalink raw reply

* Delivery Status Notification (Failure)
From: Pintu Kumar @ 2018-05-21 18:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOuPNLiaAc16BoMQ=EiqWiyMs14MP4YPOTUf42XbUs2xNYzUUg@mail.gmail.com>

Dear Lucas,

Can you give me some pointers on how to set affinity for entire GPIO Bank.
Currently I am exploring drivers/gpio/gpio-mxc.c to find out how the
GPIO banks are set up.

I also found that affinity can be set using: desc->irq_data.affinity,
may be by using cpumask_copy(...).
But still I am not familiar with this.

So, I need your help.


Thank You!

Regards,
Pintu



On Thu, May 17, 2018 at 6:58 PM, Pintu Kumar <pintu.ping@gmail.com> wrote:
> On Mon, May 14, 2018 at 7:58 PM, Pintu Kumar <pintu.ping@gmail.com> wrote:
>>
>> On Mon, May 14, 2018 at 6:41 PM, Lucas Stach <l.stach@pengutronix.de> wrote:
>> > Am Montag, den 14.05.2018, 17:42 +0530 schrieb Pintu Kumar:
>> >> Hi,
>> >>
>> >> Is there any work around possible to set IRQ affinity for some GPIO
>> >> interrupt ?
>> >> How to avoid CPU0 to receive the current GPIO interrupt ?
>> >> How do we assign GPIO interrupts to any CPU other than CPU0 ?
>> >> Is it possible to isolate CPU0 for a sometime, from my GPIO driver so
>> >> that GPIO interrupt can be served by another CPU ?
>> >>
>> >> Need your inputs to decide whether it is still possible to set
>> >> affinity for GPIO interrupt, or its impossible ?
>> >
>> > This is not possible. The GPIO IRQs are aggregated into one GPC/GIC IRQ
>> > line per GPIO bank, so it is not possible to change affinity of a
>> > single GPIO interrupt to another CPU.
>>
>> OK. Thanks for your confirmation.
>>
>> > Best we could do is change the
>> > affinity of the whole bank,
>>
>
> Hi,
>
> I found that the driver is responsible for setting GPIO bank in i.MX7:
> https://elixir.bootlin.com/linux/v4.2/source/drivers/gpio/gpio-mxc.c
>
> However I still dont know how to set the cpumask for one of the GPIO Bank.
>
> From this link, it seems it is possible to set affinity for a GPIO IRQ.
> https://community.nxp.com/thread/303144
>
> But when I try it form my GPIO138 (GPIO5_IO10) it did not help.
>
> So, as you said, I wanted to change affinity for the whole GPIO bank and try it.
> Please give me some pointers.
>
> Thanks
>
>
>> OK. How can we do this on the fly from my driver code.
>> If you have any reference please let me know.
>> This is required only for experimental purpose to prove the point to be mgmt.
>> My idea is, from the driver, change the affinity of the whole bank.
>> So, the GPIO interrupt can be delivered on to this specific CPU bank.
>> Once I am done, I will revert back to the old bank.
>> Please give me some hint on how to do this from my kernel module....
>>
>>
>> > but given the limited usefulness of
>> > something like that, nobody bothered to implement such a thing.
>> >
>> > Regards,
>> > Lucas
>> >
>> >>
>> >>
>> >> On Fri, May 11, 2018 at 8:07 PM, Pintu Kumar <pintu.ping@gmail.com>
>> >> wrote:
>> >> > On Fri, May 11, 2018 at 6:34 PM, Lucas Stach <l.stach@pengutronix.d
>> >> > e> wrote:
>> >> > > Am Freitag, den 11.05.2018, 13:39 +0100 schrieb Russell King -
>> >> > > ARM Linux:
>> >> > > > On Fri, May 11, 2018 at 05:07:37PM +0530, Pintu Kumar wrote:
>> >> > > > > Hi,
>> >> > > > >
>> >> > > > > I need one help.
>> >> > > > > I am using i.MX7 Sabre board with kernel version 4.1.15
>> >> > > > >
>> >> > > > > Let's say I am interested in GPIO number: 21
>> >> > > > > I wanted to set CPU affinity for particular GPIO->IRQ number,
>> >> > > > > so I
>> >> > > > > tried the below steps:
>> >> > > > > root at 10:~# echo 21 > /sys/class/gpio/export
>> >> > > > > root at 10:~# echo "rising" > /sys/class/gpio/gpio21/edge
>> >> > > > > root at 10:~# cat /proc/interrupts | grep 21
>> >> > > > >   47: 0 0 gpio-mxc 21 Edge gpiolib
>> >> > > > > root at 10:~# cat /sys/class/gpio/gpio21/direction
>> >> > > > > in
>> >> > > > > root at 10:~# cat /proc/irq/47/smp_affinity
>> >> > > > > 3
>> >> > > > > root at 10:~# echo 2 > /proc/irq/47/smp_affinity
>> >> > > > > -bash: echo: write error: Input/output error
>> >> > > > >
>> >> > > > > But I get input/output error.
>> >> > > > > When I debug further, found that irq_can_set_affinity is
>> >> > > > > returning 0:
>> >> > > > > [    0.000000] genirq: irq_can_set_affinity (0): balance: 1,
>> >> > > > > irq_data.chip: a81b7e48, irq_set_affinity:   (null)
>> >> > > > > [    0.000000] write_irq_affinity: FAIL
>> >> > > > >
>> >> > > > > I also tried first setting /proc/irq/default_smp_affinity to
>> >> > > > > 2 (from 3).
>> >> > > > > This change is working, but the smp_affinity setting for the
>> >> > > > > new IRQ
>> >> > > > > is not working.
>> >> > > > >
>> >> > > > > When I try to set smp_affinity for mmc0, then it works.
>> >> > > > > # cat /proc/interrupts | grep mmc
>> >> > > > > 295:         55          0     GPCV2  22 Edge      mmc0
>> >> > > > > 296:          0          0     GPCV2  23 Edge      mmc1
>> >> > > > > 297:         52          0     GPCV2  24 Edge      mmc2
>> >> > > > >
>> >> > > > > root at 10:~# echo 2 > /proc/irq/295/smp_affinity
>> >> > > > > root at 10:~#
>> >> > > > >
>> >> > > > >
>> >> > > > > So, I wanted to know what are the conditions for which
>> >> > > > > setting
>> >> > > > > smp_affinity for an IRQ will work ?
>> >> > > > >
>> >> > > > > Is there any way by which I can set CPU affinity to a GPIO ->
>> >> > > > > IRQ ?
>> >> > > > > Whether, irq_set_affinity_hint() will work in this case ?
>> >> > > >
>> >> > > > IRQ affinity is only supported where interrupts are _directly_
>> >> > > > wired to
>> >> > > > the GIC.  It's the GIC which does the interrupt steering to the
>> >> > > > CPU
>> >> > > > cores.
>> >> > > >
>> >> > > > Interrupts on downstream interrupt controllers (such as GPCV2)
>> >> > > > have no
>> >> > > > ability to be directed independently to other CPUs - the only
>> >> > > > possible
>> >> > > > way to change the mapping is to move _all_ interrupts on that
>> >> > > > controller,
>> >> > > > and any downstream chained interrupts at GIC level.
>> >> > > >
>> >> > > > Hence why Interrupt 295 has no irq_set_affinity function: there
>> >> > > > is no way
>> >> > > > for the interrupt controller itself to change the affinity of
>> >> > > > the input
>> >> > > > interrupt.
>> >> > >
>> >> > > The GPCv2 though is a secondary IRQ controller which has a 1:1
>> >> > > mapping
>> >> > > of its input IRQs to the upstream GIC IRQ lines. Affinity can
>> >> > > thus be
>> >> > > handled by forwarding the request to the GIC by
>> >> > > irq_chip_set_affinity_parent().
>> >> > >
>> >> > > As this is handled correctly in the upstream kernel since the
>> >> > > first
>> >> > > commit introducing support for the GPCv2, it seems the issue is
>> >> > > only
>> >> > > present in some downstream kernel.
>> >> > >
>> >> >
>> >> > OK. Thanks so much for your reply.
>> >> >
>> >> > I saw some of the drivers using irq_set_affinity_hint() to force
>> >> > the
>> >> > IRQ affinity to a particular CPU.
>> >> > This is the sample:
>> >> > {
>> >> > cpumask_clear(mask);
>> >> > cpumask_set_cpu(cpu, mask);
>> >> > irq_set_affinity_hint(irq, mask);
>> >> > }
>> >> >
>> >> > Whether this logic will work for a particular GPIO pin ?
>> >> >
>
>
>>
>> >> >
>> >> > > Regards,
>> >> > > Lucas

^ permalink raw reply

* [PATCH] iommu/io-pgtable-arm: Make allocations NUMA-aware
From: Will Deacon @ 2018-05-21 18:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b745ecc2acd6aad20b5c3776ecd58022a9019c91.1526926225.git.robin.murphy@arm.com>

On Mon, May 21, 2018 at 07:12:40PM +0100, Robin Murphy wrote:
> We would generally expect pagetables to be read by the IOMMU more than
> written by the CPU, so in NUMA systems it would be preferable to avoid
> the IOMMU making cross-node pagetable walks if possible. We already have
> a handle on the IOMMU device for the sake of coherency management, so
> it's trivial to grab the appropriate NUMA node when allocating new
> pagetable pages.
> 
> Note that we drop the semantics of alloc_pages_exact(), but that's fine
> since they have never been necessary: the only time we're allocating
> more than one page is for stage 2 top-level concatenation, but since
> that is based on the number of IPA bits, the size is always some exact
> power of two anyway.
> 
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
>  drivers/iommu/io-pgtable-arm.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
> index 39c2a056da21..e80ca386c5b4 100644
> --- a/drivers/iommu/io-pgtable-arm.c
> +++ b/drivers/iommu/io-pgtable-arm.c
> @@ -231,12 +231,16 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
>  				    struct io_pgtable_cfg *cfg)
>  {
>  	struct device *dev = cfg->iommu_dev;
> +	int order = get_order(size);
> +	struct page *p;
>  	dma_addr_t dma;
> -	void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO);
> +	void *pages;
>  
> -	if (!pages)
> +	p = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, order);
> +	if (!p)
>  		return NULL;
>  
> +	pages = page_address(p);

Might be worth checking/masking out __GFP_HIGHMEM if we see it, since we
could theoretically run into trouble if we got back a highmem mapping here
and we're losing the check in __get_free_pages afaict.

Other than than, looks good:

Acked-by: Will Deacon <will.deacon@arm.com>

Will

^ permalink raw reply

* [PATCH v2] arm: bcm2835: Add the PMU to the devicetree.
From: Eric Anholt @ 2018-05-21 18:39 UTC (permalink / raw)
  To: linux-arm-kernel

This only probes on arm64 so far, but hopefully that driver will be
generalized soon.

Signed-off-by: Eric Anholt <eric@anholt.net>
---
 arch/arm/boot/dts/bcm2837.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi
index 7704bb029605..beb6c502dadc 100644
--- a/arch/arm/boot/dts/bcm2837.dtsi
+++ b/arch/arm/boot/dts/bcm2837.dtsi
@@ -17,6 +17,12 @@
 		};
 	};
 
+	arm-pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupt-parent = <&local_intc>;
+		interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupt-parent = <&local_intc>;
-- 
2.17.0

^ permalink raw reply related

* [PATCH RFC] ARM: dts: add Raspberry Pi Compute Module and IO board
From: Eric Anholt @ 2018-05-21 18:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526589872-13459-1-git-send-email-stefan.wahren@i2se.com>

Stefan Wahren <stefan.wahren@i2se.com> writes:

> The Raspberry Pi Compute Module (CM1) is a SoM which contains a
> BCM2835 processor, 512 MB RAM and a 4 GB eMMC. There is also a carrier
> board which is called Compute Module IO Board.
>
> Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
> ---
>  arch/arm/boot/dts/Makefile                |  1 +
>  arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 92 +++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi    | 34 ++++++++++++
>  3 files changed, 127 insertions(+)
>  create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
>  create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
>
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index ec2024e..a9883e8 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -73,6 +73,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
>  	bcm2835-rpi-b-rev2.dtb \
>  	bcm2835-rpi-b-plus.dtb \
>  	bcm2835-rpi-a-plus.dtb \
> +	bcm2835-rpi-cm1-io1.dtb \
>  	bcm2836-rpi-2-b.dtb \
>  	bcm2837-rpi-3-b.dtb \
>  	bcm2837-rpi-3-b-plus.dtb \
> diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
> new file mode 100644
> index 0000000..4d9aa22
> --- /dev/null
> +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
> @@ -0,0 +1,92 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/dts-v1/;
> +#include "bcm2835-rpi-cm1.dtsi"
> +#include "bcm283x-rpi-usb-host.dtsi"
> +
> +/ {
> +	compatible = "raspberrypi,compute-module", "brcm,bcm2835";
> +	model = "Raspberry Pi Compute Module IO board rev1";
> +};
> +
> +&dsi1 {
> +	status = "okay";
> +};
> +
> +&gpio {
> +	/*
> +	 * This is based on the official GPU firmware DT blob.
> +	 *
> +	 * Legend:
> +	 * "NC" = not connected (no rail from the SoC)
> +	 * "FOO" = GPIO line named "FOO" on the schematic
> +	 * "FOO_N" = GPIO line named "FOO" on schematic, active low
> +	 */
> +	gpio-line-names = "GPIO0",
> +			  "GPIO1",
> +			  "GPIO2",
> +			  "GPIO3",
> +			  "GPIO4",
> +			  "GPIO5",
> +			  "GPIO6",
> +			  "GPIO7",
> +			  "GPIO8",
> +			  "GPIO9",
> +			  "GPIO10",
> +			  "GPIO11",
> +			  "GPIO12",
> +			  "GPIO13",
> +			  "GPIO14",
> +			  "GPIO15",
> +			  "GPIO16",
> +			  "GPIO17",
> +			  "GPIO18",
> +			  "GPIO19",
> +			  "GPIO20",
> +			  "GPIO21",
> +			  "GPIO22",
> +			  "GPIO23",
> +			  "GPIO24",
> +			  "GPIO25",
> +			  "GPIO26",
> +			  "GPIO27",
> +			  "GPIO28",
> +			  "GPIO29",
> +			  "GPIO30",
> +			  "GPIO31",
> +			  "GPIO32",
> +			  "GPIO33",
> +			  "GPIO34",
> +			  "GPIO35",
> +			  "GPIO36",
> +			  "GPIO37",
> +			  "GPIO38",
> +			  "GPIO39",
> +			  "GPIO40",
> +			  "GPIO41",
> +			  "GPIO42",
> +			  "GPIO43",
> +			  "GPIO44",
> +			  "GPIO45",
> +			  "HDMI_HPD_N",
> +			  /* Also used as ACT LED */
> +			  "EMMC_EN_N",
> +			  /* Used by eMMC */
> +			  "SD_CLK_R",
> +			  "SD_CMD_R",
> +			  "SD_DATA0_R",
> +			  "SD_DATA1_R",
> +			  "SD_DATA2_R",
> +			  "SD_DATA3_R";
> +
> +	pinctrl-0 = <&gpioout &alt0>;
> +};
> +
> +&hdmi {
> +	hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
> +};

I think this should be ACTIVE_LOW, since it's "HDMI_HPD_N_1V8", right?

> +
> +&uart0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart0_gpio14>;
> +	status = "okay";
> +};
> diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
> new file mode 100644
> index 0000000..ef22c2d
> --- /dev/null
> +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/dts-v1/;
> +#include "bcm2835.dtsi"
> +#include "bcm2835-rpi.dtsi"
> +
> +/ {
> +	leds {
> +		act {
> +			gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
> +		};
> +	};
> +
> +	reg_3v3: fixed-regulator {
> +		compatible = "regulator-fixed";
> +		regulator-name = "3V3";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +		regulator-always-on;
> +	};
> +
> +	reg_1v8: fixed-regulator {
> +		compatible = "regulator-fixed";
> +		regulator-name = "1V8";
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +		regulator-always-on;
> +	};
> +};
> +
> +&sdhost {
> +	non-removable;
> +	vmmc-supply = <&reg_3v3>;
> +	vqmmc-supply = <&reg_1v8>;
> +};

Also, looking at some datasheets I have laying around, it says "eMMC I/O
Voltage fixed at 1V8" -- is this regulator setup right, in that case?

With answers for these two issues, it will be:

Reviewed-by: Eric Anholt <eric@anholt.net>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/aced93f8/attachment.sig>

^ permalink raw reply

* [PATCH v3 0/5]
From: Will Deacon @ 2018-05-21 18:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180518143913.26306-1-marc.zyngier@arm.com>

Hi Marc,

Thanks for this.

On Fri, May 18, 2018 at 03:39:08PM +0100, Marc Zyngier wrote:
> PMUv3 has been introduced with ARMv8 and, while it has only been used
> on 64bit systems so far, it would definitely be useful for 32bit
> guests running under KVM/arm64, for example.
> 
> There is also the case of people natively running 32bit kernels on
> 64bit HW and trying to upstream unspeakable hacks, hoping that the
> stars will align and that they'll win the lottery (see [1]).
> 
> So let's try again, and make the PMUv3 driver usable for everyone.
> 
> This is done in three steps:
> (1) Move the driver from arch/arm64 to drivers/perf
> (2) Add a handful of system register accessors so that we can reuse
>     the driver on 32bit
> (3) Provide the same accessors on 32bit, enable compilation, and
>     make it the default selection for mach-virt.
> 
> Tested on a Seattle box with 32bit guests.

I think we should go ahead with something like this, but I don't think
we're quite there with these patches. If we're going to move the arch code
out into drivers, let's do that for the perf_event* files under arch/arm/
as well. Then we could have a structure along the lines of:


  drivers/perf/arm_pmu.c			- As it is today
  drivers/perf/arm_cpu/xscale_pmu.c		- Only builds for 32-bit
  drivers/perf/arm_cpu/armv6_pmu.c		- Only builds for 32-bit
  drivers/perf/arm_cpu/arch_pmu.c		- Works for v7/v8 on
                                                  both 32-bit and 64-bit

The latter can then pull in whatever accessors it needs from the arch
code headers.

I know it's more of an invasive change, but this way we always end up
running the same code on the two architectures and it will be much easier
to maintain.

Will

^ permalink raw reply

* [PATCH] arm64: Kconfig: Enable LSE atomics by default
From: Will Deacon @ 2018-05-21 18:14 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're seeing CPUs shipping with LSE atomics, default them to
'on' in Kconfig. CPUs without the instructions will continue to use
LDXR/STXR-based sequences, but they will be placed out-of-line by the
compiler.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/Kconfig | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 4d98774cf3c7..3aed13626fd7 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1051,6 +1051,7 @@ config ARM64_PAN
 
 config ARM64_LSE_ATOMICS
 	bool "Atomic instructions"
+	default y
 	help
 	  As part of the Large System Extensions, ARMv8.1 introduces new
 	  atomic instructions that are designed specifically to scale in
@@ -1059,7 +1060,8 @@ config ARM64_LSE_ATOMICS
 	  Say Y here to make use of these instructions for the in-kernel
 	  atomic routines. This incurs a small overhead on CPUs that do
 	  not support these instructions and requires the kernel to be
-	  built with binutils >= 2.25.
+	  built with binutils >= 2.25 in order for the new instructions
+	  to be used.
 
 config ARM64_VHE
 	bool "Enable support for Virtualization Host Extensions (VHE)"
-- 
2.1.4

^ permalink raw reply related

* [PATCH] iommu/io-pgtable-arm: Make allocations NUMA-aware
From: Robin Murphy @ 2018-05-21 18:12 UTC (permalink / raw)
  To: linux-arm-kernel

We would generally expect pagetables to be read by the IOMMU more than
written by the CPU, so in NUMA systems it would be preferable to avoid
the IOMMU making cross-node pagetable walks if possible. We already have
a handle on the IOMMU device for the sake of coherency management, so
it's trivial to grab the appropriate NUMA node when allocating new
pagetable pages.

Note that we drop the semantics of alloc_pages_exact(), but that's fine
since they have never been necessary: the only time we're allocating
more than one page is for stage 2 top-level concatenation, but since
that is based on the number of IPA bits, the size is always some exact
power of two anyway.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/io-pgtable-arm.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 39c2a056da21..e80ca386c5b4 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -231,12 +231,16 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
 				    struct io_pgtable_cfg *cfg)
 {
 	struct device *dev = cfg->iommu_dev;
+	int order = get_order(size);
+	struct page *p;
 	dma_addr_t dma;
-	void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO);
+	void *pages;
 
-	if (!pages)
+	p = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, order);
+	if (!p)
 		return NULL;
 
+	pages = page_address(p);
 	if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) {
 		dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE);
 		if (dma_mapping_error(dev, dma))
@@ -256,7 +260,7 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
 	dev_err(dev, "Cannot accommodate DMA translation for IOMMU page tables\n");
 	dma_unmap_single(dev, dma, size, DMA_TO_DEVICE);
 out_free:
-	free_pages_exact(pages, size);
+	__free_pages(p, order);
 	return NULL;
 }
 
@@ -266,7 +270,7 @@ static void __arm_lpae_free_pages(void *pages, size_t size,
 	if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA))
 		dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages),
 				 size, DMA_TO_DEVICE);
-	free_pages_exact(pages, size);
+	free_pages((unsigned long)pages, get_order(size));
 }
 
 static void __arm_lpae_sync_pte(arm_lpae_iopte *ptep,
-- 
2.17.0.dirty

^ permalink raw reply related

* [PATCH 1/6] ARM: OMAP1: ams-delta: add GPIO lookup tables
From: Janusz Krzysztofik @ 2018-05-21 18:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521173519.GA98604@atomide.com>

On Monday, May 21, 2018 7:35:19 PM CEST Tony Lindgren wrote:
> Hi,
> 
> * Janusz Krzysztofik <jmkrzyszt@gmail.com> [180518 14:12]:
> > Scope of the change is limited to GPIO pins used by board specific
> > device drivers which will be updated by follow-up patches of the
> > series. Those are some OMAP GPIO (gpio-0-15) and most of Amstrad Delta
> > latch2 GPIO bank pins. Remaining pins of those banks, as well as
> > Amstrad Delta latch1 pins, will be addressed later.
> > 
> > Assign a label ("latch2") to the bank, enumerate its pins and put that
> > information, together with OMAP GPIO bank pins, in GPIO lookup tables.
> > Assign lookup tables to devices as soon as those devices are registered
> > and their names can be obtained.
> > 
> > A step froward in:
> > - removal of hard-coded GPIO numbers from drivers,
> > - removal of board mach includes from drivers,
> > - switching to dynamically assigned GPIO numbers.
> 
> Is this first patch safe for me to apply separately?

Absolutely, it is.

Thanks,
Janusz

^ permalink raw reply

* [PATCH v3 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: Doug Anderson @ 2018-05-21 18:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <dc1fbe9c-8973-1c4d-0fbd-809c1ec0a6be@codeaurora.org>

Hi,

On Fri, May 18, 2018 at 5:46 PM, David Collins <collinsd@codeaurora.org> wrote:
> On 05/17/2018 06:01 PM, Doug Anderson wrote:
>> On Thu, May 17, 2018 at 5:16 PM, David Collins <collinsd@codeaurora.org> wrote:
>>> On 05/17/2018 02:22 PM, Doug Anderson wrote:
>>>> On Fri, May 11, 2018 at 7:28 PM, David Collins <collinsd@codeaurora.org> wrote:
>>>>> +- qcom,regulator-initial-microvolt
>>>>> +       Usage:      optional; VRM regulators only
>>>>> +       Value type: <u32>
>>>>> +       Definition: Specifies the initial voltage in microvolts to request for a
>>>>> +                   VRM regulator.
>>>>
>>>> Now that Mark has landed the patch adding support for the
>>>> -ENOTRECOVERABLE error code from get_voltage() / get_voltage_sel(), do
>>>> we still need the qcom,regulator-initial-microvolt property?
>>>
>>> Yes, this is still needed.  The -ENOTRECOVERABLE patch ensures that
>>> qcom-rpmh-regulator devices can be registered even if
>>> qcom,regulator-initial-microvolt is not specified.  However, that will
>>> result in the regulators being configured for the minimum voltage
>>> supported in the DT specified min/max range.  The
>>> qcom,regulator-initial-microvolt property allows us to set a specific
>>> voltage that is larger than the min constraint.
>>
>> Ah, OK.  In the device tree fragment I saw the initial was always
>> equal to the min, so I wasn't sure if this was really needed in
>> practice.  I presume it would only be important if a voltage was left
>> high by the bootloader for some peripheral that needs to continue to
>> function (and use the existing higher voltage) until a real device
>> claims it.  For all other voltages, it should be fine if it's set to
>> the min until a real device claims it.  Do you have real examples of
>> devices like this in boards using sdm845?
>
> Something to keep in mind about the downstream rpmh-regulator driver is
> that it caches the initial voltages specified in device tree and only
> sends them after a consumer driver makes a regulator framework call. This
> saves time during boot and ensures that requests are not made for
> regulators that no Linux consumer cares about.

You're saying that in the downstream driver you'd specify
"initial-voltage" in the device tree and:

* This voltage would be reported by any subsequent get_voltage() calls

* This voltage would _not_ be communicated to RPMh.

That seems really strange because you're essentially going to be
returning something from get_voltage() that could be a lie.  You don't
know if the BIOS actually set the value or not but you'll claim that
it did.  It also doesn't seem to match what I see in the downstream
driver.  There I see it read "qcom,init-voltage" and then do a
"rpmh_regulator_set_reg()".  Thus my reading of the downstream driver
is that it should do the same requests that you're doing.


> It is generally not safe to request all regulators to be set to the
> minimum allowed voltage.  Special care will be needed with the upstream
> qcom-rpmh-regulator driver to avoid disrupting the boot up state of
> regulators that are needed by other subsystems.  Therefore, I would like
> to keep the initial voltage feature supported.

I was asking for specific examples.  Do you have any?


BTW: have I already said how terrible of a design it is that you can't
read back the voltages that the BIOS set?  If we could just read back
what the BIOS set then everything would work great and we could stop
talking about this.


>>>>> +- qcom,allowed-drms-modes
>>>>> +       Usage:      required if regulator-allow-set-load is specified;
>>>>> +                   VRM regulators only
>>>>> +       Value type: <prop-encoded-array>
>>>>> +       Definition: A list of integers specifying the PMIC regulator modes which
>>>>> +                   can be configured at runtime based upon consumer load needs.
>>>>> +                   Supported values are RPMH_REGULATOR_MODE_* which are defined
>>>>> +                   in [1] (i.e. 0 to 3).
>>>>
>>>> Why is this still here?  You moved it to the core regulator framework,
>>>> right?  It's still in your examples too.  Shouldn't this be removed?
>>>> It looks like the driver still needs this and it needs to be an exact
>>>> duplicate of the common binding.  That doesn't seem right...
>>>
>>> The qcom,allowed-drms-modes property supports a different feature than the
>>> regulator-allowed-modes property accepted in [2].  The latter specifies
>>> the modes that may be used at all (e.g. in regulator_set_mode() calls) and
>>> it lists the mode values in an unordered fashion.
>>>
>>> qcom,allowed-drms-modes defines a specific subset of the possible allowed
>>> modes that should be set based on DRMS (e.g. in regulator_set_load()
>>> calls).  Its values are listed in a specific order and must match 1-to-1
>>> with qcom,drms-mode-max-microamps entries.
>>>
>>> It would probably be good to change the name of the property from
>>> qcom,allowed-drms-modes to qcom,regulator-drms-modes.
>>
>> Ah, I see.  It's unfortunate that now we need to effectively list all
>> modes twice.  Have you seen real-life examples where these sets of
>> modes need to be different, or is this just theoretical?  If not can
>> we start with one property (that controls both things) and if we
>> really see that we need to specify different sets of modes for the two
>> cases we can add a separate property?  ...actually, even if you do
>> have real-life examples of where these need to be different, if 90% of
>> the time they are the same it would still be nice to just have one
>> property apply to both cases.
>
> I plan to keep qcom,regulator-drms-modes (and
> qcom,drms-mode-max-microamps) around as a property specifically handled
> for qcom-rpmh-regulator.  It serves a purpose that is distinct from that
> of the generic regulator-allowed-modes.  Without it, there will not be a
> way to utilize regulator_set_load() to configure the regulator modes.

I guess we'll have to wait for Mark's opinion here.  If it were up to
me I wouldn't accept things with two properties, but if Mark is happy
with it then I won't yell.  To make it really clear what we're talking
about, currently the bindings want you to specify both:

regulator-allowed-modes =
  <RPMH_REGULATOR_MODE_LPM
   RPMH_REGULATOR_MODE_HPM>;
qcom,allowed-drms-modes =
  <RPMH_REGULATOR_MODE_LPM
   RPMH_REGULATOR_MODE_HPM>;
qcom,drms-mode-max-microamps = <1 500000>;

...with the argument that "regulator-allowed-modes" is unordered and
"qcom,allowed-drms-modes" is ordered and needs to match with
"qcom,drms-mode-max-microamps".  ...and also (in theory) you could
come up with an example where the set of allowed modes could be
different sometimes.


>>>>> +- qcom,drms-mode-max-microamps
>>>>> +       Usage:      required if regulator-allow-set-load is specified;
>>>>> +                   VRM regulators only
>>>>> +       Value type: <prop-encoded-array>
>>>>> +       Definition: A list of integers specifying the maximum allowed load
>>>>> +                   current in microamps for each of the modes listed in
>>>>> +                   qcom,allowed-drms-modes (matched 1-to-1 in order).  Elements
>>>>> +                   must be specified in order from lowest to highest value.
>>>>
>>>> Any reason this can't go into the regulator core?  You'd basically
>>>> just take the existing concept of rpmh_regulator_vrm_set_load() and
>>>> put it in the core.
>>>
>>> This could be implemented in the core via new constraint elements parsed
>>> in of_regulator and a helper function to specify in regulator_ops.
>>> However, I'm not sure about the wide-spread applicability of this feature.
>>>  I'd prefer to leave it in the driver unless Mark would like me to add it
>>> into the core.
>>
>> You're already using pre-existing APIs around specifying the current
>> and having the regulator core call you to map the total current into a
>> mode.  That implies that this is applicable to others.  Adding this
>> tiny amount of code to the core makes the pre-existing APIs generally
>> useful.
>
> I don't see the benefit of making struct regulation_constraints more
> complicated with DRMS mode and current arrays that would only every be
> used by the qcom-rpmh-regulator driver.  Other regulator drivers are able
> to hard code this information in the driver code using get_optimum_mode()
> callbacks.

IMO this belongs in the core since it's a generic mechanism and if
drivers want to implement their own custom thing they can, but again
whatever Mark says goes so I guess we'll leave it to him.


> As a side note, changing qcom-rpmh-regulator to use a get_optimum_mode()
> callback instead of a set_load() callback would probably be a good idea too.

Yeah, I remember wondering this earlier and it seemed like it was 6 of
one half dozen of the other.  ...the downside of using
get_optimum_mode() is that it requires a valid input voltage to be
supplied.  It also makes a handful of other calls that you probably
don't need in your case.


-Doug

^ permalink raw reply

* [PATCH 12/33] clk: bcm2835: use match_string() helper
From: Eric Anholt @ 2018-05-21 17:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526903890-35761-13-git-send-email-xieyisheng1@huawei.com>

Yisheng Xie <xieyisheng1@huawei.com> writes:

> match_string() returns the index of an array for a matching string,
> which can be used intead of open coded variant.
>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: Eric Anholt <eric@anholt.net>
> Cc: Stefan Wahren <stefan.wahren@i2se.com>
> Cc: linux-clk at vger.kernel.org
> Cc: linux-rpi-kernel at lists.infradead.org
> Cc: linux-arm-kernel at lists.infradead.org
> Signed-off-by: Yisheng Xie <xieyisheng1@huawei.com>
> ---
>  drivers/clk/bcm/clk-bcm2835.c | 14 ++++++--------
>  1 file changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> index fa0d5c8..a27c0d2 100644
> --- a/drivers/clk/bcm/clk-bcm2835.c
> +++ b/drivers/clk/bcm/clk-bcm2835.c
> @@ -1395,8 +1395,7 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
>  	struct bcm2835_clock *clock;
>  	struct clk_init_data init;
>  	const char *parents[1 << CM_SRC_BITS];
> -	size_t i, j;
> -	int ret;
> +	int i, ret;
>  
>  	/*
>  	 * Replace our strings referencing parent clocks with the
> @@ -1405,12 +1404,11 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
>  	for (i = 0; i < data->num_mux_parents; i++) {
>  		parents[i] = data->parents[i];
>  
> -		for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) {
> -			if (strcmp(parents[i], cprman_parent_names[j]) == 0) {
> -				parents[i] = cprman->real_parent_names[j];
> -				break;
> -			}
> -		}
> +		ret = match_string(cprman_parent_names,
> +				   ARRAY_SIZE(cprman_parent_names),
> +				   parents[i]);
> +		if (ret >= 0)
> +			parents[i] = cprman->real_parent_names[ret];

Reviewed-by: Eric Anholt <eric@anholt.net>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/d011e272/attachment.sig>

^ permalink raw reply

* [PATCH 1/6] ARM: OMAP1: ams-delta: add GPIO lookup tables
From: Tony Lindgren @ 2018-05-21 17:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180518210954.29044-1-jmkrzyszt@gmail.com>

Hi,

* Janusz Krzysztofik <jmkrzyszt@gmail.com> [180518 14:12]:
> Scope of the change is limited to GPIO pins used by board specific
> device drivers which will be updated by follow-up patches of the
> series. Those are some OMAP GPIO (gpio-0-15) and most of Amstrad Delta
> latch2 GPIO bank pins. Remaining pins of those banks, as well as
> Amstrad Delta latch1 pins, will be addressed later.
> 
> Assign a label ("latch2") to the bank, enumerate its pins and put that
> information, together with OMAP GPIO bank pins, in GPIO lookup tables.
> Assign lookup tables to devices as soon as those devices are registered
> and their names can be obtained.
> 
> A step froward in:
> - removal of hard-coded GPIO numbers from drivers,
> - removal of board mach includes from drivers,
> - switching to dynamically assigned GPIO numbers.

Is this first patch safe for me to apply separately?

Regards,

Tony

^ permalink raw reply

* [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top
From: Jernej Škrabec @ 2018-05-21 17:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521080759.rgviuva65ijcfm2e@flea>

Hi,

Dne ponedeljek, 21. maj 2018 ob 10:07:59 CEST je Maxime Ripard napisal(a):
> On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
> > If SoC has TCON TOP unit, it has to be configured from TCON, since it
> > has all information needed. Additionally, if it is TCON TV, it must also
> > enable bus gate inside TCON TOP unit.
> 
> Why?

I'll explain my design decision below.

> 
> > Add support for such TCONs.
> > 
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > ---
> > 
> >  drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
> >  drivers/gpu/drm/sun4i/sun4i_tcon.h |  8 ++++++++
> >  2 files changed, 36 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 08747fc3ee71..e0c562ce1c22
> > 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> > 
> >  		dev_err(dev, "Couldn't get the TCON bus clock\n");
> >  		return PTR_ERR(tcon->clk);
> >  	
> >  	}
> > 
> > +
> > +	if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
> > +		tcon->top_clk = devm_clk_get(dev, "tcon-top");
> > +		if (IS_ERR(tcon->top_clk)) {
> > +			dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
> > +			return PTR_ERR(tcon->top_clk);
> > +		}
> > +		clk_prepare_enable(tcon->top_clk);
> > +	}
> > +
> > 
> >  	clk_prepare_enable(tcon->clk);
> >  	
> >  	if (tcon->quirks->has_channel_0) {
> > 
> > @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> > 
> >  static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
> >  {
> >  
> >  	clk_disable_unprepare(tcon->clk);
> > 
> > +	clk_disable_unprepare(tcon->top_clk);
> > 
> >  }
> >  
> >  static int sun4i_tcon_init_irq(struct device *dev,
> > 
> > @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct
> > device *master,> 
> >  	tcon->id = engine->id;
> >  	tcon->quirks = of_device_get_match_data(dev);
> > 
> > +	if (tcon->quirks->needs_tcon_top) {
> > +		struct device_node *np;
> > +
> > +		np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> > +		if (np) {
> > +			struct platform_device *pdev;
> > +
> > +			pdev = of_find_device_by_node(np);
> > +			if (pdev)
> > +				tcon->tcon_top = platform_get_drvdata(pdev);
> > +			of_node_put(np);
> > +
> > +			if (!tcon->tcon_top)
> > +				return -EPROBE_DEFER;
> > +		}
> > +	}
> > +
> 
> I might have missed it, but I've not seen the bindings additions for
> that property. This shouldn't really be done that way anyway, instead
> of using a direct phandle, you should be using the of-graph, with the
> TCON-top sitting where it belongs in the flow of data.

Just to answer to the first question, it did describe it in "[PATCH 07/15] dt-
bindings: display: sun4i-drm: Add R40 HDMI pipeline".

As why I designed it that way - HW representation could be described that way 
(ASCII art makes sense when fixed width font is used to view it):

                            / LCD0/LVDS0
                / TCON-LCD0
                |           \ MIPI DSI
mixer0          |
       \        / TCON-LCD1 - LCD1/LVDS1
        TCON-TOP
       /        \ TCON-TV0 - TVE0/RGB
mixer1          |          \
                |           TCON-TOP - HDMI
                |          /
                \ TCON-TV1 - TVE1/RGB

This is a bit simplified, since there is also TVE-TOP, which is responsible 
for sharing 4 DACs between both TVE encoders. You can have two TV outs (PAL/
NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even seems that you 
can arbitrarly choose which DAC is responsible for which signal, so there is a 
ton of possible end combinations, but I'm not 100% sure.

Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual 
suggest more possibilities, although some of them seem wrong, like RGB feeding 
from LCD TCON. That is confirmed to be wrong when checking BSP code. 

Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and LCD1 for 
pin muxing, although I'm not sure why is that needed at all, since according 
to R40 datasheet, TVE0 and TVE1 pins are dedicated and not on PORT D and PORT 
H, respectively, as TCON-TOP documentation suggest. However, HSYNC and PSYNC 
lines might be shared between TVE (when it works in RGB mode) and LCD. But 
that is just my guess since I'm not really familiar with RGB and LCD 
interfaces.

I'm really not sure what would be the best representation in OF-graph. Can you 
suggest one?

On the other hand, mux callback in TCON driver has all available informations 
at hand. It knows mixer ID, TCON ID and most importantly, encoder type. Based 
on all that informations, it's easy to configure TCON TOP.

I hope you understand. If you have better idea, I'm all ears, since phandle 
seems a bit weird to me too, but I think it's the only future proof, when 
adding LVDS, RGB, TVE or LCD support.

Best regards,
Jernej

^ permalink raw reply

* arm64: add missing early clobber in atomic64_dec_if_positive()
From: Will Deacon @ 2018-05-21 17:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c540dd519065316c859e5cb1290de7f5041cb816.camel@redhat.com>

On Mon, May 21, 2018 at 01:18:39PM -0400, Mark Salter wrote:
> On Mon, 2018-05-21 at 18:00 +0100, Will Deacon wrote:
> > Hi Mark,
> > 
> > Thanks for reporting this.
> > 
> > On Sat, May 19, 2018 at 08:17:26PM -0400, Mark Salter wrote:
> > > When running a kernel compiled with gcc8 on a machine using LSE, I
> > > get:
> > > 
> > >  Unable to handle kernel paging request at virtual address 11111122222221
> > 
> > [...]
> > 
> > > The fault happens at the casal insn of inlined atomic64_dec_if_positive().
> > > The inline asm code in that function has:
> > > 
> > > 	"1:	ldr	x30, %[v]\n"
> > > 	"	subs	%[ret], x30, #1\n"
> > > 	"	b.lt	2f\n"
> > > 	"	casal	x30, %[ret], %[v]\n"
> > > 	"	sub	x30, x30, #1\n"
> > > 	"	sub	x30, x30, %[ret]\n"
> > > 	"	cbnz	x30, 1b\n"
> > > 	"2:")
> > > 	: [ret] "+r" (x0), [v] "+Q" (v->counter)
> > > 
> > > gcc8 used register x0 for both [ret] and [v] and the subs was
> > > clobbering [v] before it was used for casal. Gcc is free to do
> > > this because [ret] lacks an early clobber modifier. So add one
> > > to tell gcc a separate register is needed for [v].
> > 
> > Oh blimey, it looks like GCC is realising that counter is at offset 0
> > of atomic_t and therefore assigns the same register for [ret] and [v],
> > which is actually forced to be x0 by the 'register' local variable in
> > C code. The "+Q" constraint only says that the memory is read/write, so
> > the pointer is fair game.
> > 
> > I agree with your fix, but we also need to fix up the other places relying
> > on this. Patch below -- please yell if you think I missed any.
> 
> I looked at the other places but figured they were okay because we're
> explicitly using separate registers. But I suppose the early clobber
> is the right thing to do in any case.

I was worried about silly things like a caller doing:

  atomic64_and((long)v, v);

and then GCC figuring out that the two values were equal and allocating
the same register..

Will

^ permalink raw reply

* [PATCHv2] drivers/perf: arm-ccn: don't log to dmesg in event_init
From: Mark Rutland @ 2018-05-21 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

The ARM CCN PMU driver uses dev_warn() to complain about parameters in
the user-provided perf_event_attr. This means that under normal
operation (e.g. a single invocation of the perf tool), a number of
messages warnings may be logged to dmesg.

Tools may issue multiple syscalls to probe for feature support, and
multiple applications (from multiple users) can attempt to open events
simultaneously, so this is not very helpful, even if a user happens to
have access to dmesg. Worse, this can push important information out of
the dmesg ring buffer, and can significantly slow down syscall fuzzers,
vastly increasing the time it takes to find critical bugs.

Demote the dev_warn() instances to dev_dbg(), as is the case for all
other PMU drivers under drivers/perf/. Users who wish to debug PMU event
initialisation can enable dynamic debug to receive these messages.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 drivers/perf/arm-ccn.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

Since v1 [1]:
* tidy up commit message.

Mark

[1] https://lkml.kernel.org/r/20180504104117.8086-1-mark.rutland at arm.com

diff --git a/drivers/perf/arm-ccn.c b/drivers/perf/arm-ccn.c
index 65b7e4042ece..07771e28f572 100644
--- a/drivers/perf/arm-ccn.c
+++ b/drivers/perf/arm-ccn.c
@@ -736,7 +736,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
 	ccn = pmu_to_arm_ccn(event->pmu);
 
 	if (hw->sample_period) {
-		dev_warn(ccn->dev, "Sampling not supported!\n");
+		dev_dbg(ccn->dev, "Sampling not supported!\n");
 		return -EOPNOTSUPP;
 	}
 
@@ -744,12 +744,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
 			event->attr.exclude_kernel || event->attr.exclude_hv ||
 			event->attr.exclude_idle || event->attr.exclude_host ||
 			event->attr.exclude_guest) {
-		dev_warn(ccn->dev, "Can't exclude execution levels!\n");
+		dev_dbg(ccn->dev, "Can't exclude execution levels!\n");
 		return -EINVAL;
 	}
 
 	if (event->cpu < 0) {
-		dev_warn(ccn->dev, "Can't provide per-task data!\n");
+		dev_dbg(ccn->dev, "Can't provide per-task data!\n");
 		return -EOPNOTSUPP;
 	}
 	/*
@@ -771,13 +771,13 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
 	switch (type) {
 	case CCN_TYPE_MN:
 		if (node_xp != ccn->mn_id) {
-			dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp);
+			dev_dbg(ccn->dev, "Invalid MN ID %d!\n", node_xp);
 			return -EINVAL;
 		}
 		break;
 	case CCN_TYPE_XP:
 		if (node_xp >= ccn->num_xps) {
-			dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp);
+			dev_dbg(ccn->dev, "Invalid XP ID %d!\n", node_xp);
 			return -EINVAL;
 		}
 		break;
@@ -785,11 +785,11 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
 		break;
 	default:
 		if (node_xp >= ccn->num_nodes) {
-			dev_warn(ccn->dev, "Invalid node ID %d!\n", node_xp);
+			dev_dbg(ccn->dev, "Invalid node ID %d!\n", node_xp);
 			return -EINVAL;
 		}
 		if (!arm_ccn_pmu_type_eq(type, ccn->node[node_xp].type)) {
-			dev_warn(ccn->dev, "Invalid type 0x%x for node %d!\n",
+			dev_dbg(ccn->dev, "Invalid type 0x%x for node %d!\n",
 					type, node_xp);
 			return -EINVAL;
 		}
@@ -808,19 +808,19 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
 		if (event_id != e->event)
 			continue;
 		if (e->num_ports && port >= e->num_ports) {
-			dev_warn(ccn->dev, "Invalid port %d for node/XP %d!\n",
+			dev_dbg(ccn->dev, "Invalid port %d for node/XP %d!\n",
 					port, node_xp);
 			return -EINVAL;
 		}
 		if (e->num_vcs && vc >= e->num_vcs) {
-			dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n",
+			dev_dbg(ccn->dev, "Invalid vc %d for node/XP %d!\n",
 					vc, node_xp);
 			return -EINVAL;
 		}
 		valid = 1;
 	}
 	if (!valid) {
-		dev_warn(ccn->dev, "Invalid event 0x%x for node/XP %d!\n",
+		dev_dbg(ccn->dev, "Invalid event 0x%x for node/XP %d!\n",
 				event_id, node_xp);
 		return -EINVAL;
 	}
-- 
2.11.0

^ permalink raw reply related

* arm64: add missing early clobber in atomic64_dec_if_positive()
From: Mark Salter @ 2018-05-21 17:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521170022.GD21034@arm.com>

On Mon, 2018-05-21 at 18:00 +0100, Will Deacon wrote:
> Hi Mark,
> 
> Thanks for reporting this.
> 
> On Sat, May 19, 2018 at 08:17:26PM -0400, Mark Salter wrote:
> > When running a kernel compiled with gcc8 on a machine using LSE, I
> > get:
> > 
> >  Unable to handle kernel paging request at virtual address 11111122222221
> 
> [...]
> 
> > The fault happens at the casal insn of inlined atomic64_dec_if_positive().
> > The inline asm code in that function has:
> > 
> > 	"1:	ldr	x30, %[v]\n"
> > 	"	subs	%[ret], x30, #1\n"
> > 	"	b.lt	2f\n"
> > 	"	casal	x30, %[ret], %[v]\n"
> > 	"	sub	x30, x30, #1\n"
> > 	"	sub	x30, x30, %[ret]\n"
> > 	"	cbnz	x30, 1b\n"
> > 	"2:")
> > 	: [ret] "+r" (x0), [v] "+Q" (v->counter)
> > 
> > gcc8 used register x0 for both [ret] and [v] and the subs was
> > clobbering [v] before it was used for casal. Gcc is free to do
> > this because [ret] lacks an early clobber modifier. So add one
> > to tell gcc a separate register is needed for [v].
> 
> Oh blimey, it looks like GCC is realising that counter is at offset 0
> of atomic_t and therefore assigns the same register for [ret] and [v],
> which is actually forced to be x0 by the 'register' local variable in
> C code. The "+Q" constraint only says that the memory is read/write, so
> the pointer is fair game.
> 
> I agree with your fix, but we also need to fix up the other places relying
> on this. Patch below -- please yell if you think I missed any.

I looked at the other places but figured they were okay because we're
explicitly using separate registers. But I suppose the early clobber
is the right thing to do in any case.

> 
> Cheers,
> 
> Will
> 
> --->8
> 
> From 3d9417b28ed2588c33b7e54e6681c88f0224201a Mon Sep 17 00:00:00 2001
> From: Will Deacon <will.deacon@arm.com>
> Date: Mon, 21 May 2018 17:44:57 +0100
> Subject: [PATCH] arm64: lse: Add early clobbers to some input/output asm
>  operands
> 
> For LSE atomics that read and write a register operand, we need to
> ensure that these operands are annotated as "early clobber" if the
> register is written before all of the input operands have been consumed.
> Failure to do so can result in the compiler allocating the same register
> to both operands, leading to splats such as:
> 
>  Unable to handle kernel paging request at virtual address 11111122222221
>  [...]
>  x1 : 1111111122222222 x0 : 1111111122222221
>  Process swapper/0 (pid: 1, stack limit = 0x000000008209f908)
>  Call trace:
>   test_atomic64+0x1360/0x155c
> 
> where x0 has been allocated as both the value to be stored and also the
> atomic_t pointer.
> 
> This patch adds the missing clobbers.
> 
> Cc: <stable@vger.kernel.org>
> Cc: Dave Martin <dave.martin@arm.com>
> Cc: Robin Murphy <robin.murphy@arm.com>
> Reported-by: Mark Salter <msalter@redhat.com>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
>  arch/arm64/include/asm/atomic_lse.h | 24 ++++++++++++------------
>  1 file changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
> index 9ef0797380cb..f9b0b09153e0 100644
> --- a/arch/arm64/include/asm/atomic_lse.h
> +++ b/arch/arm64/include/asm/atomic_lse.h
> @@ -117,7 +117,7 @@ static inline void atomic_and(int i, atomic_t *v)
>  	/* LSE atomics */
>  	"	mvn	%w[i], %w[i]\n"
>  	"	stclr	%w[i], %[v]")
> -	: [i] "+r" (w0), [v] "+Q" (v->counter)
> +	: [i] "+&r" (w0), [v] "+Q" (v->counter)
>  	: "r" (x1)
>  	: __LL_SC_CLOBBERS);
>  }
> @@ -135,7 +135,7 @@ static inline int atomic_fetch_and##name(int i, atomic_t *v)		\
>  	/* LSE atomics */						\
>  	"	mvn	%w[i], %w[i]\n"					\
>  	"	ldclr" #mb "	%w[i], %w[i], %[v]")			\
> -	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
> +	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
>  	: "r" (x1)							\
>  	: __LL_SC_CLOBBERS, ##cl);					\
>  									\
> @@ -161,7 +161,7 @@ static inline void atomic_sub(int i, atomic_t *v)
>  	/* LSE atomics */
>  	"	neg	%w[i], %w[i]\n"
>  	"	stadd	%w[i], %[v]")
> -	: [i] "+r" (w0), [v] "+Q" (v->counter)
> +	: [i] "+&r" (w0), [v] "+Q" (v->counter)
>  	: "r" (x1)
>  	: __LL_SC_CLOBBERS);
>  }
> @@ -180,7 +180,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v)		\
>  	"	neg	%w[i], %w[i]\n"					\
>  	"	ldadd" #mb "	%w[i], w30, %[v]\n"			\
>  	"	add	%w[i], %w[i], w30")				\
> -	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
> +	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
>  	: "r" (x1)							\
>  	: __LL_SC_CLOBBERS , ##cl);					\
>  									\
> @@ -207,7 +207,7 @@ static inline int atomic_fetch_sub##name(int i, atomic_t *v)		\
>  	/* LSE atomics */						\
>  	"	neg	%w[i], %w[i]\n"					\
>  	"	ldadd" #mb "	%w[i], %w[i], %[v]")			\
> -	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
> +	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
>  	: "r" (x1)							\
>  	: __LL_SC_CLOBBERS, ##cl);					\
>  									\
> @@ -314,7 +314,7 @@ static inline void atomic64_and(long i, atomic64_t *v)
>  	/* LSE atomics */
>  	"	mvn	%[i], %[i]\n"
>  	"	stclr	%[i], %[v]")
> -	: [i] "+r" (x0), [v] "+Q" (v->counter)
> +	: [i] "+&r" (x0), [v] "+Q" (v->counter)
>  	: "r" (x1)
>  	: __LL_SC_CLOBBERS);
>  }
> @@ -332,7 +332,7 @@ static inline long atomic64_fetch_and##name(long i, atomic64_t *v)	\
>  	/* LSE atomics */						\
>  	"	mvn	%[i], %[i]\n"					\
>  	"	ldclr" #mb "	%[i], %[i], %[v]")			\
> -	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
> +	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
>  	: "r" (x1)							\
>  	: __LL_SC_CLOBBERS, ##cl);					\
>  									\
> @@ -358,7 +358,7 @@ static inline void atomic64_sub(long i, atomic64_t *v)
>  	/* LSE atomics */
>  	"	neg	%[i], %[i]\n"
>  	"	stadd	%[i], %[v]")
> -	: [i] "+r" (x0), [v] "+Q" (v->counter)
> +	: [i] "+&r" (x0), [v] "+Q" (v->counter)
>  	: "r" (x1)
>  	: __LL_SC_CLOBBERS);
>  }
> @@ -377,7 +377,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v)	\
>  	"	neg	%[i], %[i]\n"					\
>  	"	ldadd" #mb "	%[i], x30, %[v]\n"			\
>  	"	add	%[i], %[i], x30")				\
> -	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
> +	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
>  	: "r" (x1)							\
>  	: __LL_SC_CLOBBERS, ##cl);					\
>  									\
> @@ -404,7 +404,7 @@ static inline long atomic64_fetch_sub##name(long i, atomic64_t *v)	\
>  	/* LSE atomics */						\
>  	"	neg	%[i], %[i]\n"					\
>  	"	ldadd" #mb "	%[i], %[i], %[v]")			\
> -	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
> +	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
>  	: "r" (x1)							\
>  	: __LL_SC_CLOBBERS, ##cl);					\
>  									\
> @@ -435,7 +435,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
>  	"	sub	x30, x30, %[ret]\n"
>  	"	cbnz	x30, 1b\n"
>  	"2:")
> -	: [ret] "+r" (x0), [v] "+Q" (v->counter)
> +	: [ret] "+&r" (x0), [v] "+Q" (v->counter)
>  	:
>  	: __LL_SC_CLOBBERS, "cc", "memory");
>  
> @@ -516,7 +516,7 @@ static inline long __cmpxchg_double##name(unsigned long old1,		\
>  	"	eor	%[old1], %[old1], %[oldval1]\n"			\
>  	"	eor	%[old2], %[old2], %[oldval2]\n"			\
>  	"	orr	%[old1], %[old1], %[old2]")			\
> -	: [old1] "+r" (x0), [old2] "+r" (x1),				\
> +	: [old1] "+&r" (x0), [old2] "+&r" (x1),				\
>  	  [v] "+Q" (*(unsigned long *)ptr)				\
>  	: [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),		\
>  	  [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)		\

^ permalink raw reply

* [PATCH] EDAC, ghes: Make platform-based whitelisting x86-only
From: Borislav Petkov @ 2018-05-21 17:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b1d606dc-527c-6a7d-ce80-a11ac852a5f9@codeaurora.org>

On Mon, May 21, 2018 at 09:48:23AM -0400, Tyler Baicar wrote:
> I don't see an issue with not printing out the long BIOS statement, but the
> number of DIMM sockets print could still be useful.

Well, if you wanna dump the number of DIMMs - then maybe that line
should issue unconditionally. However, "DIMM sockets" is silly - it
should simply say:

	"%d DIMMs detected"

or so.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

^ permalink raw reply

* [PATCH] perf: hisi: fix uncore PMU index ID
From: Will Deacon @ 2018-05-21 17:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526901317-52248-1-git-send-email-zhangshaokun@hisilicon.com>

Hi Shaokun,

[+DT list]

On Mon, May 21, 2018 at 07:15:17PM +0800, Shaokun Zhang wrote:
> According to ACPI SPEC about _UID (Unique ID), The _UID must be unique
> across all devices with either a common _HID or _CID. For HiSilion
> uncore PMU, SCCL_ID and INDEX_ID are used to identify the uncore PMU
> for the same _HID. Therefore, _UID is not equal to INDEX_ID in
> multi-sccl scene for the same uncore PMU device.
> 
> CCL_ID can be used as the INDEX_ID for the L3C PMU and IDX-ID is added
> in DSDT table for the HHA PMU.
> 
> Fixes: 2940bc4("perf: hisi: Add support for HiSilicon SoC L3C PMU driver")
> Fixes: 2bab3cf("perf: hisi: Add support for HiSilicon SoC HHA PMU driver")
> Reported-by: Huiqiang Wang <wanghuiqiang@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Huiqiang Wang <wanghuiqiang@huawei.com>
> ---
>  drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 18 ++++++++----------
>  drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 11 ++---------
>  2 files changed, 10 insertions(+), 19 deletions(-)

Whilst I'd normally just accept PMU driver submissions for vendor PMUs,
this part rang my alarm bells:

> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> index 443906e..dcd8e77 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> @@ -238,19 +238,10 @@ MODULE_DEVICE_TABLE(acpi, hisi_hha_pmu_acpi_match);
>  static int hisi_hha_pmu_init_data(struct platform_device *pdev,
>  				  struct hisi_pmu *hha_pmu)
>  {
> -	unsigned long long id;
>  	struct resource *res;
> -	acpi_status status;
> -
> -	status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
> -				       "_UID", NULL, &id);
> -	if (ACPI_FAILURE(status))
> -		return -EINVAL;
> -
> -	hha_pmu->index_id = id;
>  
>  	/*
> -	 * Use SCCL_ID and UID to identify the HHA PMU, while
> +	 * Use SCCL_ID and HHA index ID to identify the HHA PMU, while
>  	 * SCCL_ID is in MPIDR[aff2].
>  	 */
>  	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
> @@ -258,6 +249,13 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
>  		dev_err(&pdev->dev, "Can not read hha sccl-id!\n");
>  		return -EINVAL;
>  	}
> +
> +	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
> +				     &hha_pmu->index_id)) {
> +		dev_err(&pdev->dev, "Can not read hha index-id!\n");
> +		return -EINVAL;
> +	}

Is this a new DT property? If so, please can you update the binding
documentation and get an Ack from a DT maintainer? It's not clear to me
what a "hisilicon,idx-id" is, nor how I would generate on from firmware.

Thanks,

Will

^ permalink raw reply

* [RHEL-8] arm64: add missing early clobber in atomic64_dec_if_positive()
From: Will Deacon @ 2018-05-21 17:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180520001726.27808-1-msalter@redhat.com>

Hi Mark,

Thanks for reporting this.

On Sat, May 19, 2018 at 08:17:26PM -0400, Mark Salter wrote:
> When running a kernel compiled with gcc8 on a machine using LSE, I
> get:
> 
>  Unable to handle kernel paging request at virtual address 11111122222221

[...]

> The fault happens at the casal insn of inlined atomic64_dec_if_positive().
> The inline asm code in that function has:
> 
> 	"1:	ldr	x30, %[v]\n"
> 	"	subs	%[ret], x30, #1\n"
> 	"	b.lt	2f\n"
> 	"	casal	x30, %[ret], %[v]\n"
> 	"	sub	x30, x30, #1\n"
> 	"	sub	x30, x30, %[ret]\n"
> 	"	cbnz	x30, 1b\n"
> 	"2:")
> 	: [ret] "+r" (x0), [v] "+Q" (v->counter)
> 
> gcc8 used register x0 for both [ret] and [v] and the subs was
> clobbering [v] before it was used for casal. Gcc is free to do
> this because [ret] lacks an early clobber modifier. So add one
> to tell gcc a separate register is needed for [v].

Oh blimey, it looks like GCC is realising that counter is at offset 0
of atomic_t and therefore assigns the same register for [ret] and [v],
which is actually forced to be x0 by the 'register' local variable in
C code. The "+Q" constraint only says that the memory is read/write, so
the pointer is fair game.

I agree with your fix, but we also need to fix up the other places relying
on this. Patch below -- please yell if you think I missed any.

Cheers,

Will

--->8

>From 3d9417b28ed2588c33b7e54e6681c88f0224201a Mon Sep 17 00:00:00 2001
From: Will Deacon <will.deacon@arm.com>
Date: Mon, 21 May 2018 17:44:57 +0100
Subject: [PATCH] arm64: lse: Add early clobbers to some input/output asm
 operands

For LSE atomics that read and write a register operand, we need to
ensure that these operands are annotated as "early clobber" if the
register is written before all of the input operands have been consumed.
Failure to do so can result in the compiler allocating the same register
to both operands, leading to splats such as:

 Unable to handle kernel paging request at virtual address 11111122222221
 [...]
 x1 : 1111111122222222 x0 : 1111111122222221
 Process swapper/0 (pid: 1, stack limit = 0x000000008209f908)
 Call trace:
  test_atomic64+0x1360/0x155c

where x0 has been allocated as both the value to be stored and also the
atomic_t pointer.

This patch adds the missing clobbers.

Cc: <stable@vger.kernel.org>
Cc: Dave Martin <dave.martin@arm.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Reported-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/atomic_lse.h | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
index 9ef0797380cb..f9b0b09153e0 100644
--- a/arch/arm64/include/asm/atomic_lse.h
+++ b/arch/arm64/include/asm/atomic_lse.h
@@ -117,7 +117,7 @@ static inline void atomic_and(int i, atomic_t *v)
 	/* LSE atomics */
 	"	mvn	%w[i], %w[i]\n"
 	"	stclr	%w[i], %[v]")
-	: [i] "+r" (w0), [v] "+Q" (v->counter)
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: __LL_SC_CLOBBERS);
 }
@@ -135,7 +135,7 @@ static inline int atomic_fetch_and##name(int i, atomic_t *v)		\
 	/* LSE atomics */						\
 	"	mvn	%w[i], %w[i]\n"					\
 	"	ldclr" #mb "	%w[i], %w[i], %[v]")			\
-	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: __LL_SC_CLOBBERS, ##cl);					\
 									\
@@ -161,7 +161,7 @@ static inline void atomic_sub(int i, atomic_t *v)
 	/* LSE atomics */
 	"	neg	%w[i], %w[i]\n"
 	"	stadd	%w[i], %[v]")
-	: [i] "+r" (w0), [v] "+Q" (v->counter)
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: __LL_SC_CLOBBERS);
 }
@@ -180,7 +180,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v)		\
 	"	neg	%w[i], %w[i]\n"					\
 	"	ldadd" #mb "	%w[i], w30, %[v]\n"			\
 	"	add	%w[i], %w[i], w30")				\
-	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: __LL_SC_CLOBBERS , ##cl);					\
 									\
@@ -207,7 +207,7 @@ static inline int atomic_fetch_sub##name(int i, atomic_t *v)		\
 	/* LSE atomics */						\
 	"	neg	%w[i], %w[i]\n"					\
 	"	ldadd" #mb "	%w[i], %w[i], %[v]")			\
-	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: __LL_SC_CLOBBERS, ##cl);					\
 									\
@@ -314,7 +314,7 @@ static inline void atomic64_and(long i, atomic64_t *v)
 	/* LSE atomics */
 	"	mvn	%[i], %[i]\n"
 	"	stclr	%[i], %[v]")
-	: [i] "+r" (x0), [v] "+Q" (v->counter)
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: __LL_SC_CLOBBERS);
 }
@@ -332,7 +332,7 @@ static inline long atomic64_fetch_and##name(long i, atomic64_t *v)	\
 	/* LSE atomics */						\
 	"	mvn	%[i], %[i]\n"					\
 	"	ldclr" #mb "	%[i], %[i], %[v]")			\
-	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: __LL_SC_CLOBBERS, ##cl);					\
 									\
@@ -358,7 +358,7 @@ static inline void atomic64_sub(long i, atomic64_t *v)
 	/* LSE atomics */
 	"	neg	%[i], %[i]\n"
 	"	stadd	%[i], %[v]")
-	: [i] "+r" (x0), [v] "+Q" (v->counter)
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: __LL_SC_CLOBBERS);
 }
@@ -377,7 +377,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v)	\
 	"	neg	%[i], %[i]\n"					\
 	"	ldadd" #mb "	%[i], x30, %[v]\n"			\
 	"	add	%[i], %[i], x30")				\
-	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: __LL_SC_CLOBBERS, ##cl);					\
 									\
@@ -404,7 +404,7 @@ static inline long atomic64_fetch_sub##name(long i, atomic64_t *v)	\
 	/* LSE atomics */						\
 	"	neg	%[i], %[i]\n"					\
 	"	ldadd" #mb "	%[i], %[i], %[v]")			\
-	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: __LL_SC_CLOBBERS, ##cl);					\
 									\
@@ -435,7 +435,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
 	"	sub	x30, x30, %[ret]\n"
 	"	cbnz	x30, 1b\n"
 	"2:")
-	: [ret] "+r" (x0), [v] "+Q" (v->counter)
+	: [ret] "+&r" (x0), [v] "+Q" (v->counter)
 	:
 	: __LL_SC_CLOBBERS, "cc", "memory");
 
@@ -516,7 +516,7 @@ static inline long __cmpxchg_double##name(unsigned long old1,		\
 	"	eor	%[old1], %[old1], %[oldval1]\n"			\
 	"	eor	%[old2], %[old2], %[oldval2]\n"			\
 	"	orr	%[old1], %[old1], %[old2]")			\
-	: [old1] "+r" (x0), [old2] "+r" (x1),				\
+	: [old1] "+&r" (x0), [old2] "+&r" (x1),				\
 	  [v] "+Q" (*(unsigned long *)ptr)				\
 	: [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),		\
 	  [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)		\
-- 
2.1.4

^ permalink raw reply related

* [PATCH 1/2] drm/fourcc: add a 10bits fully packed variant of NV12
From: Nicolas Dufresne @ 2018-05-21 16:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521144948.GF23723@intel.com>

Le lundi 21 mai 2018 ? 17:49 +0300, Ville Syrj?l? a ?crit :
> On Mon, May 21, 2018 at 01:17:04AM +0800, Randy Li wrote:
> > This pixel format is a fully packed and 10bits variant of NV12.
> > A luma pixel would take 10bits in memory, without any
> > filled bits between pixels in a stride. The color gamut
> > follows the BT.2020 standard.
> > 
> > Signed-off-by: Randy Li <ayaka@soulik.info>
> > ---
> >  drivers/gpu/drm/drm_fourcc.c  | 1 +
> >  include/uapi/drm/drm_fourcc.h | 3 +++
> >  2 files changed, 4 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_fourcc.c
> > b/drivers/gpu/drm/drm_fourcc.c
> > index 5ca6395cd4d3..1f43967c4013 100644
> > --- a/drivers/gpu/drm/drm_fourcc.c
> > +++ b/drivers/gpu/drm/drm_fourcc.c
> > @@ -173,6 +173,7 @@ const struct drm_format_info
> > *__drm_format_info(u32 format)
> >  		{ .format = DRM_FORMAT_UYVY,		.depth
> > = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
> >  		{ .format = DRM_FORMAT_VYUY,		.depth
> > = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
> >  		{ .format = DRM_FORMAT_AYUV,		.depth
> > = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1,
> > .has_alpha = true },
> > +		{ .format = DRM_FORMAT_NV12_10LE40,	.depth
> > = 0,  .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 },
> >  	};
> >  
> >  	unsigned int i;
> > diff --git a/include/uapi/drm/drm_fourcc.h
> > b/include/uapi/drm/drm_fourcc.h
> > index e04613d30a13..8eabf01e966f 100644
> > --- a/include/uapi/drm/drm_fourcc.h
> > +++ b/include/uapi/drm/drm_fourcc.h
> > @@ -140,6 +140,9 @@ extern "C" {
> >  #define DRM_FORMAT_NV61		fourcc_code('N', 'V', '6',
> > '1') /* 2x1 subsampled Cb:Cr plane */
> >  #define DRM_FORMAT_NV24		fourcc_code('N', 'V', '2',
> > '4') /* non-subsampled Cr:Cb plane */
> >  #define DRM_FORMAT_NV42		fourcc_code('N', 'V', '4',
> > '2') /* non-subsampled Cb:Cr plane */
> > +/* A fully packed variant of NV12_10LE32 */
> 
> What does "fully packed" mean? NV12_10LE32 doesn't even exist so
> referring to it makes no sense.

Fully packed means no padding bits at all, that's quite descriptive.
There is generally only one way to achieve this for a given layout and
format. Referring to NV12_10LE32 GStreamer format isn't very useful,
that I agree. I think Xilinx is submitting it as XV10.

In GStreamer, all the 10bit format naming started to be a mess, so I
encoded something, it's probably not great, but does the job. So when
we say NV12, it mean the YUV 4:2:0 with two planes, 10, means 10bit per
component, LE, for littlen endian, and 40 for 40bit packing length. If
you pack 10bit data over 40bit, you have basically 4 component per 5
bytes.

Unlike XV10 (aka NV12_10LE32), where you have 3 component per 4 bytes,
each 32bit have 3 components, and 2bit are ignored (padding).

> 
> Please try to provide an unambiguous description of new formats like
> we
> have for everything else.
> 
> > +#define DRM_FORMAT_NV12_10LE40	fourcc_code('R', 'K', '2',
> > '0') /* 2x2 subsampled Cr:Cb plane */
> > +
> >  
> >  /*
> >   * 3 plane YCbCr
> > -- 
> > 2.14.3
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/b5ce23df/attachment-0001.sig>

^ permalink raw reply

* Applied "ASoC: qdsp6: q6afe: Add q6afe driver" to the asoc tree
From: Mark Brown @ 2018-05-21 15:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180518125610.26200-2-srinivas.kandagatla@linaro.org>

The patch

   ASoC: qdsp6: q6afe: Add q6afe driver

has been applied to the asoc tree at

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 7fa2d70f976657111a5ea4f3d16a738ddaa10c4f Mon Sep 17 00:00:00 2001
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Date: Fri, 18 May 2018 13:55:56 +0100
Subject: [PATCH] ASoC: qdsp6: q6afe: Add q6afe driver

This patch adds support to Q6AFE (Audio Front End) module on Q6DSP.

AFE module sits right at the other end of cpu where the codec/audio
devices are connected.

AFE provides abstraced interfaces to both hardware and virtual devices.
Each AFE tx/rx port can be configured to connect to one of the hardware
devices like codec, hdmi, slimbus, i2s and so on. AFE services include
starting, stopping, and if needed, any configurations of the ports.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-and-tested-by: Rohit kumar <rohitkr@codeaurora.org>
Reviewed-by: Banajit Goswami <bgoswami@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/qcom/Kconfig        |   4 +
 sound/soc/qcom/qdsp6/Makefile |   1 +
 sound/soc/qcom/qdsp6/q6afe.c  | 549 ++++++++++++++++++++++++++++++++++
 sound/soc/qcom/qdsp6/q6afe.h  |  35 +++
 4 files changed, 589 insertions(+)
 create mode 100644 sound/soc/qcom/qdsp6/q6afe.c
 create mode 100644 sound/soc/qcom/qdsp6/q6afe.h

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 37ee0d958145..bb0a2afb0563 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -47,11 +47,15 @@ config SND_SOC_QDSP6_COMMON
 config SND_SOC_QDSP6_CORE
 	tristate
 
+config SND_SOC_QDSP6_AFE
+	tristate
+
 config SND_SOC_QDSP6
 	tristate "SoC ALSA audio driver for QDSP6"
 	depends on QCOM_APR && HAS_DMA
 	select SND_SOC_QDSP6_COMMON
 	select SND_SOC_QDSP6_CORE
+	select SND_SOC_QDSP6_AFE
 	help
 	 To add support for MSM QDSP6 Soc Audio.
 	 This will enable sound soc platform specific
diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile
index 03b8e89c9731..7ff666bd10ca 100644
--- a/sound/soc/qcom/qdsp6/Makefile
+++ b/sound/soc/qcom/qdsp6/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o
 obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o
+obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
new file mode 100644
index 000000000000..5e0032c13aab
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/soc/qcom/apr.h>
+#include "q6dsp-errno.h"
+#include "q6core.h"
+#include "q6afe.h"
+
+/* AFE CMDs */
+#define AFE_PORT_CMD_DEVICE_START	0x000100E5
+#define AFE_PORT_CMD_DEVICE_STOP	0x000100E6
+#define AFE_PORT_CMD_SET_PARAM_V2	0x000100EF
+#define AFE_SVC_CMD_SET_PARAM		0x000100f3
+#define AFE_PORT_CMDRSP_GET_PARAM_V2	0x00010106
+#define AFE_PARAM_ID_HDMI_CONFIG	0x00010210
+#define AFE_MODULE_AUDIO_DEV_INTERFACE	0x0001020C
+
+/* Port IDs */
+#define AFE_API_VERSION_HDMI_CONFIG	0x1
+#define AFE_PORT_ID_MULTICHAN_HDMI_RX	0x100E
+#define TIMEOUT_MS 1000
+#define AFE_CMD_RESP_AVAIL	0
+#define AFE_CMD_RESP_NONE	1
+
+struct q6afe {
+	struct apr_device *apr;
+	struct device *dev;
+	struct q6core_svc_api_info ainfo;
+	struct mutex lock;
+	struct list_head port_list;
+	spinlock_t port_list_lock;
+	struct platform_device *pdev_dais;
+};
+
+struct afe_port_cmd_device_start {
+	u16 port_id;
+	u16 reserved;
+} __packed;
+
+struct afe_port_cmd_device_stop {
+	u16 port_id;
+	u16 reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.*/
+} __packed;
+
+struct afe_port_param_data_v2 {
+	u32 module_id;
+	u32 param_id;
+	u16 param_size;
+	u16 reserved;
+} __packed;
+
+struct afe_port_cmd_set_param_v2 {
+	u16 port_id;
+	u16 payload_size;
+	u32 payload_address_lsw;
+	u32 payload_address_msw;
+	u32 mem_map_handle;
+} __packed;
+
+struct afe_param_id_hdmi_multi_chan_audio_cfg {
+	u32 hdmi_cfg_minor_version;
+	u16 datatype;
+	u16 channel_allocation;
+	u32 sample_rate;
+	u16 bit_width;
+	u16 reserved;
+} __packed;
+
+union afe_port_config {
+	struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
+} __packed;
+
+struct q6afe_port {
+	wait_queue_head_t wait;
+	union afe_port_config port_cfg;
+	struct aprv2_ibasic_rsp_result_t result;
+	int token;
+	int id;
+	int cfg_type;
+	struct q6afe *afe;
+	struct kref refcount;
+	struct list_head node;
+};
+
+struct afe_port_map {
+	int port_id;
+	int token;
+	int is_rx;
+	int is_dig_pcm;
+};
+
+/*
+ * Mapping between Virtual Port IDs to DSP AFE Port ID
+ * On B Family SoCs DSP Port IDs are consistent across multiple SoCs
+ * on A Family SoCs DSP port IDs are same as virtual Port IDs.
+ */
+
+static struct afe_port_map port_maps[AFE_PORT_MAX] = {
+	[HDMI_RX] = { AFE_PORT_ID_MULTICHAN_HDMI_RX, HDMI_RX, 1, 1},
+};
+
+static void q6afe_port_free(struct kref *ref)
+{
+	struct q6afe_port *port;
+	struct q6afe *afe;
+	unsigned long flags;
+
+	port = container_of(ref, struct q6afe_port, refcount);
+	afe = port->afe;
+	spin_lock_irqsave(&afe->port_list_lock, flags);
+	list_del(&port->node);
+	spin_unlock_irqrestore(&afe->port_list_lock, flags);
+	kfree(port);
+}
+
+static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token)
+{
+	struct q6afe_port *p = NULL;
+	struct q6afe_port *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&afe->port_list_lock, flags);
+	list_for_each_entry(p, &afe->port_list, node)
+		if (p->token == token) {
+			ret = p;
+			kref_get(&p->refcount);
+			break;
+		}
+
+	spin_unlock_irqrestore(&afe->port_list_lock, flags);
+	return ret;
+}
+
+static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data)
+{
+	struct q6afe *afe = dev_get_drvdata(&adev->dev);
+	struct aprv2_ibasic_rsp_result_t *res;
+	struct apr_hdr *hdr = &data->hdr;
+	struct q6afe_port *port;
+
+	if (!data->payload_size)
+		return 0;
+
+	res = data->payload;
+	switch (hdr->opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		if (res->status) {
+			dev_err(afe->dev, "cmd = 0x%x returned error = 0x%x\n",
+				res->opcode, res->status);
+		}
+		switch (res->opcode) {
+		case AFE_PORT_CMD_SET_PARAM_V2:
+		case AFE_PORT_CMD_DEVICE_STOP:
+		case AFE_PORT_CMD_DEVICE_START:
+		case AFE_SVC_CMD_SET_PARAM:
+			port = q6afe_find_port(afe, hdr->token);
+			if (port) {
+				port->result = *res;
+				wake_up(&port->wait);
+				kref_put(&port->refcount, q6afe_port_free);
+			}
+			break;
+		default:
+			dev_err(afe->dev, "Unknown cmd 0x%x\n",	res->opcode);
+			break;
+		}
+	}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * q6afe_get_port_id() - Get port id from a given port index
+ *
+ * @index: port index
+ *
+ * Return: Will be an negative on error or valid port_id on success
+ */
+int q6afe_get_port_id(int index)
+{
+	if (index < 0 || index > AFE_PORT_MAX)
+		return -EINVAL;
+
+	return port_maps[index].port_id;
+}
+EXPORT_SYMBOL_GPL(q6afe_get_port_id);
+
+static int afe_apr_send_pkt(struct q6afe *afe, struct apr_pkt *pkt,
+			    struct q6afe_port *port)
+{
+	wait_queue_head_t *wait = &port->wait;
+	struct apr_hdr *hdr = &pkt->hdr;
+	int ret;
+
+	mutex_lock(&afe->lock);
+	port->result.opcode = 0;
+	port->result.status = 0;
+
+	ret = apr_send_pkt(afe->apr, pkt);
+	if (ret < 0) {
+		dev_err(afe->dev, "packet not transmitted (%d)\n", ret);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = wait_event_timeout(*wait, (port->result.opcode == hdr->opcode),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		ret = -ETIMEDOUT;
+	} else if (port->result.status > 0) {
+		dev_err(afe->dev, "DSP returned error[%x]\n",
+			port->result.status);
+		ret = -EINVAL;
+	} else {
+		ret = 0;
+	}
+
+err:
+	mutex_unlock(&afe->lock);
+
+	return ret;
+}
+
+static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
+				   int param_id, int module_id, int psize)
+{
+	struct afe_port_cmd_set_param_v2 *param;
+	struct afe_port_param_data_v2 *pdata;
+	struct q6afe *afe = port->afe;
+	struct apr_pkt *pkt;
+	u16 port_id = port->id;
+	int ret, pkt_size;
+	void *p, *pl;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	param = p + APR_HDR_SIZE;
+	pdata = p + APR_HDR_SIZE + sizeof(*param);
+	pl = p + APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata);
+	memcpy(pl, data, psize);
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = port->token;
+	pkt->hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+	param->port_id = port_id;
+	param->payload_size = sizeof(*pdata) + psize;
+	param->payload_address_lsw = 0x00;
+	param->payload_address_msw = 0x00;
+	param->mem_map_handle = 0x00;
+	pdata->module_id = module_id;
+	pdata->param_id = param_id;
+	pdata->param_size = psize;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+		       port_id, ret);
+
+	kfree(pkt);
+	return ret;
+}
+
+/**
+ * q6afe_port_stop() - Stop a afe port
+ *
+ * @port: Instance of port to stop
+ *
+ * Return: Will be an negative on packet size on success.
+ */
+int q6afe_port_stop(struct q6afe_port *port)
+{
+	struct afe_port_cmd_device_stop *stop;
+	struct q6afe *afe = port->afe;
+	struct apr_pkt *pkt;
+	int port_id = port->id;
+	int ret = 0;
+	int index, pkt_size;
+	void *p;
+
+	port_id = port->id;
+	index = port->token;
+	if (index < 0 || index > AFE_PORT_MAX) {
+		dev_err(afe->dev, "AFE port index[%d] invalid!\n", index);
+		return -EINVAL;
+	}
+
+	pkt_size = APR_HDR_SIZE + sizeof(*stop);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	stop = p + APR_HDR_SIZE;
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = index;
+	pkt->hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+	stop->port_id = port_id;
+	stop->reserved = 0;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE close failed %d\n", ret);
+
+	kfree(pkt);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6afe_port_stop);
+
+/**
+ * q6afe_hdmi_port_prepare() - Prepare hdmi afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: HDMI configuration for the afe port
+ *
+ */
+void q6afe_hdmi_port_prepare(struct q6afe_port *port,
+			     struct q6afe_hdmi_cfg *cfg)
+{
+	union afe_port_config *pcfg = &port->port_cfg;
+
+	pcfg->hdmi_multi_ch.hdmi_cfg_minor_version =
+					AFE_API_VERSION_HDMI_CONFIG;
+	pcfg->hdmi_multi_ch.datatype = cfg->datatype;
+	pcfg->hdmi_multi_ch.channel_allocation = cfg->channel_allocation;
+	pcfg->hdmi_multi_ch.sample_rate = cfg->sample_rate;
+	pcfg->hdmi_multi_ch.bit_width = cfg->bit_width;
+}
+EXPORT_SYMBOL_GPL(q6afe_hdmi_port_prepare);
+
+/**
+ * q6afe_port_start() - Start a afe port
+ *
+ * @port: Instance of port to start
+ *
+ * Return: Will be an negative on packet size on success.
+ */
+int q6afe_port_start(struct q6afe_port *port)
+{
+	struct afe_port_cmd_device_start *start;
+	struct q6afe *afe = port->afe;
+	int port_id = port->id;
+	int ret, param_id = port->cfg_type;
+	struct apr_pkt *pkt;
+	int pkt_size;
+	void *p;
+
+	ret  = q6afe_port_set_param_v2(port, &port->port_cfg, param_id,
+				       AFE_MODULE_AUDIO_DEV_INTERFACE,
+				       sizeof(port->port_cfg));
+	if (ret) {
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+			port_id, ret);
+		return ret;
+	}
+
+	pkt_size = APR_HDR_SIZE + sizeof(*start);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	start = p + APR_HDR_SIZE;
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					    APR_HDR_LEN(APR_HDR_SIZE),
+					    APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = port->token;
+	pkt->hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+
+	start->port_id = port_id;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+			port_id, ret);
+
+	kfree(pkt);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6afe_port_start);
+
+/**
+ * q6afe_port_get_from_id() - Get port instance from a port id
+ *
+ * @dev: Pointer to afe child device.
+ * @id: port id
+ *
+ * Return: Will be an error pointer on error or a valid afe port
+ * on success.
+ */
+struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
+{
+	int port_id;
+	struct q6afe *afe = dev_get_drvdata(dev->parent);
+	struct q6afe_port *port;
+	unsigned long flags;
+	int cfg_type;
+
+	if (id < 0 || id > AFE_PORT_MAX) {
+		dev_err(dev, "AFE port token[%d] invalid!\n", id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* if port is multiple times bind/unbind before callback finishes */
+	port = q6afe_find_port(afe, id);
+	if (port) {
+		dev_err(dev, "AFE Port already open\n");
+		return port;
+	}
+
+	port_id = port_maps[id].port_id;
+
+	switch (port_id) {
+	case AFE_PORT_ID_MULTICHAN_HDMI_RX:
+		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+		break;
+	default:
+		dev_err(dev, "Invalid port id 0x%x\n", port_id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return ERR_PTR(-ENOMEM);
+
+	init_waitqueue_head(&port->wait);
+
+	port->token = id;
+	port->id = port_id;
+	port->afe = afe;
+	port->cfg_type = cfg_type;
+	kref_init(&port->refcount);
+
+	spin_lock_irqsave(&afe->port_list_lock, flags);
+	list_add_tail(&port->node, &afe->port_list);
+	spin_unlock_irqrestore(&afe->port_list_lock, flags);
+
+	return port;
+
+}
+EXPORT_SYMBOL_GPL(q6afe_port_get_from_id);
+
+/**
+ * q6afe_port_put() - Release port reference
+ *
+ * @port: Instance of port to put
+ */
+void q6afe_port_put(struct q6afe_port *port)
+{
+	kref_put(&port->refcount, q6afe_port_free);
+}
+EXPORT_SYMBOL_GPL(q6afe_port_put);
+
+static int q6afe_probe(struct apr_device *adev)
+{
+	struct q6afe *afe;
+	struct device *dev = &adev->dev;
+	struct device_node *dais_np;
+
+	afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+
+	q6core_get_svc_api_info(adev->svc_id, &afe->ainfo);
+	afe->apr = adev;
+	mutex_init(&afe->lock);
+	afe->dev = dev;
+	INIT_LIST_HEAD(&afe->port_list);
+	spin_lock_init(&afe->port_list_lock);
+
+	dev_set_drvdata(dev, afe);
+
+	dais_np = of_get_child_by_name(dev->of_node, "dais");
+	if (dais_np) {
+		afe->pdev_dais = of_platform_device_create(dais_np,
+							   "q6afe-dai", dev);
+		of_node_put(dais_np);
+	}
+
+	return 0;
+}
+
+static int q6afe_remove(struct apr_device *adev)
+{
+	struct q6afe *afe = dev_get_drvdata(&adev->dev);
+
+	if (afe->pdev_dais)
+		of_platform_device_destroy(&afe->pdev_dais->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id q6afe_device_id[]  = {
+	{ .compatible = "qcom,q6afe" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, q6afe_device_id);
+
+static struct apr_driver qcom_q6afe_driver = {
+	.probe = q6afe_probe,
+	.remove = q6afe_remove,
+	.callback = q6afe_callback,
+	.driver = {
+		.name = "qcom-q6afe",
+		.of_match_table = of_match_ptr(q6afe_device_id),
+
+	},
+};
+
+module_apr_driver(qcom_q6afe_driver);
+MODULE_DESCRIPTION("Q6 Audio Front End");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h
new file mode 100644
index 000000000000..3bd991a7c42d
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6afe.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __Q6AFE_H__
+#define __Q6AFE_H__
+
+#include <dt-bindings/sound/qcom,q6afe.h>
+
+#define AFE_PORT_MAX		48
+
+#define MSM_AFE_PORT_TYPE_RX 0
+#define MSM_AFE_PORT_TYPE_TX 1
+#define AFE_MAX_PORTS AFE_PORT_MAX
+
+struct q6afe_hdmi_cfg {
+	u16                  datatype;
+	u16                  channel_allocation;
+	u32                  sample_rate;
+	u16                  bit_width;
+};
+
+struct q6afe_port_config {
+	struct q6afe_hdmi_cfg hdmi;
+};
+
+struct q6afe_port;
+
+struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id);
+int q6afe_port_start(struct q6afe_port *port);
+int q6afe_port_stop(struct q6afe_port *port);
+void q6afe_port_put(struct q6afe_port *port);
+int q6afe_get_port_id(int index);
+void q6afe_hdmi_port_prepare(struct q6afe_port *port,
+			    struct q6afe_hdmi_cfg *cfg);
+
+#endif /* __Q6AFE_H__ */
-- 
2.17.0

^ permalink raw reply related


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