linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 2/2] ARM: dts: sun8i: enable UART1 for iNet D978 Rev2 board
From: Icenowy Zheng @ 2016-09-16 15:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160916151642.27907-1-icenowy@aosc.xyz>

UART1 is connected to the bluetooth part of RTL8723BS WiFi/BT combo card
on iNet D978 Rev2 board.

Enable the UART1 to make it possible to use the modified hciattach by
Realtek to drive the BT part of RTL8723BS.

On the board no r_uart pins are found now (the onboard RX/TX pins are
wired to PF2/PF4, which is muxed with mmc0), so also disabled it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
---
Changes since v4:
- Split the pinmux part into another patch.
Changes since v3:
- Change bluetooth to serial0.
Changes since v2:
- Remove stdout-path.

 arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts b/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts
index 0f52cd9..fb46655 100644
--- a/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts
+++ b/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts
@@ -49,6 +49,15 @@
 	model = "INet-D978 Rev 02";
 	compatible = "primux,inet-d978-rev2", "allwinner,sun8i-a33";
 
+	aliases {
+		serial0 = &uart1;
+	};
+
+	chosen {
+		/* Delete debug UART as serial0 is the UART for bluetooth */
+		/delete-property/stdout-path;
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -86,3 +95,14 @@
 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 	};
 };
+
+&r_uart {
+	status = "disabled";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins_a>,
+		    <&uart1_pins_cts_rts_a>;
+	status = "okay";
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH v4 1/2] ARM: dts: sun8i: add pinmux for UART1 at PG
From: Icenowy Zheng @ 2016-09-16 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

The UART1 at PG (PG6, PG7, PG8, PG9) is, in the Allwinner's reference
tablet design of A23/33, used to connect to UART Bluetooth cards.

Add the pinmux for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
---
This patch is splited in v4.

 arch/arm/boot/dts/sun8i-a23-a33.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index 7e05e09..c340885 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -361,6 +361,20 @@
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
+			uart1_pins_a: uart1 at 0 {
+				allwinner,pins = "PG6", "PG7";
+				allwinner,function = "uart1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart1_pins_cts_rts_a: uart1-cts-rts at 0 {
+				allwinner,pins = "PG8", "PG9";
+				allwinner,function = "uart1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
 			mmc0_pins_a: mmc0 at 0 {
 				allwinner,pins = "PF0", "PF1", "PF2",
 						 "PF3", "PF4", "PF5";
-- 
2.9.3

^ permalink raw reply related

* [RFC PATCH 2/8] thread_info: allow custom in-task thread_info
From: Andy Lutomirski @ 2016-09-16 15:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160916103101.GA21702@leverpostej>

> On Thu, Sep 15, 2016 at 11:37:47AM -0700, Andy Lutomirski wrote:
> > On Thu, Sep 15, 2016 at 6:49 AM, Mark Rutland <mark.rutland@arm.com> wrote:
> > > Currently, task_struct is defined in <linux/sched.h>, which (indirectly)
> > > pulls in a number of low-level arch headers such as <asm/preempt.h>
> > > through a number of other headers. Thus, code and structures in these
> > > headers can't rely on the definition of task_struct. Some of these
> > > headers are necessary for the definition of task_struct, so moving
> > > task_struct into its own header is insufficient tio avoid circular
> > > includes.
> >
> > The flippant answer is to fix the headers, but I tried that myself and
> > gave up :(
>
> Agreed; likewise (though I gave up quicker, I suspect). :(
>
> Longer-term I'd still hope that we can do this.
>
> > But how about this slightly less duplicative alternative:
> >
> > struct thread_info {
> > #ifdef arch_thread_info
> >   struct arch_thread_info arch_ti;
> > #endif
> > };
>
> I'm happy to have an arch_thread_info.
>
> Just to check, what do you mean to happen with the flags field? Should
> that always be in the generic thread_info? e.g.
>
> struct thread_info {
>         u32 flags;
> #ifdef arch_thread_info
>         struct arch_thread_info arch_ti;
> #endif
> };

Exactly.  Possibly with a comment that using thread_struct should be
preferred and that arch_thread_info should be used only if some header
file requires access via current_thread_info() or task_thread_info().

--Andy

>
> Thanks,
> Mark,

^ permalink raw reply

* [GIT PULL] ARM: SoC fixes for 4.8-rc7
From: Arnd Bergmann @ 2016-09-16 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

The following changes since commit 95390e3290e8bf69091116e0d91b9754c0e93a24:

  Merge tag 'sunxi-fixes-for-4.8' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into fixes (2016-09-07 21:25:08 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git tags/fixes-for-linus

for you to fetch changes up to 6408649115cfd73d6807398d04b2ba564db9211e:

  Merge tag 'samsung-fixes-4.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into fixes (2016-09-16 16:29:48 +0200)

----------------------------------------------------------------
ARM: SoC fixes

Here are a couple of bugfixes for v4.8-rc. Most of them have
actually been around for a while this time but for some reason
didn't get applied early on. The shmobile regulator fix is the
only one that isn't completely obvious.

device tree changes:
- archtimer interrupts must be level triggered (multiple platforms)
- fix for USB and MMC clocks on STiH410
- fix split DT repository in case of raspberry-pi 3
- A new use of skeleton.dtsi on arm64 has crept in after that
  was removed.

defconfig updates:
- xilinx vdma has a new Kconfig symbol name
- keystone requires CONFIG_NOP_USB_XCEIV since v4.8-rc1

code fixes:
- fix regulator quirk on shmobile
- suspend-to-ram regression on EXYNOS

maintainer updates:
- Javier Martinez Canillas is now a reviewer for Samsung EXYNOS

----------------------------------------------------------------
Arnd Bergmann (4):
      Merge tag 'renesas-fixes-for-v4.8' of git://git.kernel.org/.../horms/renesas into fixes
      Merge tag 'sti-dt-fixes-for-v4.8-rcs' of git://git.kernel.org/.../pchotard/sti into fixes
      Merge branch 'dt/irq-fix' into fixes
      Merge tag 'samsung-fixes-4.8-2' of git://git.kernel.org/.../krzk/linux into fixes

Fabian Frederick (1):
      ARM: multi_v7_defconfig: update XILINX_VDMA

Ian Campbell (2):
      ARM: dts: Remove use of skeleton.dtsi from bcm283x.dtsi
      ARM64: dts: bcm: Use a symlink to R-Pi dtsi files from arch=arm

Javier Martinez Canillas (2):
      MAINTAINERS: Add myself as reviewer for Samsung Exynos support
      ARM: EXYNOS: Clear OF_POPULATED flag from PMU node in IRQ init callback

Lee Jones (2):
      ARM: dts: STiH410: Handle interconnect clock required by EHCI/OHCI (USB)
      ARM: dts: STiH407-family: Provide interconnect clock for consumption in ST SDHCI

Marc Zyngier (1):
      arm64: dts: Fix broken architected timer interrupt trigger

Roger Quadros (1):
      ARM: keystone: defconfig: Fix USB configuration

Wolfram Sang (1):
      ARM: shmobile: fix regulator quirk for Gen2

 MAINTAINERS                                        |  1 +
 arch/arm/boot/dts/bcm2835-rpi.dtsi                 |  1 +
 arch/arm/boot/dts/bcm283x.dtsi                     |  3 +-
 arch/arm/boot/dts/stih407-family.dtsi              | 10 ++--
 arch/arm/boot/dts/stih410.dtsi                     | 12 +++--
 arch/arm/configs/keystone_defconfig                |  1 +
 arch/arm/configs/multi_v7_defconfig                |  2 +-
 arch/arm/mach-exynos/suspend.c                     |  6 +++
 arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c | 62 +++++++++-------------
 arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi  |  8 +--
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |  8 +--
 arch/arm64/boot/dts/apm/apm-storm.dtsi             |  8 +--
 arch/arm64/boot/dts/broadcom/bcm2835-rpi.dtsi      |  1 +
 arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts   |  4 +-
 arch/arm64/boot/dts/broadcom/bcm2837.dtsi          |  2 +-
 .../boot/dts/broadcom/bcm283x-rpi-smsc9514.dtsi    |  1 +
 arch/arm64/boot/dts/broadcom/bcm283x.dtsi          |  1 +
 arch/arm64/boot/dts/broadcom/ns2.dtsi              |  8 +--
 arch/arm64/boot/dts/cavium/thunder-88xx.dtsi       |  8 +--
 arch/arm64/boot/dts/exynos/exynos7.dtsi            |  8 +--
 arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi     |  8 +--
 arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |  8 +--
 arch/arm64/boot/dts/marvell/armada-ap806.dtsi      |  8 +--
 .../boot/dts/socionext/uniphier-ph1-ld20.dtsi      |  8 +--
 arch/arm64/boot/dts/xilinx/zynqmp.dtsi             |  8 +--
 25 files changed, 102 insertions(+), 93 deletions(-)
 create mode 120000 arch/arm64/boot/dts/broadcom/bcm2835-rpi.dtsi
 create mode 120000 arch/arm64/boot/dts/broadcom/bcm283x-rpi-smsc9514.dtsi
 create mode 120000 arch/arm64/boot/dts/broadcom/bcm283x.dtsi

^ permalink raw reply

* [RESEND PATCH v7 2/2] sdhci-of-arasan: Set controller to test mode when xlnx, fails-without-test-cd is present
From: Zach Brown @ 2016-09-16 15:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474038102-20937-1-git-send-email-zach.brown@ni.com>

The sdhci controller on xilinx zynq devices will not function unless
the CD bit is provided. http://www.xilinx.com/support/answers/61064.html
In cases where it is impossible to provide the CD bit in hardware,
setting the controller to test mode and then setting inserted to true
will get the controller to function without the CD bit.

When the device has the property xlnx,fails-without-test-cd the driver
changes the controller to test mode and sets test inserted to true to
make the controller function.

Signed-off-by: Zach Brown <zach.brown@ni.com>
---
 drivers/mmc/host/sdhci-of-arasan.c | 27 ++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci.h           |  2 ++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 33601a8..da8e40a 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -26,6 +26,7 @@
 #include <linux/phy/phy.h>
 #include <linux/regmap.h>
 #include "sdhci-pltfm.h"
+#include <linux/of.h>
 
 #define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
 #define SDHCI_ARASAN_VENDOR_REGISTER	0x78
@@ -98,6 +99,10 @@ struct sdhci_arasan_data {
 
 	struct regmap	*soc_ctl_base;
 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
+	unsigned int	quirks; /* Arasan deviations from spec */
+
+/* Controller does not have CD wired and will not function normally without */
+#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST	BIT(0)
 };
 
 static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
@@ -245,12 +250,27 @@ static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
 	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
 }
 
+void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
+{
+	u8 ctrl;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+
+	sdhci_reset(host, mask);
+
+	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
+		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+		ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
+		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+	}
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
 	.set_clock = sdhci_arasan_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
 	.set_bus_width = sdhci_set_bus_width,
-	.reset = sdhci_reset,
+	.reset = sdhci_arasan_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
@@ -545,6 +565,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 	struct sdhci_host *host;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct sdhci_arasan_data *sdhci_arasan;
+	struct device_node *np = pdev->dev.of_node;
 
 	host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata,
 				sizeof(*sdhci_arasan));
@@ -599,6 +620,10 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 	}
 
 	sdhci_get_of_property(pdev);
+
+	if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
+		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
+
 	pltfm_host->clk = clk_xin;
 
 	if (of_device_is_compatible(pdev->dev.of_node,
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a2bc9e1..c722cd2 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -84,6 +84,8 @@
 #define   SDHCI_CTRL_ADMA32	0x10
 #define   SDHCI_CTRL_ADMA64	0x18
 #define   SDHCI_CTRL_8BITBUS	0x20
+#define  SDHCI_CTRL_CDTEST_INS	0x40
+#define  SDHCI_CTRL_CDTEST_EN	0x80
 
 #define SDHCI_POWER_CONTROL	0x29
 #define  SDHCI_POWER_ON		0x01
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v7 1/2] sdhci-of-arasan: Add device tree parameter xlnx, fails-without-test-cd bit
From: Zach Brown @ 2016-09-16 15:01 UTC (permalink / raw)
  To: linux-arm-kernel

The sdhci controller on xilinx zynq devices will not function unless
the CD bit is provided. http://www.xilinx.com/support/answers/61064.html
In cases where it is impossible to provide the CD bit in hardware,
setting the controller to test mode and then setting inserted to true
will get the controller to function without the CD bit.

The device property "xlnx,fails-without-test-cd" will let the arasan
driver know the controller does not have the CD line wired and that the
controller does not function without it.

Signed-off-by: Zach Brown <zach.brown@ni.com>
---
v2:
 * improved commit messages
 * removed fake-cd device property
 * removed fake-cd quirk
 * use broken-cd device property
 * documented new usage of broken-cd
v3:
 * removed new usage of broken-cd
 * created fails-without-test-cd device property
 * created arasan controller specific quirk
v4:
 * changed fails-without-test-cd to xlnx-fails-without-test-cd
 * removed extra blank line
v5:
 * Fixed style mistake
 * Changed (1 << 0 ) to BIT(0)
v6:
 * Fixed style mistakes
 * Condensed unnecessarily long variable names
 * Removed line wraps that were no longer necessary.
 * Rebased changes off Ulf's mmc tree's next branch.
v7:
 * Removed erroneous re-creation of Optional Properties section
 * Changed xlnx-fails-without-test-cd to xlnx,fails-without-test-cd
 * Changed of_get_property to of_property_read_bool


 Documentation/devicetree/bindings/mmc/arasan,sdhci.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
index 3404afa..49df630 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
@@ -36,6 +36,9 @@ Optional Properties:
   - #clock-cells: If specified this should be the value <0>.  With this property
     in place we will export a clock representing the Card Clock.  This clock
     is expected to be consumed by our PHY.  You must also specify
+  - xlnx,fails-without-test-cd: when present, the controller doesn't work when
+    the CD line is not connected properly, and the line is not connected
+    properly. Test mode can be used to force the controller to function.
 
 Example:
 	sdhci at e0100000 {
-- 
2.7.4

^ permalink raw reply related

* [PATCH] musb: Export musb_root_disconnect for use in modules
From: Hans de Goede @ 2016-09-16 14:59 UTC (permalink / raw)
  To: linux-arm-kernel

Export musb_root_disconnect for use in modules, so that musb glue
code build as module can use it.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/musb/musb_virthub.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index fe08e77..61b5f1c 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -245,6 +245,7 @@ void musb_root_disconnect(struct musb *musb)
 			usb_otg_state_string(musb->xceiv->otg->state));
 	}
 }
+EXPORT_SYMBOL_GPL(musb_root_disconnect);
 
 
 /*---------------------------------------------------------------------*/
-- 
2.9.3

^ permalink raw reply related

* next-20160915 build: 2 failures 16 warnings (next-20160915)
From: Hans de Goede @ 2016-09-16 14:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160915154140.GM27974@sirena.org.uk>

Hi,

On 15-09-16 17:41, Mark Brown wrote:
> On Thu, Sep 15, 2016 at 12:43:41PM +0100, Build bot for Mark Brown wrote:
>
> Today's -next fails to build both arm and arm64 allmodconfigs due to:
>
>> 	arm64-allmodconfig
>> ERROR: "musb_root_disconnect" [drivers/usb/musb/sunxi.ko] undefined!
>
>> 	arm-allmodconfig
>> ERROR: "musb_root_disconnect" [drivers/usb/musb/sunxi.ko] undefined!
>
> due to 7cba17ec9adc8cf (musb: sunxi: Add support for platform_set_mode)
> which adds a call to that non-exported function to a module.

Thank you for catching / reporting this. One patch fixing this
coming up.

Regards,

Hans

^ permalink raw reply

* [PATCH v26 3/7] arm64: kdump: add kdump support
From: James Morse @ 2016-09-16 14:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160907042908.6232-4-takahiro.akashi@linaro.org>

On 07/09/16 05:29, AKASHI Takahiro wrote:
> On crash dump kernel, all the information about primary kernel's system
> memory (core image) is available in elf core header.
> The primary kernel will set aside this header with reserve_elfcorehdr()
> at boot time and inform crash dump kernel of its location via a new
> device-tree property, "linux,elfcorehdr".
> 
> Please note that all other architectures use traditional "elfcorehdr="
> kernel parameter for this purpose.
> 
> Then crash dump kernel will access the primary kernel's memory with
> copy_oldmem_page(), which reads one page by ioremap'ing it since it does
> not reside in linear mapping on crash dump kernel.
> 
> We also need our own elfcorehdr_read() here since the header is placed
> within crash dump kernel's usable memory.

One nit below, looks good.

Reviewed-by: James Morse <james.morse@arm.com>


Thanks,

James


> diff --git a/arch/arm64/kernel/crash_dump.c b/arch/arm64/kernel/crash_dump.c

> +/**
> + * copy_oldmem_page() - copy one page from old kernel memory
> + * @pfn: page frame number to be copied
> + * @buf: buffer where the copied page is placed
> + * @csize: number of bytes to copy
> + * @offset: offset in bytes into the page
> + * @userbuf: if set, @buf is in a user address space
> + *
> + * This function copies one page from old kernel memory into buffer pointed by
> + * @buf. If @buf is in userspace, set @userbuf to %1. Returns number of bytes
> + * copied or negative error in case of failure.
> + */
> +ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
> +			 size_t csize, unsigned long offset,
> +			 int userbuf)
> +{
> +	void *vaddr;
> +
> +	if (!csize)
> +		return 0;
> +
> +	vaddr = memremap(__pfn_to_phys(pfn), PAGE_SIZE, MEMREMAP_WB);
> +	if (!vaddr)
> +		return -ENOMEM;
> +
> +	if (userbuf) {

> +		if (copy_to_user(buf, vaddr + offset, csize)) {

If you re-cast buf with (char __user *), it should stop sparse complaining:
> ../arch/arm64/kernel/crash_dump.c:45:34: warning: incorrect type in argument 1
(different address spaces)
> ../arch/arm64/kernel/crash_dump.c:45:34:    expected void [noderef] <asn:1>*to
> ../arch/arm64/kernel/crash_dump.c:45:34:    got char *buf

^ permalink raw reply

* [PATCH v26 2/7] arm64: kdump: implement machine_crash_shutdown()
From: James Morse @ 2016-09-16 14:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160915114815.GK16712@linaro.org>

On 16/09/16 04:21, AKASHI Takahiro wrote:
> On Wed, Sep 14, 2016 at 07:09:33PM +0100, James Morse wrote:
>> On 07/09/16 05:29, AKASHI Takahiro wrote:
>>> Primary kernel calls machine_crash_shutdown() to shut down non-boot cpus
>>> and save registers' status in per-cpu ELF notes before starting crash
>>> dump kernel. See kernel_kexec().
>>> Even if not all secondary cpus have shut down, we do kdump anyway.
>>>
>>> As we don't have to make non-boot(crashed) cpus offline (to preserve
>>> correct status of cpus at crash dump) before shutting down, this patch
>>> also adds a variant of smp_send_stop().

>>> diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
>>> index 04744dc..a908958 100644
>>> --- a/arch/arm64/include/asm/kexec.h
>>> +++ b/arch/arm64/include/asm/kexec.h
>>> @@ -40,7 +40,46 @@
>>>  static inline void crash_setup_regs(struct pt_regs *newregs,
>>>  				    struct pt_regs *oldregs)
>>>  {
>>> -	/* Empty routine needed to avoid build errors. */
>>> +	if (oldregs) {
>>> +		memcpy(newregs, oldregs, sizeof(*newregs));
>>> +	} else {
>>> +		u64 tmp1, tmp2;
>>> +
>>> +		__asm__ __volatile__ (
>>> +			"stp	 x0,   x1, [%2, #16 *  0]\n"
>>> +			"stp	 x2,   x3, [%2, #16 *  1]\n"
>>> +			"stp	 x4,   x5, [%2, #16 *  2]\n"
>>> +			"stp	 x6,   x7, [%2, #16 *  3]\n"
>>> +			"stp	 x8,   x9, [%2, #16 *  4]\n"
>>> +			"stp	x10,  x11, [%2, #16 *  5]\n"
>>> +			"stp	x12,  x13, [%2, #16 *  6]\n"
>>> +			"stp	x14,  x15, [%2, #16 *  7]\n"
>>> +			"stp	x16,  x17, [%2, #16 *  8]\n"
>>> +			"stp	x18,  x19, [%2, #16 *  9]\n"
>>> +			"stp	x20,  x21, [%2, #16 * 10]\n"
>>> +			"stp	x22,  x23, [%2, #16 * 11]\n"
>>> +			"stp	x24,  x25, [%2, #16 * 12]\n"
>>> +			"stp	x26,  x27, [%2, #16 * 13]\n"
>>> +			"stp	x28,  x29, [%2, #16 * 14]\n"
>>> +			"mov	 %0,  sp\n"
>>> +			"stp	x30,  %0,  [%2, #16 * 15]\n"
>>> +
>>> +			"/* faked current PSTATE */\n"
>>> +			"mrs	 %0, CurrentEL\n"
>>> +			"mrs	 %1, DAIF\n"
>>> +			"orr	 %0, %0, %1\n"
>>> +			"mrs	 %1, NZCV\n"
>>> +			"orr	 %0, %0, %1\n"
>>> +
>>
>> What about SPSEL? While we don't use it, it is correctly preserved for
>> everything except a CPU that calls panic()...
> 
> My comment above might be confusing, but what I want to fake
> here is "spsr" as pt_regs.pstate is normally set based on spsr_el1.
> So there is no corresponding field of SPSEL in spsr.

Here is my logic, I may have missed something obvious, see what you think:

SPSR_EL{1,2} shows the CPU mode 'M' in bits 0-4, From aarch64 bit 4 is always 0.
>From the register definitions in the ARM-ARM C5.2, likely values in 0-3 are:
0100 EL1t
0101 EL1h
1000 EL2t
1001 EL2h

I'm pretty sure this least significant bit is what SPSEL changes, so it does get
implicitly recorded in SPSR.
CurrentEL returns a value in bits 0-3, of which 0-1 are RES0, so we lose the
difference between EL?t and EL?h.


> 
>>
>>> +			/* pc */
>>> +			"adr	 %1, 1f\n"
>>> +		"1:\n"
>>> +			"stp	 %1, %0,   [%2, #16 * 16]\n"
>>> +			: "=r" (tmp1), "=r" (tmp2), "+r" (newregs)
>>> +			:
>>> +			: "memory"

Do you need the memory clobber? This asm only modifies values in newregs.


>>> +		);
>>> +	}
>>>  }
>>>  
>>>  #endif /* __ASSEMBLY__ */


>>> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c

>>> +#ifdef CONFIG_KEXEC_CORE
>>> +void smp_send_crash_stop(void)
>>> +{
>>> +	cpumask_t mask;
>>> +	unsigned long timeout;
>>> +
>>> +	if (num_online_cpus() == 1)
>>> +		return;
>>> +
>>> +	cpumask_copy(&mask, cpu_online_mask);
>>> +	cpumask_clear_cpu(smp_processor_id(), &mask);
>>> +
>>> +	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
>>> +
>>> +	pr_crit("SMP: stopping secondary CPUs\n");
>>> +	smp_cross_call(&mask, IPI_CPU_CRASH_STOP);
>>> +
>>> +	/* Wait up to one second for other CPUs to stop */
>>> +	timeout = USEC_PER_SEC;
>>> +	while ((atomic_read(&waiting_for_crash_ipi) > 0) && timeout--)
>>> +		udelay(1);
>>> +
>>> +	if (atomic_read(&waiting_for_crash_ipi) > 0)
>>> +		pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",
>>> +			   cpumask_pr_args(cpu_online_mask));
>>> +}
>>> +#endif
>>
>> This is very similar to smp_send_stop() which also has the timeout. Is it
>> possible to merge them? You could use in_crash_kexec to choose the IPI type.
> 
> Yeah, we could merge them along with ipi_cpu_(crash_)stop().
> But the resulting code would be quite noisy if each line
> is switched by "if (in_crash_kexec)."
> Otherwise, we may have one big "if" like:
> void smp_send_stop(void)
> {
>     if (in_crash_kexec)
>         ...
>     else
>         ...
> }
> It seems to me that it is not much different from the current code.
> What do you think?

Hmm, yes, its too fiddly to keep the existing behaviour of both.

The problems are ipi_cpu_stop() doesn't call cpu_die(), (I can't see a good
reason for this, but more archaeology is needed), and ipi_cpu_crash_stop()
doesn't modify the online cpu mask.

I don't suggest we do this yet, but it could be future cleanup if it's proved to
be safe:
smp_send_stop() is only called from:  machine_halt(), machine_power_off(),
machine_restart() and panic(). In all those cases the CPUs are never expected to
come back, so we can probably merge the IPIs.  This involves modifying the
online cpu mask during kdump, (which I think is fine as it uses the atomic
bitops so we won't get blocked on a lock), and promoting in_crash_kexec to some
atomic type.

But I think we should leave it as it is for now,


Thanks,

James

^ permalink raw reply

* [PATCH V7 3/3] perf tools: adding support for address filters
From: Mathieu Poirier @ 2016-09-16 14:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474037045-31730-1-git-send-email-mathieu.poirier@linaro.org>

This patch makes it possible to use the current filter
framework with address filters.  That way address filters for
HW tracers such as CoreSight and Intel PT can be communicated
to the kernel drivers.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/evsel.c        |  5 +++++
 tools/perf/util/evsel.h        |  2 ++
 tools/perf/util/parse-events.c | 39 ++++++++++++++++++++++++++++++++++-----
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a99e82d97df2..e0bb399dcdd4 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1067,6 +1067,11 @@ int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter)
 	return perf_evsel__append_filter(evsel, "(%s) && (%s)", filter);
 }
 
+int perf_evsel__append_addr_filter(struct perf_evsel *evsel, const char *filter)
+{
+	return perf_evsel__append_filter(evsel, "%s,%s", filter);
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel)
 {
 	int nthreads = thread_map__nr(evsel->threads);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 36ed0997e65b..49c51fb3d05c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -234,6 +234,8 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel,
 
 int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter);
 int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter);
+int perf_evsel__append_addr_filter(struct perf_evsel *evsel,
+				   const char *filter);
 int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 			     const char *filter);
 int perf_evsel__enable(struct perf_evsel *evsel);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 751b48fc641c..c23f2d5fc134 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1755,20 +1755,49 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist,
 static int set_filter(struct perf_evsel *evsel, const void *arg)
 {
 	const char *str = arg;
+	bool found = false;
+	int nr_addr_filters = 0;
+	struct perf_pmu *pmu = NULL;
 
-	if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) {
-		fprintf(stderr,
-			"--filter option should follow a -e tracepoint option\n");
-		return -1;
+	if (evsel == NULL)
+		goto err;
+
+	if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
+		if (perf_evsel__append_tp_filter(evsel, str) < 0) {
+			fprintf(stderr,
+				"not enough memory to hold filter string\n");
+			return -1;
+		}
+
+		return 0;
 	}
 
-	if (perf_evsel__append_tp_filter(evsel, str) < 0) {
+	while ((pmu = perf_pmu__scan(pmu)) != NULL)
+		if (pmu->type == evsel->attr.type) {
+			found = true;
+			break;
+		}
+
+	if (found)
+		perf_pmu__scan_file(pmu, "nr_addr_filters",
+				    "%d", &nr_addr_filters);
+
+	if (!nr_addr_filters)
+		goto err;
+
+	if (perf_evsel__append_addr_filter(evsel, str) < 0) {
 		fprintf(stderr,
 			"not enough memory to hold filter string\n");
 		return -1;
 	}
 
 	return 0;
+
+err:
+	fprintf(stderr,
+		"--filter option should follow a -e tracepoint or HW tracer option\n");
+
+	return -1;
 }
 
 int parse_filter(const struct option *opt, const char *str,
-- 
2.7.4

^ permalink raw reply related

* [PATCH V7 2/3] perf tools: new tracepoint specific function
From: Mathieu Poirier @ 2016-09-16 14:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474037045-31730-1-git-send-email-mathieu.poirier@linaro.org>

Making function perf_evsel__append_filter() static and
introducing a new tracepoint specific function to append
filters.  That way we eliminate redundant code and avoid
formatting mistake.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-trace.c     | 7 +++----
 tools/perf/util/evsel.c        | 9 +++++++--
 tools/perf/util/evsel.h        | 3 +--
 tools/perf/util/parse-events.c | 4 ++--
 4 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 4c2704332c14..34effab09f39 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2148,11 +2148,10 @@ static int trace__set_ev_qualifier_filter(struct trace *trace)
 	if (filter == NULL)
 		goto out_enomem;
 
-	if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter,
-				       "(%s) && (%s)", filter)) {
+	if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
+					  filter)) {
 		sys_exit = trace->syscalls.events.sys_exit;
-		err = perf_evsel__append_filter(sys_exit,
-						"(%s) && (%s)", filter);
+		err = perf_evsel__append_tp_filter(sys_exit, filter);
 	}
 
 	free(filter);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index b93369745e08..a99e82d97df2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1045,8 +1045,8 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter)
 	return -1;
 }
 
-int perf_evsel__append_filter(struct perf_evsel *evsel,
-			      const char *fmt, const char *filter)
+static int perf_evsel__append_filter(struct perf_evsel *evsel,
+				     const char *fmt, const char *filter)
 {
 	char *new_filter;
 
@@ -1062,6 +1062,11 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
 	return -1;
 }
 
+int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter)
+{
+	return perf_evsel__append_filter(evsel, "(%s) && (%s)", filter);
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel)
 {
 	int nthreads = thread_map__nr(evsel->threads);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 7ab59f15892f..36ed0997e65b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -233,8 +233,7 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel,
 			       bool use_sample_identifier);
 
 int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter);
-int perf_evsel__append_filter(struct perf_evsel *evsel,
-			      const char *fmt, const char *filter);
+int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter);
 int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 			     const char *filter);
 int perf_evsel__enable(struct perf_evsel *evsel);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9692300585f6..751b48fc641c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1762,7 +1762,7 @@ static int set_filter(struct perf_evsel *evsel, const void *arg)
 		return -1;
 	}
 
-	if (perf_evsel__append_filter(evsel, "(%s) && (%s)", str) < 0) {
+	if (perf_evsel__append_tp_filter(evsel, str) < 0) {
 		fprintf(stderr,
 			"not enough memory to hold filter string\n");
 		return -1;
@@ -1793,7 +1793,7 @@ static int add_exclude_perf_filter(struct perf_evsel *evsel,
 
 	snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid());
 
-	if (perf_evsel__append_filter(evsel, "(%s) && (%s)", new_filter) < 0) {
+	if (perf_evsel__append_tp_filter(evsel, new_filter) < 0) {
 		fprintf(stderr,
 			"not enough memory to hold filter string\n");
 		return -1;
-- 
2.7.4

^ permalink raw reply related

* [PATCH V7 1/3] perf tools: making perf_evsel__append_filter() generic
From: Mathieu Poirier @ 2016-09-16 14:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474037045-31730-1-git-send-email-mathieu.poirier@linaro.org>

By making function perf_evsel__append_filter() take a format rather
than an operator it is possible to reuse the code for other purposes
(ex. Intel PT and CoreSight) than tracepoints.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-trace.c     | 9 +++++++--
 tools/perf/util/evsel.c        | 4 ++--
 tools/perf/util/evsel.h        | 2 +-
 tools/perf/util/parse-events.c | 4 ++--
 4 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index b8c6766301db..4c2704332c14 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2140,6 +2140,7 @@ out_delete_sys_enter:
 static int trace__set_ev_qualifier_filter(struct trace *trace)
 {
 	int err = -1;
+	struct perf_evsel *sys_exit;
 	char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
 						trace->ev_qualifier_ids.nr,
 						trace->ev_qualifier_ids.entries);
@@ -2147,8 +2148,12 @@ static int trace__set_ev_qualifier_filter(struct trace *trace)
 	if (filter == NULL)
 		goto out_enomem;
 
-	if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
-		err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
+	if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter,
+				       "(%s) && (%s)", filter)) {
+		sys_exit = trace->syscalls.events.sys_exit;
+		err = perf_evsel__append_filter(sys_exit,
+						"(%s) && (%s)", filter);
+	}
 
 	free(filter);
 out:
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 21fd573106ed..b93369745e08 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1046,14 +1046,14 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter)
 }
 
 int perf_evsel__append_filter(struct perf_evsel *evsel,
-			      const char *op, const char *filter)
+			      const char *fmt, const char *filter)
 {
 	char *new_filter;
 
 	if (evsel->filter == NULL)
 		return perf_evsel__set_filter(evsel, filter);
 
-	if (asprintf(&new_filter,"(%s) %s (%s)", evsel->filter, op, filter) > 0) {
+	if (asprintf(&new_filter, fmt, evsel->filter, filter) > 0) {
 		free(evsel->filter);
 		evsel->filter = new_filter;
 		return 0;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4d44129e050b..7ab59f15892f 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -234,7 +234,7 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel,
 
 int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter);
 int perf_evsel__append_filter(struct perf_evsel *evsel,
-			      const char *op, const char *filter);
+			      const char *fmt, const char *filter);
 int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 			     const char *filter);
 int perf_evsel__enable(struct perf_evsel *evsel);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6c913c3914fb..9692300585f6 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1762,7 +1762,7 @@ static int set_filter(struct perf_evsel *evsel, const void *arg)
 		return -1;
 	}
 
-	if (perf_evsel__append_filter(evsel, "&&", str) < 0) {
+	if (perf_evsel__append_filter(evsel, "(%s) && (%s)", str) < 0) {
 		fprintf(stderr,
 			"not enough memory to hold filter string\n");
 		return -1;
@@ -1793,7 +1793,7 @@ static int add_exclude_perf_filter(struct perf_evsel *evsel,
 
 	snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid());
 
-	if (perf_evsel__append_filter(evsel, "&&", new_filter) < 0) {
+	if (perf_evsel__append_filter(evsel, "(%s) && (%s)", new_filter) < 0) {
 		fprintf(stderr,
 			"not enough memory to hold filter string\n");
 		return -1;
-- 
2.7.4

^ permalink raw reply related

* [PATCH V7 0/3] Adding support for address filters
From: Mathieu Poirier @ 2016-09-16 14:44 UTC (permalink / raw)
  To: linux-arm-kernel

This patch set makes it possible to use the current filter
framework with address filters.  That way address filters for
HW tracers such as CoreSight and Intel PT can be communicated
to the kernel drivers.

In this revision precursor work is done to make function
perf_evsel__append_filter() generic, along with changes to
current customers.  From there the work on address filters is
introduced.

Thanks,
Mathieu

---
Changes for V7:
 - s/intelPT/Intel PT
 - Added Adrian's ack.

Changes for V6:
 - Split work in 3 (small) patches.
 - Adding tracepoint and address filter append() functions

Changes for V5:
 - Modified perf_evsel__append_filter() to take a string format
   rather than an operation.

Changes for V4:
 - Added support for address filters over more than one
   nibble.
 - Removed Jiri's ack, this version is too different from
   what was reviewed.

Changes for V3:
 - Added Jiri's ack.
 - Rebased to v4.8-rc5.

Changes for V2:
 - Rebased to v4.8-rc4.
 - Revisited error path.

Mathieu Poirier (3):
  perf tools: making perf_evsel__append_filter() generic
  perf tools: new tracepoint specific function
  perf tools: adding support for address filters

 tools/perf/builtin-trace.c     |  8 ++++++--
 tools/perf/util/evsel.c        | 16 +++++++++++++---
 tools/perf/util/evsel.h        |  5 +++--
 tools/perf/util/parse-events.c | 41 +++++++++++++++++++++++++++++++++++------
 4 files changed, 57 insertions(+), 13 deletions(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH v5 3/3] clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK
From: Philipp Zabel @ 2016-09-16 14:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOMZO5DPTSGafyYavoOcpKgo7Y=bh9Kd7KPHQ2QKLAxqzbQyMA@mail.gmail.com>

Am Freitag, den 16.09.2016, 11:33 -0300 schrieb Fabio Estevam:
> On Thu, Sep 15, 2016 at 10:36 PM, Shawn Guo <shawnguo@kernel.org> wrote:
> 
> >> Shawn,
> >>
> >> Are you happy with it?
> >
> > Acked-by: Shawn Guo <shawnguo@kernel.org>
> >
> > Please send it to clk maintainers for applying.
> 
> Thanks. Just sent it to the clk folks.

Thanks!

^ permalink raw reply

* [PATCH 3/3] clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK
From: Fabio Estevam @ 2016-09-16 14:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474036587-13819-1-git-send-email-fabio.estevam@nxp.com>

Due to incorrect placement of the clock gate cell in the ldb_di[x]_clk
tree, the glitchy parent mux of ldb_di[x]_clk can cause a glitch to
enter the ldb_di_ipu_div divider. If the divider gets locked up, no
ldb_di[x]_clk is generated, and the LVDS display will hang when the
ipu_di_clk is sourced from ldb_di_clk.

To fix the problem, both the new and current parent of the ldb_di_clk
should be disabled before the switch. This patch ensures that correct
steps are followed when ldb_di_clk parent is switched in the beginning
of boot. The glitchy muxes are then registered as read-only. The clock
parent can be selected using the assigned-clocks and
assigned-clock-parents properties of the ccm device tree node:

	&clks {
		assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
				  <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
		assigned-clock-parents = <&clks IMX6QDL_CLK_MMDC_CH1_AXI>,
					 <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>;
	};

The issue is explained in detail in EB821 ("LDB Clock Switch Procedure &
i.MX6 Asynchronous Clock Switching Guidelines") [1].

[1] http://www.nxp.com/files/32bit/doc/eng_bulletin/EB821.pdf

Signed-off-by: Ranjani Vaidyanathan <Ranjani.Vaidyanathan@nxp.com>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Akshay Bhat <akshay.bhat@timesys.com>
Tested-by Joshua Clayton <stillcompiling@gmail.com>
Tested-by: Charles Kang <Charles.Kang@advantech.com.tw>
Acked-by: Shawn Guo <shawnguo@kernel.org>
---
 drivers/clk/imx/clk-imx6q.c | 264 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 259 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 9bbc994..fc3ed87 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -156,9 +156,90 @@ static struct clk ** const uart_clks[] __initconst = {
 	NULL
 };
 
+static int ldb_di_sel_by_clock_id(int clock_id)
+{
+	switch (clock_id) {
+	case IMX6QDL_CLK_PLL5_VIDEO_DIV:
+		if (clk_on_imx6q() &&
+		    imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
+			return -ENOENT;
+		return 0;
+	case IMX6QDL_CLK_PLL2_PFD0_352M:
+		return 1;
+	case IMX6QDL_CLK_PLL2_PFD2_396M:
+		return 2;
+	case IMX6QDL_CLK_MMDC_CH1_AXI:
+		return 3;
+	case IMX6QDL_CLK_PLL3_USB_OTG:
+		return 4;
+	default:
+		return -ENOENT;
+	}
+}
+
+static void of_assigned_ldb_sels(struct device_node *node,
+				 unsigned int *ldb_di0_sel,
+				 unsigned int *ldb_di1_sel)
+{
+	struct of_phandle_args clkspec;
+	int index, rc, num_parents;
+	int parent, child, sel;
+
+	num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
+						 "#clock-cells");
+	for (index = 0; index < num_parents; index++) {
+		rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
+					"#clock-cells", index, &clkspec);
+		if (rc < 0) {
+			/* skip empty (null) phandles */
+			if (rc == -ENOENT)
+				continue;
+			else
+				return;
+		}
+		if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
+			pr_err("ccm: parent clock %d not in ccm\n", index);
+			return;
+		}
+		parent = clkspec.args[0];
+
+		rc = of_parse_phandle_with_args(node, "assigned-clocks",
+				"#clock-cells", index, &clkspec);
+		if (rc < 0)
+			return;
+		if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
+			pr_err("ccm: child clock %d not in ccm\n", index);
+			return;
+		}
+		child = clkspec.args[0];
+
+		if (child != IMX6QDL_CLK_LDB_DI0_SEL &&
+		    child != IMX6QDL_CLK_LDB_DI1_SEL)
+			continue;
+
+		sel = ldb_di_sel_by_clock_id(parent);
+		if (sel < 0) {
+			pr_err("ccm: invalid ldb_di%d parent clock: %d\n",
+			       child == IMX6QDL_CLK_LDB_DI1_SEL, parent);
+			continue;
+		}
+
+		if (child == IMX6QDL_CLK_LDB_DI0_SEL)
+			*ldb_di0_sel = sel;
+		if (child == IMX6QDL_CLK_LDB_DI1_SEL)
+			*ldb_di1_sel = sel;
+	}
+}
+
 #define CCM_CCDR		0x04
+#define CCM_CCSR		0x0c
+#define CCM_CS2CDR		0x2c
+
+#define CCDR_MMDC_CH1_MASK		BIT(16)
+#define CCSR_PLL3_SW_CLK_SEL		BIT(0)
 
-#define CCDR_MMDC_CH1_MASK	BIT(16)
+#define CS2CDR_LDB_DI0_CLK_SEL_SHIFT	9
+#define CS2CDR_LDB_DI1_CLK_SEL_SHIFT	12
 
 static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
 {
@@ -169,10 +250,173 @@ static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
 	writel_relaxed(reg, ccm_base + CCM_CCDR);
 }
 
+/*
+ * The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk
+ * via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the
+ * bypass clock source, since there is no CG bit for mmdc_ch1.
+ */
+static void mmdc_ch1_disable(void __iomem *ccm_base)
+{
+	unsigned int reg;
+
+	clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL],
+		       clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+
+	/*
+	 * Handshake with mmdc_ch1 module must be masked when changing
+	 * periph2_clk_sel.
+	 */
+	clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]);
+
+	/* Disable pll3_sw_clk by selecting the bypass clock source */
+	reg = readl_relaxed(ccm_base + CCM_CCSR);
+	reg |= CCSR_PLL3_SW_CLK_SEL;
+	writel_relaxed(reg, ccm_base + CCM_CCSR);
+}
+
+static void mmdc_ch1_reenable(void __iomem *ccm_base)
+{
+	unsigned int reg;
+
+	/* Enable pll3_sw_clk by disabling the bypass */
+	reg = readl_relaxed(ccm_base + CCM_CCSR);
+	reg &= ~CCSR_PLL3_SW_CLK_SEL;
+	writel_relaxed(reg, ccm_base + CCM_CCSR);
+
+	clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]);
+}
+
+/*
+ * We have to follow a strict procedure when changing the LDB clock source,
+ * otherwise we risk introducing a glitch that can lock up the LDB divider.
+ * Things to keep in mind:
+ *
+ * 1. The current and new parent clock inputs to the mux must be disabled.
+ * 2. The default clock input for ldb_di0/1_clk_sel is mmdc_ch1_axi, which
+ *    has no CG bit.
+ * 3. pll2_pfd2_396m can not be gated if it is used as memory clock.
+ * 4. In the RTL implementation of the LDB_DI_CLK_SEL muxes the top four
+ *    options are in one mux and the PLL3 option along with three unused
+ *    inputs is in a second mux. There is a third mux with two inputs used
+ *    to decide between the first and second 4-port mux:
+ *
+ *    pll5_video_div 0 --|\
+ *    pll2_pfd0_352m 1 --| |_
+ *    pll2_pfd2_396m 2 --| | `-|\
+ *    mmdc_ch1_axi   3 --|/    | |
+ *                             | |--
+ *    pll3_usb_otg   4 --|\    | |
+ *                   5 --| |_,-|/
+ *                   6 --| |
+ *                   7 --|/
+ *
+ * The ldb_di0/1_clk_sel[1:0] bits control both 4-port muxes@the same time.
+ * The ldb_di0/1_clk_sel[2] bit controls the 2-port mux. The code below
+ * switches the parent to the bottom mux first and then manipulates the top
+ * mux to ensure that no glitch will enter the divider.
+ */
+static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
+{
+	unsigned int reg;
+	unsigned int sel[2][4];
+	int i;
+
+	reg = readl_relaxed(ccm_base + CCM_CS2CDR);
+	sel[0][0] = (reg >> CS2CDR_LDB_DI0_CLK_SEL_SHIFT) & 7;
+	sel[1][0] = (reg >> CS2CDR_LDB_DI1_CLK_SEL_SHIFT) & 7;
+
+	sel[0][3] = sel[0][2] = sel[0][1] = sel[0][0];
+	sel[1][3] = sel[1][2] = sel[1][1] = sel[1][0];
+
+	of_assigned_ldb_sels(np, &sel[0][3], &sel[1][3]);
+
+	for (i = 0; i < 2; i++) {
+		/* Warn if a glitch might have been introduced already */
+		if (sel[i][0] != 3) {
+			pr_warn("ccm: ldb_di%d_sel already changed from reset value: %d\n",
+				i, sel[i][0]);
+		}
+
+		if (sel[i][0] == sel[i][3])
+			continue;
+
+		/* Only switch to or from pll2_pfd2_396m if it is disabled */
+		if ((sel[i][0] == 2 || sel[i][3] == 2) &&
+		    (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
+		     clk[IMX6QDL_CLK_PLL2_PFD2_396M])) {
+			pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n",
+			       i);
+			sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0];
+			continue;
+		}
+
+		/* First switch to the bottom mux */
+		sel[i][1] = sel[i][0] | 4;
+
+		/* Then configure the top mux before switching back to it */
+		sel[i][2] = sel[i][3] | 4;
+
+		pr_debug("ccm: switching ldb_di%d_sel: %d->%d->%d->%d\n", i,
+			 sel[i][0], sel[i][1], sel[i][2], sel[i][3]);
+	}
+
+	if (sel[0][0] == sel[0][3] && sel[1][0] == sel[1][3])
+		return;
+
+	mmdc_ch1_disable(ccm_base);
+
+	for (i = 1; i < 4; i++) {
+		reg = readl_relaxed(ccm_base + CCM_CS2CDR);
+		reg &= ~((7 << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) |
+			 (7 << CS2CDR_LDB_DI1_CLK_SEL_SHIFT));
+		reg |= ((sel[0][i] << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) |
+			(sel[1][i] << CS2CDR_LDB_DI1_CLK_SEL_SHIFT));
+		writel_relaxed(reg, ccm_base + CCM_CS2CDR);
+	}
+
+	mmdc_ch1_reenable(ccm_base);
+}
+
+#define CCM_ANALOG_PLL_VIDEO	0xa0
+#define CCM_ANALOG_PFD_480	0xf0
+#define CCM_ANALOG_PFD_528	0x100
+
+#define PLL_ENABLE		BIT(13)
+
+#define PFD0_CLKGATE		BIT(7)
+#define PFD1_CLKGATE		BIT(15)
+#define PFD2_CLKGATE		BIT(23)
+#define PFD3_CLKGATE		BIT(31)
+
+static void disable_anatop_clocks(void __iomem *anatop_base)
+{
+	unsigned int reg;
+
+	/* Make sure PLL2 PFDs 0-2 are gated */
+	reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528);
+	/* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */
+	if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
+	    clk[IMX6QDL_CLK_PLL2_PFD2_396M])
+		reg |= PFD0_CLKGATE | PFD1_CLKGATE;
+	else
+		reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE;
+	writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_528);
+
+	/* Make sure PLL3 PFDs 0-3 are gated */
+	reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_480);
+	reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE | PFD3_CLKGATE;
+	writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_480);
+
+	/* Make sure PLL5 is disabled */
+	reg = readl_relaxed(anatop_base + CCM_ANALOG_PLL_VIDEO);
+	reg &= ~PLL_ENABLE;
+	writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO);
+}
+
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
 	struct device_node *np;
-	void __iomem *base;
+	void __iomem *anatop_base, *base;
 	int i;
 	int ret;
 
@@ -185,7 +429,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
-	base = of_iomap(np, 0);
+	anatop_base = base = of_iomap(np, 0);
 	WARN_ON(!base);
 
 	/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
@@ -310,8 +554,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
 
-	imx6q_mmdc_ch1_mask_handshake(base);
-
 	/*                                              name                reg       shift width parent_names     num_parents */
 	clk[IMX6QDL_CLK_STEP]             = imx_clk_mux("step",	            base + 0xc,  8,  1, step_sels,	   ARRAY_SIZE(step_sels));
 	clk[IMX6QDL_CLK_PLL1_SW]          = imx_clk_mux("pll1_sw",	    base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
@@ -340,6 +582,18 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
 	clk[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
 	clk[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
+
+	disable_anatop_clocks(anatop_base);
+
+	imx6q_mmdc_ch1_mask_handshake(base);
+
+	/*
+	 * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware
+	 * bug. Set the muxes to the requested values before registering the
+	 * ldb_di_sel clocks.
+	 */
+	init_ldb_clks(np, base);
+
 	clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
 	clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
 	clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/3] clk: imx6: Make the LDB_DI0 and LDB_DI1 clocks read-only
From: Fabio Estevam @ 2016-09-16 14:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474036587-13819-1-git-send-email-fabio.estevam@nxp.com>

From: Philipp Zabel <p.zabel@pengutronix.de>

Due to incorrect placement of the clock gate cell in the ldb_di[x]_clk
tree, the glitchy parent mux of ldb_di[x]_clk can cause a glitch to
enter the ldb_di_ipu_div divider. If the divider gets locked up, no
ldb_di[x]_clk is generated, and the LVDS display will hang when the
ipu_di_clk is sourced from ldb_di_clk.

To fix the problem, both the new and current parent of the ldb_di_clk
should be disabled before the switch. As this can not be guaranteed by
the clock framework during runtime, make the ldb_di[x]_sel muxes read-only.
A workaround to set the muxes once during boot could be added to the
kernel or bootloader.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
 drivers/clk/imx/clk-imx6q.c | 10 ++--------
 drivers/clk/imx/clk.h       |  8 ++++++++
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index dd33ebc..9bbc994 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -340,8 +340,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
 	clk[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
 	clk[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
-	clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
-	clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+	clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
+	clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
 	clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
 	clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
 	clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
@@ -593,12 +593,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 
 	clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
 
-	if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) ||
-	    clk_on_imx6dl()) {
-		clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-		clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-	}
-
 	clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
 	if (clk_on_imx6dl())
 		clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 3799ff8..4afad3b 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -75,6 +75,14 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate)
 	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
 }
 
+static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
+		u8 shift, u8 width, const char **parents, int num_parents)
+{
+	return clk_register_mux(NULL, name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
+			shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock);
+}
+
 static inline struct clk *imx_clk_fixed_factor(const char *name,
 		const char *parent, unsigned int mult, unsigned int div)
 {
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/3] clk: imx6: Mask mmdc_ch1 handshake for periph2_sel and mmdc_ch1_axi_podf
From: Fabio Estevam @ 2016-09-16 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>

MMDC CH1 is not used on i.MX6Q, so the handshake needed to change the
parent of periph2_sel or the divider of mmdc_ch1_axi_podf will never
succeed.
Disable the handshake mechanism to allow changing the frequency of
mmdc_ch1_axi, allowing to use it as a possible source for the LDB DI
clock.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
 drivers/clk/imx/clk-imx6q.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index ba1c1ae..dd33ebc 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -156,6 +156,19 @@ static struct clk ** const uart_clks[] __initconst = {
 	NULL
 };
 
+#define CCM_CCDR		0x04
+
+#define CCDR_MMDC_CH1_MASK	BIT(16)
+
+static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
+{
+	unsigned int reg;
+
+	reg = readl_relaxed(ccm_base + CCM_CCDR);
+	reg |= CCDR_MMDC_CH1_MASK;
+	writel_relaxed(reg, ccm_base + CCM_CCDR);
+}
+
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
 	struct device_node *np;
@@ -297,6 +310,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
 
+	imx6q_mmdc_ch1_mask_handshake(base);
+
 	/*                                              name                reg       shift width parent_names     num_parents */
 	clk[IMX6QDL_CLK_STEP]             = imx_clk_mux("step",	            base + 0xc,  8,  1, step_sels,	   ARRAY_SIZE(step_sels));
 	clk[IMX6QDL_CLK_PLL1_SW]          = imx_clk_mux("pll1_sw",	    base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-- 
2.7.4

^ permalink raw reply related

* [PATCH 5/6] arm/arm64: vgic-new: Implement VGICv3 CPU interface access
From: Marc Zyngier @ 2016-09-16 14:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474028453-29132-6-git-send-email-vijay.kilari@gmail.com>

On 16/09/16 13:20, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> VGICv3 CPU interface registers are accessed using
> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> as 64-bit. The cpu MPIDR value is passed along with register id.
> is used to identify the cpu for registers access.
> 
> The version of VGIC v3 specification is define here
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/445611.html
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm64/include/uapi/asm/kvm.h   |   3 +
>  arch/arm64/kvm/Makefile             |   1 +
>  include/linux/irqchip/arm-gic-v3.h  |  30 ++++
>  virt/kvm/arm/vgic/vgic-kvm-device.c |  27 ++++
>  virt/kvm/arm/vgic/vgic-mmio-v3.c    |  18 +++
>  virt/kvm/arm/vgic/vgic-sys-reg-v3.c | 296 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  10 ++
>  7 files changed, 385 insertions(+)
> 
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 56dc08d..91c7137 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -206,9 +206,12 @@ struct kvm_arch_memory_slot {
>  			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> +#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
>  /* Device Control API on vcpu fd */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index d50a82a..1a14e29 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -32,5 +32,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 88d83d3..d4e9c7d 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -355,6 +355,27 @@
>  #define ICC_CTLR_EL1_EOImode_SHIFT	(1)
>  #define ICC_CTLR_EL1_EOImode_drop_dir	(0U << ICC_CTLR_EL1_EOImode_SHIFT)
>  #define ICC_CTLR_EL1_EOImode_drop	(1U << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_EOImode_MASK	(1 << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_CBPR_SHIFT		(0)
> +#define ICC_CTLR_EL1_CBPR_MASK		(1 << ICC_CTLR_EL1_CBPR_SHIFT)
> +#define ICC_CTLR_EL1_PRI_BITS_SHIFT	(8)
> +#define ICC_CTLR_EL1_PRI_BITS_MASK	(0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
> +#define ICC_CTLR_EL1_ID_BITS_SHIFT	(11)
> +#define ICC_CTLR_EL1_ID_BITS_MASK	(0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
> +#define ICC_CTLR_EL1_SEIS_SHIFT		(14)
> +#define ICC_CTLR_EL1_SEIS_MASK		(0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
> +#define ICC_CTLR_EL1_A3V_SHIFT		(15)
> +#define ICC_CTLR_EL1_A3V_MASK		(0x1 << ICC_CTLR_EL1_A3V_SHIFT)
> +#define ICC_PMR_EL1_SHIFT		(0)
> +#define ICC_PMR_EL1_MASK		(0xff << ICC_PMR_EL1_SHIFT)
> +#define ICC_BPR0_EL1_SHIFT		(0)
> +#define ICC_BPR0_EL1_MASK		(0x7 << ICC_BPR0_EL1_SHIFT)
> +#define ICC_BPR1_EL1_SHIFT		(0)
> +#define ICC_BPR1_EL1_MASK		(0x7 << ICC_BPR1_EL1_SHIFT)
> +#define ICC_IGRPEN0_EL1_SHIFT		(0)
> +#define ICC_IGRPEN0_EL1_MASK		(1 << ICC_IGRPEN0_EL1_SHIFT)
> +#define ICC_IGRPEN1_EL1_SHIFT		(0)
> +#define ICC_IGRPEN1_EL1_MASK		(1 << ICC_IGRPEN1_EL1_SHIFT)
>  #define ICC_SRE_EL1_SRE			(1U << 0)
>  
>  /*
> @@ -398,6 +419,15 @@
>  #define ICH_VMCR_ENG1_SHIFT		1
>  #define ICH_VMCR_ENG1_MASK		(1 << ICH_VMCR_ENG1_SHIFT)
>  
> +#define ICH_VTR_PRI_BITS_SHIFT		29
> +#define ICH_VTR_PRI_BITS_MASK		(7 << ICH_VTR_PRI_BITS_SHIFT)
> +#define ICH_VTR_ID_BITS_SHIFT		23
> +#define ICH_VTR_ID_BITS_MASK		(7 << ICH_VTR_ID_BITS_SHIFT)
> +#define ICH_VTR_SEIS_SHIFT		22
> +#define ICH_VTR_SEIS_MASK		(1 << ICH_VTR_SEIS_SHIFT)
> +#define ICH_VTR_A3V_SHIFT		21
> +#define ICH_VTR_A3V_MASK		(1 << ICH_VTR_A3V_SHIFT)
> +

Same thing here. Please group all the additions to this file into a
single, independent patch.

>  #define ICC_IAR1_EL1_SPURIOUS		0x3ff
>  
>  #define ICC_SRE_EL2_SRE			(1 << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index a4656fc..a48101f 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -506,6 +506,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>  		if (!is_write)
>  			*reg = tmp32;
>  		break;
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 regid;
> +
> +		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
> +		ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
> +						  regid, reg);
> +		break;
> +	}
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -539,6 +547,15 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>  		reg = tmp32;
>  		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 reg;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
> +
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
>  	}
>  	return -ENXIO;
>  }
> @@ -565,6 +582,15 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>  		tmp32 = reg;
>  		return put_user(tmp32, uaddr);
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 reg;
> +
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
>  	}
>  
>  	return -ENXIO;
> @@ -583,6 +609,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS:
>  		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 83dece8..af748d7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -23,6 +23,7 @@
>  
>  #include "vgic.h"
>  #include "vgic-mmio.h"
> +#include "sys_regs.h"
>  
>  /* extract @num bytes at @offset bytes offset in data */
>  unsigned long extract_bytes(u64 data, unsigned int offset,
> @@ -639,6 +640,23 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>  		break;
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 reg, id;
> +		unsigned long mpidr;
> +		struct kvm_vcpu *vcpu;
> +
> +		mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
> +			 KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
> +
> +		vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr);

No. Your "mpidr" variable is not an MPIDR.  It represents the same
thing, but not with the right format.

> +		if (!vcpu)
> +			return -EINVAL;
> +		if (vcpu->vcpu_id >= atomic_read(&dev->kvm->online_vcpus))

How can that happen?

> +			return -EINVAL;
> +
> +		id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
> +		return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, &reg);
> +	}
>  	default:
>  		return -ENXIO;
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> new file mode 100644
> index 0000000..8e4f403
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> @@ -0,0 +1,296 @@
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +#include <asm/kvm_emulate.h>
> +#include <asm/kvm_arm.h>
> +#include <asm/kvm_mmu.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +#include "sys_regs.h"
> +
> +static bool access_gic_ctlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	struct vgic_vmcr vmcr;
> +	u64 val;
> +	u32 ich_vtr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (p->is_write) {
> +		val = p->regval;
> +		vmcr.ctlr &= ~(ICH_VMCR_CBPR_MASK | ICH_VMCR_EOIM_MASK);
> +		vmcr.ctlr |= ((val & ICC_CTLR_EL1_CBPR_MASK) >>
> +			      ICC_CTLR_EL1_CBPR_SHIFT) << ICH_VMCR_CBPR_SHIFT;
> +		vmcr.ctlr |= ((val & ICC_CTLR_EL1_EOImode_MASK) >>
> +			     ICC_CTLR_EL1_EOImode_SHIFT) << ICH_VMCR_EOIM_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);

You've ignored my comments again: "What if userspace writes something
that is incompatible with the current configuration? Wrong number of ID
bits, or number of priorities?"

> +	} else {
> +		ich_vtr = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
> +
> +		val = 0;
> +		val |= ((ich_vtr & ICH_VTR_PRI_BITS_MASK) >>
> +			ICH_VTR_PRI_BITS_SHIFT) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
> +		val |= ((ich_vtr & ICH_VTR_ID_BITS_MASK) >>
> +			ICH_VTR_ID_BITS_SHIFT) << ICC_CTLR_EL1_ID_BITS_SHIFT;
> +		val |= ((ich_vtr & ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT)
> +			<< ICC_CTLR_EL1_SEIS_SHIFT;
> +		val |= ((ich_vtr & ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT)
> +			<< ICC_CTLR_EL1_A3V_SHIFT;
> +		val |= ((vmcr.ctlr & ICH_VMCR_CBPR_MASK) >>
> +			ICH_VMCR_CBPR_SHIFT) << ICC_CTLR_EL1_CBPR_SHIFT;
> +		val |= ((vmcr.ctlr & ICH_VMCR_EOIM_MASK) >>
> +			ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
> +
> +		p->regval = val;
> +	}
> +
> +	return true;
> +}
> +
> +static bool access_gic_pmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			   const struct sys_reg_desc *r)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (p->is_write) {
> +		vmcr.pmr = (p->regval & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		p->regval = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +static bool access_gic_bpr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (p->is_write) {
> +		vmcr.bpr = (p->regval & ICC_BPR0_EL1_MASK) >>
> +			    ICC_BPR0_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		p->regval = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) &
> +			     ICC_BPR0_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +static bool access_gic_bpr1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (p->is_write) {
> +		vmcr.abpr = (p->regval & ICC_BPR1_EL1_MASK) >>
> +			     ICC_BPR1_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		p->regval = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) &
> +			     ICC_BPR1_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +static bool access_gic_grpen0(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (p->is_write) {
> +		vmcr.grpen0 = (p->regval & ICC_IGRPEN0_EL1_MASK) >>
> +				      ICC_IGRPEN0_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		p->regval = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) &
> +			     ICC_IGRPEN0_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +static bool access_gic_grpen1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (p->is_write) {
> +		vmcr.grpen1 = (p->regval & ICC_IGRPEN1_EL1_MASK) >>
> +				      ICC_IGRPEN1_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		p->regval = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) &
> +			     ICC_IGRPEN1_EL1_MASK;

>From the previous review comments: "Shouldn't this account for the
ICC_CTLR_EL1.CBPR setting?"

> +	}
> +
> +	return true;
> +}
> +
> +static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu,
> +				   struct sys_reg_params *p, u8 apr, u8 idx)
> +{
> +	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +	uint32_t *ap_reg;
> +
> +	if (apr)
> +		ap_reg = &vgicv3->vgic_ap1r[idx];
> +	else
> +		ap_reg = &vgicv3->vgic_ap0r[idx];
> +
> +	if (p->is_write)
> +		*ap_reg = p->regval;
> +	else
> +		p->regval = *ap_reg;
> +}
> +
> +static void access_gic_aprn(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r, u8 apr)
> +{
> +	u8 num_pri_bits, idx;
> +	u32 ich_vtr = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);

Maybe you should cache this once and for all? It is fairly unlikely to
change over time...

> +
> +
> +	num_pri_bits = ((ich_vtr & ICH_VTR_PRI_BITS_MASK) >>
> +			ICH_VTR_PRI_BITS_SHIFT) + 1;
> +	idx = r->Op2 & 3;
> +
> +	switch (num_pri_bits) {
> +	case 7:
> +		if (idx > 3)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, p, apr, idx);
> +		break;
> +	case 6:
> +		if (idx > 1)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, p, apr, idx);
> +		break;
> +	default:
> +		if (idx > 0)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, p, apr, idx);
> +	}
> +
> +	return;
> +err:
> +	if (!p->is_write)
> +		p->regval = 0;
> +}
> +
> +static bool access_gic_ap0r(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	access_gic_aprn(vcpu, p, r, 0);
> +
> +	return true;
> +}
> +
> +static bool access_gic_ap1r(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	access_gic_aprn(vcpu, p, r, 1);
> +
> +	return true;
> +}
> +
> +static bool access_gic_sre(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			   const struct sys_reg_desc *r)
> +{
> +	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	/* Read only. Write ignore */
> +	if (!p->is_write)
> +		p->regval = vgicv3->vgic_sre;
> +
> +	return true;
> +}
> +
> +static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
> +	/* ICC_PMR_EL1 */
> +	{ Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr },
> +	/* ICC_BPR0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0 },
> +	/* ICC_AP0R0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r },
> +	/* ICC_AP0R1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r },
> +	/* ICC_AP0R2_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r },
> +	/* ICC_AP0R3_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r },
> +	/* ICC_AP1R0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r },
> +	/* ICC_AP1R1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r },
> +	/* ICC_AP1R2_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r },
> +	/* ICC_AP1R3_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r },
> +	/* ICC_BPR1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1 },
> +	/* ICC_CTLR_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr },
> +	/* ICC_SRE_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre },
> +	/* ICC_IGRPEN0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0 },
> +	/* ICC_GRPEN1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1 },
> +};
> +
> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg)
> +{
> +	struct sys_reg_params params;
> +	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
> +
> +	params.regval = *reg;
> +	params.is_write = is_write;
> +	params.is_aarch32 = false;
> +	params.is_32bit = false;
> +
> +	if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
> +			      ARRAY_SIZE(gic_v3_icc_reg_descs)))
> +		return 0;
> +
> +	return -ENXIO;
> +}
> +
> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg)
> +{
> +	struct sys_reg_params params;
> +	const struct sys_reg_desc *r;
> +	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
> +
> +	if (is_write)
> +		params.regval = *reg;
> +	params.is_write = is_write;
> +	params.is_aarch32 = false;
> +	params.is_32bit = false;
> +
> +	r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
> +			   ARRAY_SIZE(gic_v3_icc_reg_descs));
> +	if (!r)
> +		return -ENXIO;
> +
> +	if (!r->access(vcpu, &params, r))
> +		return -EINVAL;
> +
> +	if (!is_write)
> +		*reg = params.regval;
> +
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 9ee54e3..4c0076c 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -30,6 +30,12 @@
>  
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
> +#define   KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM64_SYSREG_OP0_MASK | \
> +					KVM_REG_ARM64_SYSREG_OP1_MASK | \
> +					KVM_REG_ARM64_SYSREG_CRN_MASK | \
> +					KVM_REG_ARM64_SYSREG_CRM_MASK | \
> +					KVM_REG_ARM64_SYSREG_OP2_MASK)
> +
>  struct vgic_vmcr {
>  	u32	ctlr;
>  	u32	abpr;
> @@ -98,6 +104,10 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 u64 id, u64 *val);
> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg);
>  #else
>  static inline int vgic_register_its_iodevs(struct kvm *kvm)
>  {
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH v5 3/3] clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK
From: Fabio Estevam @ 2016-09-16 14:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160916013621.GB7398@tiger>

On Thu, Sep 15, 2016 at 10:36 PM, Shawn Guo <shawnguo@kernel.org> wrote:

>> Shawn,
>>
>> Are you happy with it?
>
> Acked-by: Shawn Guo <shawnguo@kernel.org>
>
> Please send it to clk maintainers for applying.

Thanks. Just sent it to the clk folks.

^ permalink raw reply

* [GIT PULL] ARM: exynos: Fixes for v4.8, secound round
From: Arnd Bergmann @ 2016-09-16 14:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474009808-8520-1-git-send-email-k.kozlowski@samsung.com>

On Friday, September 16, 2016 9:10:08 AM CEST Krzysztof Kozlowski wrote:
> 1. A recent change in populating irqchip devices from Device Tree
>    broke Suspend to RAM on Exynos boards due to lack of probing of
>    PMU (Power Management Unit) driver.  Multiple drivers attach to
>    the PMU's DT node: irqchip, clock controller and PMU platform
>    driver for handling suspend.  The new irqchip code marked the
>    PMU's DT node as OF_POPULATED but we need to attach to this
>    node also PMU platform driver.
> 
> 2. Add Javier as additional reviewer for Exynos patches.
> 

Pulled into fixes, thanks!

	Arnd

^ permalink raw reply

* [PATCH v3 1/3] tty: amba-pl011: define flag register bits for ZTE device
From: Sudeep Holla @ 2016-09-16 14:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1467968441-4056-2-git-send-email-shawn.guo@linaro.org>

Hi Shawn, Russell,

I noticed this change is in linux-next and but I happen to hit an issue
with this as I tested it with earlycon enabled today for the first time.

On 08/07/16 10:00, Shawn Guo wrote:
> For some reason we do not really understand, ZTE hardware designers
> choose to define PL011 Flag Register bit positions differently from
> standard ones as below.
>
> 	Bit		Standard	ZTE
> 	-----------------------------------
> 	CTS		0		1
> 	DSR		1		3
> 	BUSY		3		8
> 	RI		8		0
>
> Let's define these bits into vendor data and get ZTE PL011 supported
> properly.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>

[...]

> @@ -2303,13 +2325,16 @@ static struct console amba_console = {
>
>  static void pl011_putc(struct uart_port *port, int c)
>  {
> +	struct uart_amba_port *uap =
> +		container_of(port, struct uart_amba_port, port);
> +
>  	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
>  		cpu_relax();
>  	if (port->iotype == UPIO_MEM32)
>  		writel(c, port->membase + UART01x_DR);
>  	else
>  		writeb(c, port->membase + UART01x_DR);
> -	while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
> +	while (readl(port->membase + UART01x_FR) & uap->vendor->fr_busy)
>  		cpu_relax();
>  }

The above hunk won't work for early console devices. The earlycon_device
just has uart_port and is not uart_amba_port. I don't know how to fix
this properly but I thought we could reuse private_data in uart_port for
early_con devices. Something like below(incomplete for other vendors,
works only for ARM)

Regards,
Sudeep

-->8

diff --git i/drivers/tty/serial/amba-pl011.c 
w/drivers/tty/serial/amba-pl011.c
index 0b78b04e895e..abe88223790c 100644
--- i/drivers/tty/serial/amba-pl011.c
+++ w/drivers/tty/serial/amba-pl011.c
@@ -2330,8 +2330,7 @@ static struct console amba_console = {

  static void pl011_putc(struct uart_port *port, int c)
  {
-       struct uart_amba_port *uap =
-               container_of(port, struct uart_amba_port, port);
+       struct vendor_data *vendor = port->private_data;

         while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
                 cpu_relax();
@@ -2339,7 +2338,7 @@ static void pl011_putc(struct uart_port *port, int c)
                 writel(c, port->membase + UART01x_DR);
         else
                 writeb(c, port->membase + UART01x_DR);
-       while (readl(port->membase + UART01x_FR) & uap->vendor->fr_busy)
+       while (readl(port->membase + UART01x_FR) & vendor->fr_busy)
                 cpu_relax();
  }

@@ -2356,6 +2355,7 @@ static int __init pl011_early_console_setup(struct 
earlycon_device *device,
         if (!device->port.membase)
                 return -ENODEV;

+       device->port.private_data = &vendor_arm;
         device->con->write = pl011_early_write;
         return 0;
  }

^ permalink raw reply related

* [PATCH v4 21/22] phy: Add support for Qualcomm's USB HSIC phy
From: Rob Herring @ 2016-09-16 14:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160907213519.27340-22-stephen.boyd@linaro.org>

On Wed, Sep 07, 2016 at 02:35:18PM -0700, Stephen Boyd wrote:
> The HSIC USB controller on qcom SoCs has an integrated all
> digital phy controlled via the ULPI viewport.
> 
> Cc: Kishon Vijay Abraham I <kishon@ti.com>
> Cc: <devicetree@vger.kernel.org>
> Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
> ---
>  .../devicetree/bindings/phy/qcom,usb-hsic-phy.txt  |  65 +++++++++

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/phy/Kconfig                                |   7 +
>  drivers/phy/Makefile                               |   1 +
>  drivers/phy/phy-qcom-usb-hsic.c                    | 160 +++++++++++++++++++++
>  4 files changed, 233 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt
>  create mode 100644 drivers/phy/phy-qcom-usb-hsic.c

^ permalink raw reply

* [PATCH] pcie: qcom: add support to msm8996 PCIE controller
From: Rob Herring @ 2016-09-16 14:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473246412-24616-1-git-send-email-srinivas.kandagatla@linaro.org>

On Wed, Sep 07, 2016 at 12:06:52PM +0100, Srinivas Kandagatla wrote:
> This patch adds support to msm8996/apq8096 pcie, MSM8996 supports
> Gen 1/2, One lane, 3 pcie root-complex with support to MSI and
> legacy interrupts and it conforms to PCI Express Base 2.1 specification.
> 
> This patch adds post_init callback to qcom_pcie_ops, as this is pcie
> pipe clocks and smmu configuration are only setup after the phy is
> powered on. It also adds ltssm_enable callback as it is very much
> different to other supported SOCs in the driver.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
> 
> I tested this patch along with phy driver patch on DB820c based on
> APQ8096 on port A and port B using sata and ethernet controllers.
> 
> Thanks
> srini
> 
>  .../devicetree/bindings/pci/qcom,pcie.txt          |  88 +++++++-
>  drivers/pci/host/pcie-qcom.c                       | 237 ++++++++++++++++++++-
>  2 files changed, 318 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> index 4059a6f..1ddfcb4 100644
> --- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> @@ -92,6 +92,18 @@
>  			- "aux"		Auxiliary (AUX) clock
>  			- "bus_master"	Master AXI clock
>  			- "bus_slave"	Slave AXI clock
> +
> +- clock-names:
> +	Usage: required for msm8996/apq8096
> +	Value type: <stringlist>
> +	Definition: Should contain the following entries
> +			- "aux"		Auxiliary (AUX) clock
> +			- "bus_master"	Master AXI clock
> +			- "bus_slave"	Slave AXI clock
> +			- "pipe"	Pipe Clock driving internal logic.
> +			- "cfg"		Configuration clk.
> +			- "snoc_axi"	SNOC AXI clk
> +			- "cnoc_ahb"	CNOC AHB clk
>  - resets:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -114,8 +126,15 @@
>  	Definition: Should contain the following entries
>  			- "core" Core reset
>  
> +- iommus:
> +	Usage: required for msm8996/apq8096
> +	Value type: <prop-encoded-array>
> +	Definition: Should point to the respective IOMMU block with master port
> +		    as argument, see Documentation/devicetree/bindings/iommu/
> +		    mediatek,iommu.txt for details.
> +
>  - power-domains:
> -	Usage: required for apq8084
> +	Usage: required for apq8084 and msm8996/apq8096
>  	Value type: <prop-encoded-array>
>  	Definition: A phandle and power domain specifier pair to the
>  		    power domain which is responsible for collapsing
> @@ -137,6 +156,11 @@
>  	Definition: A phandle to the analog power supply for IC which generates
>  		    reference clock
>  
> +- vdda_1p8-supply:

Don't use '_' in property names.

> +	Usage: required for msm8996/apq8096
> +	Value type: <phandle>
> +	Definition: A phandle to the analog power supply for PCIE_1P8
> +
>  - phys:
>  	Usage: required for apq8084
>  	Value type: <phandle>
> @@ -231,3 +255,65 @@
>  		pinctrl-0 = <&pcie0_pins_default>;
>  		pinctrl-names = "default";
>  	};
> +
> +* Example for apq8096:
> +	pcie1: qcom,pcie at 00608000 {

pcie at ...

> +		compatible = "qcom,pcie-msm8996", "snps,dw-pcie";
> +		power-domains = <&gcc PCIE1_GDSC>;
> +		bus-range = <0x00 0xff>;
> +		num-lanes = <1>;
> +
> +		status  = "disabled";
> +
> +		reg = <0x00608000 0x2000>,
> +		      <0x0d000000 0xf1d>,
> +		      <0x0d000f20 0xa8>,
> +		      <0x0d100000 0x100000>;
> +
> +		reg-names = "parf", "dbi", "elbi","config";
> +
> +		phys = <&pcie_phy 1>;
> +		phy-names = "pciephy";
> +
> +		#address-cells = <3>;
> +		#size-cells = <2>;
> +		ranges = <0x01000000 0x0 0x0d200000 0x0d200000 0x0 0x100000>,
> +			<0x02000000 0x0 0x0d300000 0x0d300000 0x0 0xd00000>;
> +
> +		interrupts = <GIC_SPI 413 IRQ_TYPE_NONE>;
> +		interrupt-names = "msi";
> +		#interrupt-cells = <1>;
> +		interrupt-map-mask = <0 0 0 0x7>;
> +		interrupt-map = <0 0 0 1 &intc 0 272 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
> +				<0 0 0 2 &intc 0 273 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
> +				<0 0 0 3 &intc 0 274 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
> +				<0 0 0 4 &intc 0 275 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
> +
> +		pinctrl-names = "default", "sleep";
> +		pinctrl-0 = <&pcie1_clkreq_default &pcie1_perst_default &pcie1_wake_default>;
> +		pinctrl-1 = <&pcie1_clkreq_sleep &pcie1_perst_default &pcie1_wake_sleep>;
> +
> +
> +		vreg-1.8-supply = <&pm8994_l12>;
> +		vreg-0.9-supply = <&pm8994_l28>;

Doesn't match binding?

> +		iommus = <&anoc0_smmu>;
> +
> +		linux,pci-domain = <1>;
> +
> +		clocks = <&gcc GCC_PCIE_1_PIPE_CLK>,
> +			<&gcc GCC_PCIE_1_AUX_CLK>,
> +			<&gcc GCC_PCIE_1_CFG_AHB_CLK>,
> +			<&gcc GCC_PCIE_1_MSTR_AXI_CLK>,
> +			<&gcc GCC_PCIE_1_SLV_AXI_CLK>,
> +			<&gcc GCC_AGGRE0_SNOC_AXI_CLK>,
> +			<&gcc GCC_AGGRE0_CNOC_AHB_CLK>;
> +
> +		clock-names =  "pipe",
> +				"aux",
> +				"cfg",
> +				"bus_master",
> +				"bus_slave",
> +				"snoc_axi",
> +				"cnoc_ahb";
> +
> +	};

^ permalink raw reply

* [PATCH v6 2/3] ARM: dts: add TOPEET itop elite based board
From: ayaka @ 2016-09-16 14:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6bd9905d-0818-a917-8b8e-6abce134a3d3@kernel.org>



On 09/16/2016 03:23 PM, Krzysztof Kozlowski wrote:
> On 09/07/2016 11:58 PM, Randy Li wrote:
>> The TOPEET itop exynos 4412 have three versions base board. The
>> Elite version is the cheap one without too much peripheral devices
>> on it.
>>
>> Currently supported are serial console, wired networking(USB),
>> USB OTG in peripheral mode, USB host, SD storage, GPIO buttons,
>> PWM beeper, ADC and LEDs. The WM8960 analog audio codec is also
>> enabled.
>>
>> The FIMC is not used for camera currently, I enabled it just for a
>> colorspace convertor.
>>
>> Signed-off-by: Randy Li <ayaka@soulik.info>
>> ---
>>   .../bindings/arm/samsung/samsung-boards.txt        |   3 +
>>   arch/arm/boot/dts/Makefile                         |   1 +
>>   arch/arm/boot/dts/exynos4412-itop-elite.dts        | 239 +++++++++++++++++++++
>>   3 files changed, 243 insertions(+)
>>   create mode 100644 arch/arm/boot/dts/exynos4412-itop-elite.dts
>>
>> diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
>> index 0ea7f14..c7159ac 100644
>> --- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
>> +++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
>> @@ -22,6 +22,9 @@ Required root node properties:
>>     * FriendlyARM
>>   	- "friendlyarm,tiny4412"  - for Exynos4412-based FriendlyARM
>>   				    TINY4412 board.
>> +  * TOPEET
>> +	- "topeet,itop4412-elite" - for Exynos4412-based TOPEET
>> +                                    Elite base board.
>>   
>>     * Google
>>   	- "google,pi"		- for Exynos5800-based Google Peach Pi
>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>> index 207f96f..0b39d00 100644
>> --- a/arch/arm/boot/dts/Makefile
>> +++ b/arch/arm/boot/dts/Makefile
>> @@ -130,6 +130,7 @@ dtb-$(CONFIG_ARCH_EXYNOS4) += \
>>   	exynos4210-smdkv310.dtb \
>>   	exynos4210-trats.dtb \
>>   	exynos4210-universal_c210.dtb \
>> +	exynos4412-itop-elite.dtb \
>>   	exynos4412-odroidu3.dtb \
>>   	exynos4412-odroidx.dtb \
>>   	exynos4412-odroidx2.dtb \
>> diff --git a/arch/arm/boot/dts/exynos4412-itop-elite.dts b/arch/arm/boot/dts/exynos4412-itop-elite.dts
>> new file mode 100644
>> index 0000000..dd83689
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/exynos4412-itop-elite.dts
>> @@ -0,0 +1,239 @@
>> +/*
>> + * TOPEET's Exynos4412 based itop board device tree source
>> + *
>> + * Copyright (c) 2016 SUMOMO Computer Association
>> + *			https://www.sumomo.mobi
>> + *			Randy Li <ayaka@soulik.info>
>> + *			
>> + * Device tree source file for TOPEET iTop Exynos 4412 core board
>> + * which is based on Samsung's Exynos4412 SoC.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> +*/
>> +
>> +/dts-v1/;
>> +#include <dt-bindings/sound/samsung-i2s.h>
>> +#include "exynos4412-itop-scp-core.dtsi"
>> +
>> +/ {
>> +	model = "TOPEET iTop 4412 Elite board based on Exynos4412";
>> +	compatible = "topeet,itop4412-elite", "samsung,exynos4412", "samsung,exynos4";
>> +
>> +	chosen {
>> +		bootargs = "root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait";
>> +		stdout-path = "serial2:115200n8";
>> +	};
>> +	
>> +	leds {
>> +		compatible = "gpio-leds";
>> +		
>> +		led2 {
>> +			label = "red:system";
>> +			gpios = <&gpx1 0 GPIO_ACTIVE_HIGH>;
>> +			default-state = "off";
>> +			linux,default-trigger = "heartbeat";
>> +		};
>> +
>> +		led3 {
>> +			label = "red:user";
>> +			gpios = <&gpk1 1 GPIO_ACTIVE_HIGH>;
>> +			default-state = "off";
>> +		};
>> +	};
>> +
>> +	gpio-keys {
>> +		compatible = "gpio-keys";
>> +		
>> +		home {
>> +			label = "GPIO Key Home";
>> +			linux,code = <KEY_HOME>;
>> +			gpios = <&gpx1 1 GPIO_ACTIVE_LOW>;
>> +		};
>> +
>> +		back {
>> +			label = "GPIO Key Back";
>> +			linux,code = <KEY_BACK>;
>> +			gpios = <&gpx1 2 GPIO_ACTIVE_LOW>;
>> +		};
>> +
>> +		sleep {
>> +			label = "GPIO Key Sleep";
>> +			linux,code = <KEY_POWER>;
>> +			gpios = <&gpx3 3 GPIO_ACTIVE_LOW>;
>> +		};
>> +
>> +		vol-up {
>> +			label = "GPIO Key Vol+";
>> +			linux,code = <KEY_UP>;
>> +			gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
>> +		};
>> +
>> +		vol-down {
>> +			label = "GPIO Key Vol-";
>> +			linux,code = <KEY_DOWN>;
>> +			gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
>> +		};
>> +	};
>> +
>> +	sound {
>> +		compatible = "simple-audio-card";
>> +		simple-audio-card,name = "wm-sound";
>> +
>> +		assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
>> +				<&clock_audss EXYNOS_MOUT_I2S>,
>> +				<&clock_audss EXYNOS_DOUT_SRP>,
>> +				<&clock_audss EXYNOS_DOUT_AUD_BUS>;
>> +		assigned-clock-parents = <&clock CLK_FOUT_EPLL>,
>> +				<&clock_audss EXYNOS_MOUT_AUDSS>;
>> +		assigned-clock-rates = <0>,
>> +				<0>,
>> +				<112896000>,
>> +				<11289600>;
>> +
>> +		simple-audio-card,format = "i2s";
>> +		simple-audio-card,bitclock-master = <&link0_codec>;
>> +		simple-audio-card,frame-master = <&link0_codec>;
>> +
>> +		simple-audio-card,widgets =
>> +			"Microphone", "Mic Jack",
>> +			"Line", "Line In",
>> +			"Line", "Line Out",
>> +			"Speaker", "Speaker",
>> +			"Headphone", "Headphone Jack";
>> +		simple-audio-card,routing =
>> +			"Headphone Jack", "HP_L",
>> +			"Headphone Jack", "HP_R",
>> +			"Speaker", "SPK_LP",
>> +			"Speaker", "SPK_LN",
>> +			"Speaker", "SPK_RP",
>> +			"Speaker", "SPK_RN",
>> +			"LINPUT1", "Mic Jack",
>> +			"LINPUT3", "Mic Jack",
>> +			"RINPUT1", "Mic Jack",
>> +			"RINPUT2", "Mic Jack";
>> +
>> +		simple-audio-card,cpu {
>> +			sound-dai = <&i2s0 0>;
>> +		};
>> +
>> +		link0_codec: simple-audio-card,codec {
>> +			sound-dai = <&codec>;
>> +			clocks = <&i2s0 CLK_I2S_CDCLK>;
>> +			system-clock-frequency = <11289600>;
>> +		};
>> +	};
>> +	
>> +	beep {
>> +		compatible = "pwm-beeper";
>> +		pwms = <&pwm 0 4000000 PWM_POLARITY_INVERTED>;
> I have serious doubts that you run this code... if it does not even
> compile. Sorry, I cannot accept code that does not compile and was not
> tested.
>
> Please, test your DTS on top of current Linux tree, which would be one of:
> 1. Linus' master branch: v4.8-rc6,
> 2. one of my branches (for-next, next/dt etc),
When I sent those patches, I tested in "Add linux-next specific files 
for 20160907"
> 3. recent linux-next.
>
> Best regards,
> Krzysztof

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).