* [PATCH] arm64: smp: Prevent raw_smp_processor_id() recursion
From: Catalin Marinas @ 2016-12-01 17:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2bd54897-df2e-a20e-d748-07966642b850@arm.com>
On Thu, Dec 01, 2016 at 05:16:50PM +0000, Robin Murphy wrote:
> On 01/12/16 15:55, Robin Murphy wrote:
> > Under CONFIG_DEBUG_PREEMPT=y, this_cpu_ptr() ends up calling back into
> > raw_smp_processor_id(), resulting in some hilariously catastrophic
> > infinite recursion. In the normal case, we have:
> >
> > #define this_cpu_ptr(ptr) raw_cpu_ptr(ptr)
> >
> > and everything is dandy. However for CONFIG_DEBUG_PREEMPT, this_cpu_ptr()
> > is defined in terms of my_cpu_offset, wherein the fun begins:
> >
> > #define my_cpu_offset per_cpu_offset(smp_processor_id())
> > ...
> > #define smp_processor_id() debug_smp_processor_id()
> > ...
> > notrace unsigned int debug_smp_processor_id(void)
> > {
> > return check_preemption_disabled("smp_processor_id", "");
> > ...
> > notrace static unsigned int check_preemption_disabled(const char *what1,
> > const char *what2)
> > {
> > int this_cpu = raw_smp_processor_id();
> >
> > and bang. Use raw_cpu_ptr() directly to avoid that.
> >
> > Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > Acked-by: Will Deacon <will.deacon@arm.com>
> > Signed-off-by: Robin Murphy <robin.murphy@arm.com>
>
> I wasn't sure whether commit IDs on for-next/core are stable, but if
> they are, this could also have:
>
> Fixes: 57c82954e77f ("arm64: make cpu number a percpu variable")
It depends on which branch is pulled into next. I keep the for-next/core
stable at this stage, so I'll include the Fixes like as well. Thanks.
--
Catalin
^ permalink raw reply
* [PATCH dt V2] ARM: BCM5301X: Enable UART by default for BCM4708(1), BCM4709(4) & BCM53012
From: Rafał Miłecki @ 2016-12-01 17:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161128140134.25128-1-zajec5@gmail.com>
From: Rafa? Mi?ecki <rafal@milecki.pl>
Every device tested so far got UART0 (at 0x18000300) working as serial
console. It's most likely part of reference design and all vendors use
it that way.
It seems to be easier to enable it by default and just disable it if we
ever see a device with different hardware design.
Signed-off-by: Rafa? Mi?ecki <rafal@milecki.pl>
---
V2: Update bcm94708.dts bcm94709.dts bcm953012er.dts & bcm953012k.dts
---
arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 4 ----
arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts | 4 ----
arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts | 4 ----
arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 4 ----
arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts | 4 ----
arch/arm/boot/dts/bcm4708.dtsi | 4 ++++
arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 4 ----
arch/arm/boot/dts/bcm47081.dtsi | 4 ++++
arch/arm/boot/dts/bcm4709-netgear-r7000.dts | 4 ----
arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 4 ----
arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts | 4 ----
arch/arm/boot/dts/bcm4709.dtsi | 1 +
arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts | 4 ----
arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts | 4 ----
arch/arm/boot/dts/bcm47094-netgear-r8500.dts | 4 ----
arch/arm/boot/dts/bcm47094.dtsi | 1 +
arch/arm/boot/dts/bcm94708.dts | 4 ----
arch/arm/boot/dts/bcm94709.dts | 4 ----
arch/arm/boot/dts/bcm953012er.dts | 4 ----
arch/arm/boot/dts/bcm953012k.dts | 1 -
20 files changed, 10 insertions(+), 61 deletions(-)
diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
index 9cb186e..d49afec0 100644
--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
@@ -136,10 +136,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&usb2 {
vcc-gpio = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
index 35e6ed6..f591b0f 100644
--- a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
+++ b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
@@ -55,10 +55,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&spi_nor {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
index 1c7e53d..50d65d8 100644
--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
@@ -56,10 +56,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&spi_nor {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
index 8ce39d5..8519548 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
@@ -83,10 +83,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&usb3 {
vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
index 70f4bb9..74cfcd3 100644
--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
@@ -119,10 +119,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&spi_nor {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index eed4dd1..d0eec09 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -34,3 +34,7 @@
};
};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
index a9c8def..2922536 100644
--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
@@ -122,7 +122,3 @@
};
};
};
-
-&uart0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/bcm47081.dtsi b/arch/arm/boot/dts/bcm47081.dtsi
index f720012..c5f7619 100644
--- a/arch/arm/boot/dts/bcm47081.dtsi
+++ b/arch/arm/boot/dts/bcm47081.dtsi
@@ -24,3 +24,7 @@
};
};
};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
index fd38d2a..0225d82 100644
--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
@@ -100,7 +100,3 @@
};
};
};
-
-&uart0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
index 92f8a72..56d38a3 100644
--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
@@ -107,10 +107,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&usb2 {
vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
index 9a92c24..c67bfaa 100644
--- a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
+++ b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
@@ -97,10 +97,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&usb2 {
vcc-gpio = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm4709.dtsi b/arch/arm/boot/dts/bcm4709.dtsi
index f039765..c645fea 100644
--- a/arch/arm/boot/dts/bcm4709.dtsi
+++ b/arch/arm/boot/dts/bcm4709.dtsi
@@ -8,4 +8,5 @@
&uart0 {
clock-frequency = <125000000>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
index 661348d..7fb9270 100644
--- a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
+++ b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
@@ -105,10 +105,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&usb3 {
vcc-gpio = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
index 169b35f..2f4a651 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
@@ -98,10 +98,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&usb3 {
vcc-gpio = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
index 521b415..7ecd57c 100644
--- a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
+++ b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
@@ -97,7 +97,3 @@
};
};
};
-
-&uart0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/bcm47094.dtsi b/arch/arm/boot/dts/bcm47094.dtsi
index 4f09aa0..4840a78 100644
--- a/arch/arm/boot/dts/bcm47094.dtsi
+++ b/arch/arm/boot/dts/bcm47094.dtsi
@@ -14,4 +14,5 @@
&uart0 {
clock-frequency = <125000000>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm94708.dts b/arch/arm/boot/dts/bcm94708.dts
index 251a486..42855a7 100644
--- a/arch/arm/boot/dts/bcm94708.dts
+++ b/arch/arm/boot/dts/bcm94708.dts
@@ -50,7 +50,3 @@
reg = <0x00000000 0x08000000>;
};
};
-
-&uart0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/bcm94709.dts b/arch/arm/boot/dts/bcm94709.dts
index b16cac9..95e8be6 100644
--- a/arch/arm/boot/dts/bcm94709.dts
+++ b/arch/arm/boot/dts/bcm94709.dts
@@ -50,7 +50,3 @@
reg = <0x00000000 0x08000000>;
};
};
-
-&uart0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/bcm953012er.dts b/arch/arm/boot/dts/bcm953012er.dts
index 0a9abec..decd86b 100644
--- a/arch/arm/boot/dts/bcm953012er.dts
+++ b/arch/arm/boot/dts/bcm953012er.dts
@@ -70,10 +70,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&spi_nor {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm953012k.dts b/arch/arm/boot/dts/bcm953012k.dts
index 05a985a..bfd9230 100644
--- a/arch/arm/boot/dts/bcm953012k.dts
+++ b/arch/arm/boot/dts/bcm953012k.dts
@@ -54,7 +54,6 @@
&uart0 {
clock-frequency = <62499840>;
- status = "okay";
};
&uart1 {
--
2.10.1
^ permalink raw reply related
* [PATCH v4 2/3] doc: dt: add cyclone-spi binding document
From: Moritz Fischer @ 2016-12-01 17:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <137f03de76e5f865430b17ca247e8f73e3315c8d.1480551148.git.stillcompiling@gmail.com>
On Thu, Dec 1, 2016 at 9:04 AM, Joshua Clayton <stillcompiling@gmail.com> wrote:
> Describe a cyclonei-ps-spi devicetree entry, required features
>
> Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
Acked-by: Moritz Fischer <moritz.fischer@ettus.com>
> ---
>
> .../bindings/fpga/cyclone-ps-spi-fpga-mgr.txt | 25 ++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
>
> diff --git a/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
> new file mode 100644
> index 0000000..3f515c7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
> @@ -0,0 +1,25 @@
> +Altera Cyclone Passive Serial SPI FPGA Manager
> +
> +Altera Cyclone FPGAs support a method of loading the bitstream over what is
> +referred to as "passive serial".
> +The passive serial link is not technically spi, and might require extra
> +circuits in order to play nicely with other spi slaves on the same bus.
> +
> +See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf
> +
> +Required properties:
> +- compatible : should contain "altr,cyclone-ps-spi-fpga-mgr"
> +- reg : spi slave id of the fpga
> +- config-gpios : config pin (referred to as nCONFIG in the cyclone manual)
> +- status-gpios : status pin (referred to as nSTATUS in the cyclone manual)
> +
> +both gpio pins are normally active low open drain.
> +
> +Example:
> + fpga_spi: evi-fpga-spi at 0 {
> + compatible = "altr,cyclone-ps-spi-fpga-mgr";
> + spi-max-frequency = <20000000>;
> + reg = <0>;
> + config-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>;
> + status-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
> + };
> --
> 2.9.3
>
^ permalink raw reply
* [PATCH v3] ARM: davinci: da8xx: Fix sleeping function called from invalid context
From: David Lechner @ 2016-12-01 17:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480612342-23614-1-git-send-email-abailon@baylibre.com>
On 12/01/2016 11:12 AM, Alexandre Bailon wrote:
> Everytime the usb20 phy is enabled, there is a
Every time is two words
> "sleeping function called from invalid context" BUG.
>
> clk_enable() from arch/arm/mach-davinci/clock.c uses spin_lock_irqsave()
> before to invoke the callback usb20_phy_clk_enable().
> usb20_phy_clk_enable() uses clk_get() and clk_enable_prepapre()
> which may sleep.
> Move clk_get() to da8xx_register_usb20_phy_clk() and
> replace clk_prepare_enable() by clk_enable().
>
> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
> ---
> arch/arm/mach-davinci/usb-da8xx.c | 23 ++++++++++++-----------
> 1 file changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
> index b010e5f..bfb55b9 100644
> --- a/arch/arm/mach-davinci/usb-da8xx.c
> +++ b/arch/arm/mach-davinci/usb-da8xx.c
> @@ -156,23 +156,18 @@ int __init da8xx_register_usb_refclkin(int rate)
> return 0;
> }
>
> +static struct clk *usb20_clk;
Not a serious issue, but I would rather have the global variable
declared at the beginning of the file to make it more obvious there is a
global variable.
> +
> static void usb20_phy_clk_enable(struct clk *clk)
> {
> - struct clk *usb20_clk;
> int err;
> u32 val;
> u32 timeout = 500000; /* 500 msec */
>
> val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
>
> - usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
> - if (IS_ERR(usb20_clk)) {
> - pr_err("could not get usb20 clk: %ld\n", PTR_ERR(usb20_clk));
> - return;
> - }
> -
> /* The USB 2.O PLL requires that the USB 2.O PSC is enabled as well. */
> - err = clk_prepare_enable(usb20_clk);
> + err = clk_enable(usb20_clk);
> if (err) {
> pr_err("failed to enable usb20 clk: %d\n", err);
> clk_put(usb20_clk);
> @@ -197,8 +192,7 @@ static void usb20_phy_clk_enable(struct clk *clk)
>
> pr_err("Timeout waiting for USB 2.0 PHY clock good\n");
> done:
> - clk_disable_unprepare(usb20_clk);
> - clk_put(usb20_clk);
> + clk_disable(usb20_clk);
> }
>
> static void usb20_phy_clk_disable(struct clk *clk)
> @@ -287,9 +281,16 @@ int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
> struct clk *parent;
> int ret = 0;
No longer need to initialize ret here.
>
> + usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
> + ret = PTR_ERR_OR_ZERO(usb20_clk);
> + if (ret)
> + return ret;
> +
> parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "pll0_aux");
> - if (IS_ERR(parent))
> + if (IS_ERR(parent)) {
why not use ret = PTR_ERR_OR_ZERO(parent) pattern here too?
> + clk_put(usb20_clk);
The global usb20_clk is no longer valid after this. Should we set it to
NULL here?
> return PTR_ERR(parent);
> + }
>
> usb20_phy_clk.parent = parent;
> ret = clk_register(&usb20_phy_clk);
>
^ permalink raw reply
* [PATCH V1 1/2] PCI: thunder: Enable ACPI PCI controller for ThunderX pass2.x silicon version
From: Bjorn Helgaas @ 2016-12-01 17:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201145450.GA10353@red-moon>
On Thu, Dec 01, 2016 at 02:54:50PM +0000, Lorenzo Pieralisi wrote:
> On Thu, Dec 01, 2016 at 02:55:49PM +0100, Robert Richter wrote:
> > Tomasz, Bjorn,
> >
> > On 01.12.16 09:49:51, Tomasz Nowicki wrote:
> > > I put the picture together here (on top of your pci/ecam branch):
> > > [1] https://github.com/semihalf-nowicki-tomasz/linux/commits/pci-quirks-thunderx-v2
> >
> > please note that acpi_* functions must be protected with acpi_disabled
> > or something else to make sure an acpi enabled kernel does not break
> > dt. See the crash below with above branch.
>
> You could use struct device.of_node, or just move the MCFG check to ACPI
> code that probes the root bus in arm64 before calling pci_ecam_create()
> which will save you some ifdeffery too while at it.
Oh, I like that idea even better! I took the acpi_disabled check back out
of acpi_resource_consumer() and moved the call to
pci_acpi_setup_ecam_mapping(). Thanks!
> > [ 12.493028] Unable to handle kernel NULL pointer dereference at virtual address 00000018
> > [ 12.501113] pgd = ffff0000090a0000
> > [ 12.504511] [00000018] *pgd=0000010fffef0003[ 12.508602] , *pud=0000010fffef0003
> > , *pmd=0000010fffee0003[ 12.514093] , *pte=0000000000000000
> > [ 12.517575]
> > [ 12.519064] Internal error: Oops: 96000005 [#1] SMP
> > [ 12.523933] Modules linked in:
> > [ 12.526987] CPU: 73 PID: 1 Comm: swapper/0 Tainted: G W 4.9.0-rc6.0.vanilla10-00019-g09abd2b6bbeb #135
> > [ 12.537409] Hardware name: Cavium ThunderX CRB/To be filled by O.E.M., BIOS 5.11 12/12/2012
> > [ 12.545748] task: ffff800fe85b8000 task.stack: ffff800ff4288000
> > [ 12.551674] PC is at acpi_ns_walk_namespace+0x68/0x1d4
> > [ 12.556803] LR is at acpi_get_devices+0x6c/0x94
> > ...
> > [ 13.124920] [<ffff0000084dc5a0>] acpi_ns_walk_namespace+0x68/0x1d4
> > [ 13.131090] [<ffff0000084dcadc>] acpi_get_devices+0x6c/0x94
> > [ 13.136663] [<ffff0000084c0aec>] acpi_resource_consumer+0x34/0x44
> > [ 13.142752] [<ffff000008496bc0>] pci_ecam_create+0x80/0x228
> > [ 13.148314] [<ffff000008498e64>] pci_host_common_probe+0x294/0x348
> > [ 13.154486] [<ffff00000849bf3c>] thunder_ecam_probe+0x2c/0x38
> > [ 13.160226] [<ffff0000085880b8>] platform_drv_probe+0x60/0xc8
> > [ 13.165970] [<ffff000008585a04>] driver_probe_device+0x26c/0x420
> > [ 13.171966] [<ffff000008585cdc>] __driver_attach+0x124/0x128
> > [ 13.177615] [<ffff000008583238>] bus_for_each_dev+0x70/0xb0
> > [ 13.183177] [<ffff000008585060>] driver_attach+0x30/0x40
> > [ 13.188478] [<ffff000008584a98>] bus_add_driver+0x200/0x2b8
> > [ 13.194041] [<ffff000008586860>] driver_register+0x68/0x100
> > [ 13.199602] [<ffff000008587fdc>] __platform_driver_register+0x54/0x60
> > [ 13.206038] [<ffff000008c39b98>] thunder_ecam_driver_init+0x18/0x20
> > [ 13.212296] [<ffff000008082d94>] do_one_initcall+0x44/0x138
> > [ 13.217862] [<ffff000008c00d0c>] kernel_init_freeable+0x1ac/0x24c
> > [ 13.223950] [<ffff0000088605f0>] kernel_init+0x18/0x110
> > [ 13.229165] [<ffff000008082b30>] ret_from_fork+0x10/0x20
^ permalink raw reply
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Bjorn Helgaas @ 2016-12-01 18:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480549373-2123-1-git-send-email-dhdang@apm.com>
Hi Duc,
On Wed, Nov 30, 2016 at 03:42:53PM -0800, Duc Dang wrote:
> PCIe controllers in X-Gene SoCs is not ECAM compliant: software
> needs to configure additional controller's register to address
> device at bus:dev:function.
>
> The quirk will only be applied for X-Gene PCIe MCFG table with
> OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs).
>
> The quirk declares the X-Gene PCIe controller register space as 64KB
> fixed memory resource with name "PCIe CSR". This name will be showed
> next to the resource range in the output of "cat /proc/iomem".
>
> Signed-off-by: Duc Dang <dhdang@apm.com>
> ---
> v3:
> - Rebase on top of pci/ecam-v6 tree.
> - Use DEFINE_RES_MEM_NAMED to declare controller register space
> with name "PCIe CSR"
> v2:
> RFC v2: https://patchwork.ozlabs.org/patch/686846/
> v1:
> RFC v1: https://patchwork.kernel.org/patch/9337115/
>
> drivers/acpi/pci_mcfg.c | 31 ++++++++
> drivers/pci/host/pci-xgene.c | 165 ++++++++++++++++++++++++++++++++++++++++++-
> include/linux/pci-ecam.h | 7 ++
> 3 files changed, 200 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> index ac21db3..eb6125b 100644
> --- a/drivers/acpi/pci_mcfg.c
> +++ b/drivers/acpi/pci_mcfg.c
> @@ -57,6 +57,37 @@ struct mcfg_fixup {
> { "QCOM ", "QDF2432 ", 1, 5, MCFG_BUS_ANY, &pci_32b_ops },
> { "QCOM ", "QDF2432 ", 1, 6, MCFG_BUS_ANY, &pci_32b_ops },
> { "QCOM ", "QDF2432 ", 1, 7, MCFG_BUS_ANY, &pci_32b_ops },
> +
> +#ifdef CONFIG_PCI_XGENE
As you've no doubt noticed, I'm proposing to add these quirks without
CONFIG_PCI_XGENE, so we don't have to select each device when building
a generic ACPI kernel.
I'm also proposing some Kconfig and Makefile changes so we don't build
the platform driver part in a generic ACPI kernel (unless we *also*
explicitly select the platform driver).
Here's an example:
https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/commit/?h=pci/ecam&id=f80edf4d6c05
> +#define XGENE_V1_ECAM_MCFG(rev, seg) \
> + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
> + &xgene_v1_pcie_ecam_ops }
> +#define XGENE_V2_1_ECAM_MCFG(rev, seg) \
> + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
> + &xgene_v2_1_pcie_ecam_ops }
> +#define XGENE_V2_2_ECAM_MCFG(rev, seg) \
> + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
> + &xgene_v2_2_pcie_ecam_ops }
> +
> + /* X-Gene SoC with v1 PCIe controller */
> + XGENE_V1_ECAM_MCFG(1, 0),
> + XGENE_V1_ECAM_MCFG(1, 1),
> @@ -64,6 +66,7 @@
> /* PCIe IP version */
> #define XGENE_PCIE_IP_VER_UNKN 0
> #define XGENE_PCIE_IP_VER_1 1
> +#define XGENE_PCIE_IP_VER_2 2
This isn't used anywhere, which makes me wonder whether it's worth
keeping it.
> static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
> {
> - struct xgene_pcie_port *port = bus->sysdata;
> + struct pci_config_window *cfg;
> + struct xgene_pcie_port *port;
> +
> + if (acpi_disabled)
> + port = bus->sysdata;
> + else {
> + cfg = bus->sysdata;
> + port = cfg->priv;
> + }
I would really, really like to figure out a way to get rid of these
"if (acpi_disabled)" checks sprinkled through here. Is there any way
we can set up bus->sysdata to be the same, regardless of whether we're
using this as a platform driver or an ACPI quirk?
> +#ifdef CONFIG_ACPI
You've probably noticed that I've been using
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
in this situation, mostly to make it clear that this is part of a
workaround. I don't want people to blindly copy this stuff without
realizing that it's a workaround for a hardware issue.
> +static struct resource xgene_v1_csr_res[] = {
> + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
> + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
> + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
> + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
> + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
I assume these ranges are not the actual ECAM space, right?
If they *were* ECAM, I assume you would have included them in the
quirk itself in the mcfg_quirks[] table.
> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
> +{
> + struct acpi_device *adev = to_acpi_device(cfg->parent);
> + struct acpi_pci_root *root = acpi_driver_data(adev);
> + struct device *dev = cfg->parent;
> + struct xgene_pcie_port *port;
> + struct resource *csr;
> +
> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> + if (!port)
> + return -ENOMEM;
> +
> + csr = &xgene_v1_csr_res[root->segment];
This makes me nervous because root->segment comes from the ACPI _SEG,
and if firmware gives us junk in _SEG, we will reference something in
the weeds.
> + port->csr_base = devm_ioremap_resource(dev, csr);
> + if (IS_ERR(port->csr_base)) {
> + kfree(port);
> + return -ENOMEM;
> + }
> +
> + port->cfg_base = cfg->win;
> + port->version = XGENE_PCIE_IP_VER_1;
> +
> + cfg->priv = port;
All these init functions are almost identical. Can we factor this out
by having wrappers that do nothing more than pass in the table and
version, and put the kzalloc and ioremap in a shared back-end?
We're so close I can taste it! I can't wait to see all this work come
to fruition.
Bjorn
^ permalink raw reply
* [GIT PULL 1/3] ARM: exynos: Soc/mach for v4.10
From: Krzysztof Kozlowski @ 2016-12-01 18:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479967709-6619-2-git-send-email-krzk@kernel.org>
On Thu, Nov 24, 2016 at 08:08:27AM +0200, Krzysztof Kozlowski wrote:
> Hi,
>
> This contains previous dts branch because SCU node in dts is needed
> prior to removing it from mach code.
>
> Below you will find full pull request and one stripped from dependency.
>
Hi Arnd, Kevin and Olof,
What about this pull from the set?
Best regards,
Krzysztof
> Best regards,
> Krzysztof
>
>
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
>
> Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git tags/samsung-soc-4.10
>
> for you to fetch changes up to c689de56c0a7c8387ea00509f94fa483ae61d979:
>
> ARM: Drop fixed 200 Hz timer requirement from Samsung platforms (2016-11-23 19:34:55 +0200)
>
> ----------------------------------------------------------------
> Samsung mach/soc update for v4.10:
> 1. Use SCU mapping from Device Tree instead of statically mapped one.
> 2. Drop fixed requirement for HZ=200 on Samsung platforms.
>
> ----------------------------------------------------------------
> Javier Martinez Canillas (1):
> ARM: dts: exynos: Document eMMC/SD/SDIO devices in Snow and Peach boards
>
> Krzysztof Kozlowski (3):
> ARM: dts: exynos: Remove exynos4415.dtsi
> Merge tag 'samsung-dt-4.10' into next/soc
> ARM: Drop fixed 200 Hz timer requirement from Samsung platforms
>
> Pankaj Dubey (4):
> ARM: EXYNOS: Remove smp_init_cpus hook from platsmp.c
> ARM: dts: exynos: Add SCU device node to exynos4.dtsi
> ARM: EXYNOS: Remove static mapping of SCU SFR
> ARM: EXYNOS: Remove unused soc_is_exynos{4,5}
>
> Randy Li (2):
> ARM: dts: exynos: Add TOPEET itop core board SCP package version
> ARM: dts: exynos: Add TOPEET itop elite based board
>
> Sylwester Nawrocki (3):
> ARM: dts: exynos: Remove "simple-bus" compatible from fimc-is node
> ARM: dts: exynos: Add entries for sound support on Odroid-XU board
> ARM: S3C24XX: Add DMA slave maps for remaining s3c24xx SoCs
>
> .../bindings/arm/samsung/samsung-boards.txt | 3 +
> arch/arm/Kconfig | 3 +-
> arch/arm/boot/dts/Makefile | 1 +
> arch/arm/boot/dts/exynos4.dtsi | 5 +
> arch/arm/boot/dts/exynos4412-itop-elite.dts | 240 ++++++++
> arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi | 501 ++++++++++++++++
> arch/arm/boot/dts/exynos4415-pinctrl.dtsi | 575 ------------------
> arch/arm/boot/dts/exynos4415.dtsi | 650 ---------------------
> arch/arm/boot/dts/exynos4x12.dtsi | 2 +-
> arch/arm/boot/dts/exynos5250-snow-common.dtsi | 4 +
> arch/arm/boot/dts/exynos5410-odroidxu.dts | 69 +++
> arch/arm/boot/dts/exynos5410-pinctrl.dtsi | 9 +
> arch/arm/boot/dts/exynos5410.dtsi | 59 ++
> arch/arm/boot/dts/exynos5420-peach-pit.dts | 3 +
> arch/arm/boot/dts/exynos5800-peach-pi.dts | 3 +
> arch/arm/mach-exynos/common.h | 6 +-
> arch/arm/mach-exynos/exynos.c | 22 -
> arch/arm/mach-exynos/include/mach/map.h | 2 -
> arch/arm/mach-exynos/platsmp.c | 65 +--
> arch/arm/mach-exynos/pm.c | 4 +-
> arch/arm/mach-exynos/suspend.c | 4 +-
> arch/arm/mach-s3c24xx/common.c | 76 +++
> arch/arm/plat-samsung/include/plat/map-s5p.h | 4 -
> 23 files changed, 1004 insertions(+), 1306 deletions(-)
> create mode 100644 arch/arm/boot/dts/exynos4412-itop-elite.dts
> create mode 100644 arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi
> delete mode 100644 arch/arm/boot/dts/exynos4415-pinctrl.dtsi
> delete mode 100644 arch/arm/boot/dts/exynos4415.dtsi
>
>
> Pull request details for Soc only:
> ##################################
> ----------------------------------------------------------------
> Samsung mach/soc update for v4.10:
> 1. Use SCU mapping from Device Tree instead of statically mapped one.
> 2. Drop fixed requirement for HZ=200 on Samsung platforms.
>
> ----------------------------------------------------------------
> Krzysztof Kozlowski (1):
> ARM: Drop fixed 200 Hz timer requirement from Samsung platforms
>
> Pankaj Dubey (3):
> ARM: EXYNOS: Remove static mapping of SCU SFR
> ARM: EXYNOS: Remove unused soc_is_exynos{4,5}
> ARM: EXYNOS: Remove smp_init_cpus hook from platsmp.c
>
> Sylwester Nawrocki (1):
> ARM: S3C24XX: Add DMA slave maps for remaining s3c24xx SoCs
>
^ permalink raw reply
* [PATCH dt V2] ARM: BCM5301X: Enable UART by default for BCM4708(1), BCM4709(4) & BCM53012
From: Jon Mason @ 2016-12-01 18:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201174051.4965-1-zajec5@gmail.com>
On Thu, Dec 01, 2016 at 06:40:51PM +0100, Rafa? Mi?ecki wrote:
> From: Rafa? Mi?ecki <rafal@milecki.pl>
>
> Every device tested so far got UART0 (at 0x18000300) working as serial
> console. It's most likely part of reference design and all vendors use
> it that way.
>
> It seems to be easier to enable it by default and just disable it if we
> ever see a device with different hardware design.
>
> Signed-off-by: Rafa? Mi?ecki <rafal@milecki.pl>
Looks good to me!
Acked-by: Jon Mason <jon.mason@broadcom.com>
> ---
> V2: Update bcm94708.dts bcm94709.dts bcm953012er.dts & bcm953012k.dts
> ---
> arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 4 ----
> arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts | 4 ----
> arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts | 4 ----
> arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 4 ----
> arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts | 4 ----
> arch/arm/boot/dts/bcm4708.dtsi | 4 ++++
> arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 4 ----
> arch/arm/boot/dts/bcm47081.dtsi | 4 ++++
> arch/arm/boot/dts/bcm4709-netgear-r7000.dts | 4 ----
> arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 4 ----
> arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts | 4 ----
> arch/arm/boot/dts/bcm4709.dtsi | 1 +
> arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts | 4 ----
> arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts | 4 ----
> arch/arm/boot/dts/bcm47094-netgear-r8500.dts | 4 ----
> arch/arm/boot/dts/bcm47094.dtsi | 1 +
> arch/arm/boot/dts/bcm94708.dts | 4 ----
> arch/arm/boot/dts/bcm94709.dts | 4 ----
> arch/arm/boot/dts/bcm953012er.dts | 4 ----
> arch/arm/boot/dts/bcm953012k.dts | 1 -
> 20 files changed, 10 insertions(+), 61 deletions(-)
>
> diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
> index 9cb186e..d49afec0 100644
> --- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
> +++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
> @@ -136,10 +136,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &usb2 {
> vcc-gpio = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
> };
> diff --git a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
> index 35e6ed6..f591b0f 100644
> --- a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
> +++ b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
> @@ -55,10 +55,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &spi_nor {
> status = "okay";
> };
> diff --git a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
> index 1c7e53d..50d65d8 100644
> --- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
> +++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
> @@ -56,10 +56,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &spi_nor {
> status = "okay";
> };
> diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
> index 8ce39d5..8519548 100644
> --- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
> +++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
> @@ -83,10 +83,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &usb3 {
> vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
> };
> diff --git a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
> index 70f4bb9..74cfcd3 100644
> --- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
> +++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
> @@ -119,10 +119,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &spi_nor {
> status = "okay";
> };
> diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
> index eed4dd1..d0eec09 100644
> --- a/arch/arm/boot/dts/bcm4708.dtsi
> +++ b/arch/arm/boot/dts/bcm4708.dtsi
> @@ -34,3 +34,7 @@
> };
>
> };
> +
> +&uart0 {
> + status = "okay";
> +};
> diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
> index a9c8def..2922536 100644
> --- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
> +++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
> @@ -122,7 +122,3 @@
> };
> };
> };
> -
> -&uart0 {
> - status = "okay";
> -};
> diff --git a/arch/arm/boot/dts/bcm47081.dtsi b/arch/arm/boot/dts/bcm47081.dtsi
> index f720012..c5f7619 100644
> --- a/arch/arm/boot/dts/bcm47081.dtsi
> +++ b/arch/arm/boot/dts/bcm47081.dtsi
> @@ -24,3 +24,7 @@
> };
> };
> };
> +
> +&uart0 {
> + status = "okay";
> +};
> diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
> index fd38d2a..0225d82 100644
> --- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
> +++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
> @@ -100,7 +100,3 @@
> };
> };
> };
> -
> -&uart0 {
> - status = "okay";
> -};
> diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
> index 92f8a72..56d38a3 100644
> --- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
> +++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
> @@ -107,10 +107,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &usb2 {
> vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
> };
> diff --git a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
> index 9a92c24..c67bfaa 100644
> --- a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
> +++ b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
> @@ -97,10 +97,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &usb2 {
> vcc-gpio = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
> };
> diff --git a/arch/arm/boot/dts/bcm4709.dtsi b/arch/arm/boot/dts/bcm4709.dtsi
> index f039765..c645fea 100644
> --- a/arch/arm/boot/dts/bcm4709.dtsi
> +++ b/arch/arm/boot/dts/bcm4709.dtsi
> @@ -8,4 +8,5 @@
>
> &uart0 {
> clock-frequency = <125000000>;
> + status = "okay";
> };
> diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
> index 661348d..7fb9270 100644
> --- a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
> +++ b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
> @@ -105,10 +105,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &usb3 {
> vcc-gpio = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
> };
> diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
> index 169b35f..2f4a651 100644
> --- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
> +++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
> @@ -98,10 +98,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &usb3 {
> vcc-gpio = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
> };
> diff --git a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
> index 521b415..7ecd57c 100644
> --- a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
> +++ b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
> @@ -97,7 +97,3 @@
> };
> };
> };
> -
> -&uart0 {
> - status = "okay";
> -};
> diff --git a/arch/arm/boot/dts/bcm47094.dtsi b/arch/arm/boot/dts/bcm47094.dtsi
> index 4f09aa0..4840a78 100644
> --- a/arch/arm/boot/dts/bcm47094.dtsi
> +++ b/arch/arm/boot/dts/bcm47094.dtsi
> @@ -14,4 +14,5 @@
>
> &uart0 {
> clock-frequency = <125000000>;
> + status = "okay";
> };
> diff --git a/arch/arm/boot/dts/bcm94708.dts b/arch/arm/boot/dts/bcm94708.dts
> index 251a486..42855a7 100644
> --- a/arch/arm/boot/dts/bcm94708.dts
> +++ b/arch/arm/boot/dts/bcm94708.dts
> @@ -50,7 +50,3 @@
> reg = <0x00000000 0x08000000>;
> };
> };
> -
> -&uart0 {
> - status = "okay";
> -};
> diff --git a/arch/arm/boot/dts/bcm94709.dts b/arch/arm/boot/dts/bcm94709.dts
> index b16cac9..95e8be6 100644
> --- a/arch/arm/boot/dts/bcm94709.dts
> +++ b/arch/arm/boot/dts/bcm94709.dts
> @@ -50,7 +50,3 @@
> reg = <0x00000000 0x08000000>;
> };
> };
> -
> -&uart0 {
> - status = "okay";
> -};
> diff --git a/arch/arm/boot/dts/bcm953012er.dts b/arch/arm/boot/dts/bcm953012er.dts
> index 0a9abec..decd86b 100644
> --- a/arch/arm/boot/dts/bcm953012er.dts
> +++ b/arch/arm/boot/dts/bcm953012er.dts
> @@ -70,10 +70,6 @@
> };
> };
>
> -&uart0 {
> - status = "okay";
> -};
> -
> &spi_nor {
> status = "okay";
> };
> diff --git a/arch/arm/boot/dts/bcm953012k.dts b/arch/arm/boot/dts/bcm953012k.dts
> index 05a985a..bfd9230 100644
> --- a/arch/arm/boot/dts/bcm953012k.dts
> +++ b/arch/arm/boot/dts/bcm953012k.dts
> @@ -54,7 +54,6 @@
>
> &uart0 {
> clock-frequency = <62499840>;
> - status = "okay";
> };
>
> &uart1 {
> --
> 2.10.1
>
^ permalink raw reply
* [PATCH v3 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs
From: kbuild test robot @ 2016-12-01 19:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e193572d7746e6f6b8666da7ac0f54031fed5214.1480467185.git.stillcompiling@gmail.com>
Hi Joshua,
[auto build test WARNING on linus/master]
[also build test WARNING on v4.9-rc7]
[cannot apply to next-20161201]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Joshua-Clayton/lib-add-bitrev8x4/20161202-013521
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
include/linux/compiler.h:253:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/fpga/cyclone-ps-spi.c:93:33: sparse: incompatible types in comparison expression (different type sizes)
In file included from include/linux/delay.h:10:0,
from drivers/fpga/cyclone-ps-spi.c:14:
drivers/fpga/cyclone-ps-spi.c: In function 'cyclonespi_write':
include/linux/kernel.h:739:16: warning: comparison of distinct pointer types lacks a cast
(void) (&min1 == &min2); \
^
include/linux/kernel.h:742:2: note: in expansion of macro '__min'
__min(typeof(x), typeof(y), \
^~~~~
drivers/fpga/cyclone-ps-spi.c:93:19: note: in expansion of macro 'min'
size_t stride = min(fw_data_end - fw_data, SZ_4K);
^~~
vim +93 drivers/fpga/cyclone-ps-spi.c
77 /* set buffer to lsb first */
78 while (fw32 < fw_end) {
79 *fw32 = bitrev8x4(*fw32);
80 fw32++;
81 }
82 }
83
84 static int cyclonespi_write(struct fpga_manager *mgr, const char *buf,
85 size_t count)
86 {
87 struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
88 const char *fw_data = buf;
89 const char *fw_data_end = fw_data + count;
90
91 while (fw_data < fw_data_end) {
92 int ret;
> 93 size_t stride = min(fw_data_end - fw_data, SZ_4K);
94
95 rev_buf((void *)fw_data, stride);
96 ret = spi_write(conf->spi, fw_data, stride);
97 if (ret) {
98 dev_err(&mgr->dev, "spi error in firmware write: %d\n",
99 ret);
100 return ret;
101 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply
* [PATCHv4 08/10] mm/kasan: Switch to using __pa_symbol and lm_alias
From: Laura Abbott @ 2016-12-01 19:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2f3ac043-c4cc-5c5a-8ac7-1396b6bb193f@virtuozzo.com>
On 12/01/2016 03:36 AM, Andrey Ryabinin wrote:
> On 11/29/2016 09:55 PM, Laura Abbott wrote:
>> __pa_symbol is the correct API to find the physical address of symbols.
>> Switch to it to allow for debugging APIs to work correctly.
>
> But __pa() is correct for symbols. I see how __pa_symbol() might be a little
> faster than __pa(), but there is nothing wrong in using __pa() on symbols.
>
>> Other
>> functions such as p*d_populate may call __pa internally. Ensure that the
>> address passed is in the linear region by calling lm_alias.
>
> Why it should be linear mapping address? __pa() translates kernel image address just fine.
> This lm_alias() only obfuscates source code. Generated code is probably worse too.
>
>
This is part of adding CONFIG_DEBUG_VIRTUAL for arm64. We want to
differentiate between __pa and __pa_symbol to enforce stronger
virtual checks and have __pa only be for linear map addresses.
Thanks,
Laura
^ permalink raw reply
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Jon Masters @ 2016-12-01 19:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480604901.4751.17.camel@redhat.com>
On 12/01/2016 10:08 AM, Mark Salter wrote:
> On Wed, 2016-11-30 at 15:42 -0800, Duc Dang wrote:
>> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
>> +{
>> + struct acpi_device *adev = to_acpi_device(cfg->parent);
>> + struct acpi_pci_root *root = acpi_driver_data(adev);
>> + struct device *dev = cfg->parent;
>> + struct xgene_pcie_port *port;
>> + struct resource *csr;
>> +
>> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>> + if (!port)
>> + return -ENOMEM;
>> +
>> + csr = &xgene_v1_csr_res[root->segment];
>
> This hard-coded assumption that segment N uses controller N breaks
> for m400 where segment 0 is using controller 3.
This seems very fragile. So in addition to Bjorn's comment about not
trusting firmware provided data for the segment offset in the CSR list,
you will want to also determine the controller from the ACPI tree. The
existing code walks the ACPI hierarchy and finds the CSR that way.
Obviously, the goal is to avoid that in the latest incarnation, but you
could still determine which controller matches a given device.
Jon.
--
Computer Architect | Sent from my Fedora powered laptop
^ permalink raw reply
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Mark Salter @ 2016-12-01 19:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201183350.GF30746@bhelgaas-glaptop.roam.corp.google.com>
On Thu, 2016-12-01 at 12:33 -0600, Bjorn Helgaas wrote:
> Hi Duc,
>
> On Wed, Nov 30, 2016 at 03:42:53PM -0800, Duc Dang wrote:
> >
> > PCIe controllers in X-Gene SoCs is not ECAM compliant: software
> > needs to configure additional controller's register to address
> > device at bus:dev:function.
> >
> > The quirk will only be applied for X-Gene PCIe MCFG table with
> > OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs).
> >
> > The quirk declares the X-Gene PCIe controller register space as 64KB
> > fixed memory resource with name "PCIe CSR". This name will be showed
> > next to the resource range in the output of "cat /proc/iomem".
> >
> > Signed-off-by: Duc Dang <dhdang@apm.com>
> > ---
> > v3:
> > ? - Rebase on top of pci/ecam-v6 tree.
> > ? - Use DEFINE_RES_MEM_NAMED to declare controller register space
> > ? with name "PCIe CSR"
> > v2:
> > ? RFC v2: https://patchwork.ozlabs.org/patch/686846/
> > v1:
> > ? RFC v1: https://patchwork.kernel.org/patch/9337115/
> >
> > ?drivers/acpi/pci_mcfg.c??????|??31 ++++++++
> > ?drivers/pci/host/pci-xgene.c | 165 ++++++++++++++++++++++++++++++++++++++++++-
> > ?include/linux/pci-ecam.h?????|???7 ++
> > ?3 files changed, 200 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> > index ac21db3..eb6125b 100644
> > --- a/drivers/acpi/pci_mcfg.c
> > +++ b/drivers/acpi/pci_mcfg.c
> > @@ -57,6 +57,37 @@ struct mcfg_fixup {
> > ? { "QCOM??", "QDF2432 ", 1, 5, MCFG_BUS_ANY, &pci_32b_ops },
> > ? { "QCOM??", "QDF2432 ", 1, 6, MCFG_BUS_ANY, &pci_32b_ops },
> > ? { "QCOM??", "QDF2432 ", 1, 7, MCFG_BUS_ANY, &pci_32b_ops },
> > +
> > +#ifdef CONFIG_PCI_XGENE
> As you've no doubt noticed, I'm proposing to add these quirks without
> CONFIG_PCI_XGENE, so we don't have to select each device when building
> a generic ACPI kernel.
>
> I'm also proposing some Kconfig and Makefile changes so we don't build
> the platform driver part in a generic ACPI kernel (unless we *also*
> explicitly select the platform driver).
>
> Here's an example:
> https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/commit/?h=pci/ecam&id=f80edf4d6c05
>
> >
> > +#define XGENE_V1_ECAM_MCFG(rev, seg) \
> > + {"APM???", "XGENE???", rev, seg, MCFG_BUS_ANY, \
> > + &xgene_v1_pcie_ecam_ops }
> > +#define XGENE_V2_1_ECAM_MCFG(rev, seg) \
> > + {"APM???", "XGENE???", rev, seg, MCFG_BUS_ANY, \
> > + &xgene_v2_1_pcie_ecam_ops }
> > +#define XGENE_V2_2_ECAM_MCFG(rev, seg) \
> > + {"APM???", "XGENE???", rev, seg, MCFG_BUS_ANY, \
> > + &xgene_v2_2_pcie_ecam_ops }
> > +
> > + /* X-Gene SoC with v1 PCIe controller */
> > + XGENE_V1_ECAM_MCFG(1, 0),
> > + XGENE_V1_ECAM_MCFG(1, 1),
> >
> > @@ -64,6 +66,7 @@
> > ?/* PCIe IP version */
> > ?#define XGENE_PCIE_IP_VER_UNKN 0
> > ?#define XGENE_PCIE_IP_VER_1 1
> > +#define XGENE_PCIE_IP_VER_2 2
> This isn't used anywhere, which makes me wonder whether it's worth
> keeping it.
>
> >
> > ?static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
> > ?{
> > - struct xgene_pcie_port *port = bus->sysdata;
> > + struct pci_config_window *cfg;
> > + struct xgene_pcie_port *port;
> > +
> > + if (acpi_disabled)
> > + port = bus->sysdata;
> > + else {
> > + cfg = bus->sysdata;
> > + port = cfg->priv;
> > + }
> I would really, really like to figure out a way to get rid of these
> "if (acpi_disabled)" checks sprinkled through here.??Is there any way
> we can set up bus->sysdata to be the same, regardless of whether we're
> using this as a platform driver or an ACPI quirk?
>
> >
> > +#ifdef CONFIG_ACPI
> You've probably noticed that I've been using
>
> ? #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
>
> in this situation, mostly to make it clear that this is part of a
> workaround.??I don't want people to blindly copy this stuff without
> realizing that it's a workaround for a hardware issue.
>
> >
> > +static struct resource xgene_v1_csr_res[] = {
> > + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
> > + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
> > + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
> > + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
> > + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
> I assume these ranges are not the actual ECAM space, right?
> If they *were* ECAM, I assume you would have included them in the
> quirk itself in the mcfg_quirks[] table.
These are base addresses for some RC mmio registers.
>
> >
> > +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
> > +{
> > + struct acpi_device *adev = to_acpi_device(cfg->parent);
> > + struct acpi_pci_root *root = acpi_driver_data(adev);
> > + struct device *dev = cfg->parent;
> > + struct xgene_pcie_port *port;
> > + struct resource *csr;
> > +
> > + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > + if (!port)
> > + return -ENOMEM;
> > +
> > + csr = &xgene_v1_csr_res[root->segment];
> This makes me nervous because root->segment comes from the ACPI _SEG,
> and if firmware gives us junk in _SEG, we will reference something in
> the weeds.
The SoC provide some number of RC bridges, each with a different base
for some mmio registers. Even if segment is legitimate in MCFG, there
is still a problem if a platform doesn't use the segment ordering
implied by the code. But the PNP0A03 _CRS does have this base address
as the first memory resource, so we could get it from there and not
have hard-coded addresses and implied ording in the quirk code.
I have tested a modified version of these quirks using this to
get the CSR base and it works on the 3 different platforms I have
access to.
static int xgene_pcie_get_csr(struct device *dev, struct resource *r)
{
struct acpi_device *adev = to_acpi_device(dev);
unsigned long flags;
struct list_head list;
struct resource_entry *entry;
int ret;
INIT_LIST_HEAD(&list);
flags = IORESOURCE_MEM;
ret = acpi_dev_get_resources(adev, &list,
?????acpi_dev_filter_resource_type_cb,
?????(void *)flags);
if (ret < 0) {
dev_err(dev, "failed to parse _CRS, error: %d\n", ret);
return ret;
} else if (ret == 0) {
dev_err(dev, "no memory resources present in _CRS\n");
return -EINVAL;
}
entry = list_first_entry(&list, struct resource_entry, node);
*r = *entry->res;
acpi_dev_free_resource_list(&list);
return 0;
}
>
> >
> > + port->csr_base = devm_ioremap_resource(dev, csr);
> > + if (IS_ERR(port->csr_base)) {
> > + kfree(port);
> > + return -ENOMEM;
> > + }
> > +
> > + port->cfg_base = cfg->win;
> > + port->version = XGENE_PCIE_IP_VER_1;
> > +
> > + cfg->priv = port;
> All these init functions are almost identical.??Can we factor this out
> by having wrappers that do nothing more than pass in the table and
> version, and put the kzalloc and ioremap in a shared back-end?
>
> We're so close I can taste it!??I can't wait to see all this work come
> to fruition.
>
> Bjorn
^ permalink raw reply
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Jon Masters @ 2016-12-01 19:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480620053.4751.30.camel@redhat.com>
On 12/01/2016 02:20 PM, Mark Salter wrote:
> On Thu, 2016-12-01 at 12:33 -0600, Bjorn Helgaas wrote:
>>> + csr = &xgene_v1_csr_res[root->segment];
>> This makes me nervous because root->segment comes from the ACPI _SEG,
>> and if firmware gives us junk in _SEG, we will reference something in
>> the weeds.
>
> The SoC provide some number of RC bridges, each with a different base
> for some mmio registers. Even if segment is legitimate in MCFG, there
> is still a problem if a platform doesn't use the segment ordering
> implied by the code. But the PNP0A03 _CRS does have this base address
> as the first memory resource, so we could get it from there and not
> have hard-coded addresses and implied ording in the quirk code.
>
> I have tested a modified version of these quirks using this to
> get the CSR base and it works on the 3 different platforms I have
> access to.
>
> static int xgene_pcie_get_csr(struct device *dev, struct resource *r)
> {
> struct acpi_device *adev = to_acpi_device(dev);
> unsigned long flags;
> struct list_head list;
> struct resource_entry *entry;
> int ret;
>
> INIT_LIST_HEAD(&list);
> flags = IORESOURCE_MEM;
> ret = acpi_dev_get_resources(adev, &list,
> acpi_dev_filter_resource_type_cb,
> (void *)flags);
> if (ret < 0) {
> dev_err(dev, "failed to parse _CRS, error: %d\n", ret);
> return ret;
> } else if (ret == 0) {
> dev_err(dev, "no memory resources present in _CRS\n");
> return -EINVAL;
> }
>
> entry = list_first_entry(&list, struct resource_entry, node);
> *r = *entry->res;
> acpi_dev_free_resource_list(&list);
> return 0;
> }
This seems a lot safer. At some point trusting firmware to provide the
correct _CRS for the RC in use is better than hard coding for every
possible implementation configuration of an X-Gene SoC.
Jon.
--
Computer Architect | Sent from my Fedora powered laptop
^ permalink raw reply
* [PATCH] clk: bcm2835: Avoid overwriting the div info when disabling a pll_div clk
From: Boris Brezillon @ 2016-12-01 19:27 UTC (permalink / raw)
To: linux-arm-kernel
bcm2835_pll_divider_off() is resetting the divider field in the A2W reg
to zero when disabling the clock.
Make sure we preserve this value by reading the previous a2w_reg value
first and ORing the result with A2W_PLL_CHANNEL_DISABLE.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
Cc: <stable@vger.kernel.org>
---
drivers/clk/bcm/clk-bcm2835.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 836d07550be3..2acaa77ad482 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -751,7 +751,9 @@ static void bcm2835_pll_divider_off(struct clk_hw *hw)
cprman_write(cprman, data->cm_reg,
(cprman_read(cprman, data->cm_reg) &
~data->load_mask) | data->hold_mask);
- cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE);
+ cprman_write(cprman, data->a2w_reg,
+ cprman_read(cprman, data->a2w_reg) |
+ A2W_PLL_CHANNEL_DISABLE);
spin_unlock(&cprman->regs_lock);
}
--
2.7.4
^ permalink raw reply related
* [PATCH v2] KVM: arm/arm64: Access CNTHCTL_EL2 bit fields correctly
From: Jintack Lim @ 2016-12-01 19:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f77698be-d30d-53af-0782-3ef6bea3ba4a@arm.com>
Hi Marc,
On Thu, Dec 1, 2016 at 8:30 AM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Hi Jintack,
>
> On 01/12/16 11:38, Jintack Lim wrote:
>> Current KVM world switch code is unintentionally setting wrong bits to
>> CNTHCTL_EL2 when E2H == 1, which may allow guest OS to access physical
>> timer. Bit positions of CNTHCTL_EL2 are changing depending on
>> HCR_EL2.E2H bit. EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is
>> not set, but they are 11th and 10th bits respectively when E2H is set.
>>
>> In fact, on VHE we only need to set those bits once, not for every world
>> switch. This is because the host kernel runs in EL2 with HCR_EL2.TGE ==
>> 1, which makes those bits have no effect for the host kernel execution.
>> So we just set those bits once for guests, and that's it.
>>
>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>> ---
>> v2: Skip configuring cnthctl_el2 in world switch path on VHE system.
>> This patch is based on linux-next.
>>
>> ---
>> arch/arm/kvm/arm.c | 1 +
>> include/kvm/arm_arch_timer.h | 1 +
>> virt/kvm/arm/arch_timer.c | 23 ++++++++++++++++++++++
>> virt/kvm/arm/hyp/timer-sr.c | 45 ++++++++++++++++++++++++++++++++------------
>> 4 files changed, 58 insertions(+), 12 deletions(-)
>>
>> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
>> index 8f92efa..38c0645 100644
>> --- a/arch/arm/kvm/arm.c
>> +++ b/arch/arm/kvm/arm.c
>> @@ -1286,6 +1286,7 @@ static void teardown_hyp_mode(void)
>>
>> static int init_vhe_mode(void)
>> {
>> + on_each_cpu(kvm_timer_init_vhe, NULL, 1);
>
> I'm pretty sure this is not going to work with CPU hotplug, as you only
> perform this once and for all at boot time.
>
> I think it would be better if you called this init function as part of
> cpu_init_hyp_mode().
All right. I'll do that.
>
>> kvm_info("VHE mode initialized successfully\n");
>> return 0;
>> }
>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>> index dda39d8..5853399 100644
>> --- a/include/kvm/arm_arch_timer.h
>> +++ b/include/kvm/arm_arch_timer.h
>> @@ -76,4 +76,5 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
>>
>> void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>>
>> +void kvm_timer_init_vhe(void *dummy);
>> #endif
>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>> index 17b8fa5..7a0d85d7 100644
>> --- a/virt/kvm/arm/arch_timer.c
>> +++ b/virt/kvm/arm/arch_timer.c
>> @@ -24,6 +24,7 @@
>>
>> #include <clocksource/arm_arch_timer.h>
>> #include <asm/arch_timer.h>
>> +#include <asm/kvm_hyp.h>
>>
>> #include <kvm/arm_vgic.h>
>> #include <kvm/arm_arch_timer.h>
>> @@ -507,3 +508,25 @@ void kvm_timer_init(struct kvm *kvm)
>> {
>> kvm->arch.timer.cntvoff = kvm_phys_timer_read();
>> }
>> +
>> +/*
>> + * On VHE system, we only need to configure trap on physical timer and counter
>> + * accesses in EL0 and EL1 once, not for every world switch.
>> + * The host kernel runs at EL2 with HCR_EL2.TGE == 1,
>> + * and this makes those bits have no effect for the host kernel execution.
>> + */
>> +void kvm_timer_init_vhe(void *dummy)
>> +{
>> + /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
>> + u32 cnthctl_shift = 10;
>> + u64 val;
>> +
>> + /*
>> + * Disallow physical timer access for the guest.
>> + * Physical counter access is allowed.
>> + */
>> + val = read_sysreg(cnthctl_el2);
>> + val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
>> + val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
>> + write_sysreg(val, cnthctl_el2);
>> +}
>
> If you make this called from cpu_init_hyp_mode(), it will have to be
> guarded with is_kernel_in_hyp_mode().
>
>> diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
>> index 798866a..f7fc957 100644
>> --- a/virt/kvm/arm/hyp/timer-sr.c
>> +++ b/virt/kvm/arm/hyp/timer-sr.c
>> @@ -21,6 +21,18 @@
>>
>> #include <asm/kvm_hyp.h>
>>
>> +#ifdef CONFIG_ARM64
>> +static inline bool has_vhe(void)
>> +{
>> + if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
>> + return true;
>> +
>> + return false;
>> +}
>> +#else
>> +#define has_vhe() false
>
> Could this now be moved to asm/virt.h, and maybe replace the current
> implementation of is_kernel_in_hyp_mode? The latter may require some
> more hacking around, so I'm not sure this is worth it.
I can move that to asm/virt.h, but I'll leave is_kernel_in_hyp_mode()
as it is because, as you pointed out in another e-mail,
is_kernel_in_hyp_mode() can be used before setting up the CPU
capabilities (e.g. runs_at_el2()). I'll send out v3 soon.
Thanks,
Jintack
>
>> +#endif
>> +
>> /* vcpu is already in the HYP VA space */
>> void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
>> {
>> @@ -35,10 +47,16 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
>> /* Disable the virtual timer */
>> write_sysreg_el0(0, cntv_ctl);
>>
>> - /* Allow physical timer/counter access for the host */
>> - val = read_sysreg(cnthctl_el2);
>> - val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
>> - write_sysreg(val, cnthctl_el2);
>> + /*
>> + * We don't need to do this for VHE since the host kernel runs in EL2
>> + * with HCR_EL2.TGE ==1, which makes those bits have no impact.
>> + */
>> + if (!has_vhe()) {
>> + /* Allow physical timer/counter access for the host */
>> + val = read_sysreg(cnthctl_el2);
>> + val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
>> + write_sysreg(val, cnthctl_el2);
>> + }
>>
>> /* Clear cntvoff for the host */
>> write_sysreg(0, cntvoff_el2);
>> @@ -50,14 +68,17 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
>> struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>> u64 val;
>>
>> - /*
>> - * Disallow physical timer access for the guest
>> - * Physical counter access is allowed
>> - */
>> - val = read_sysreg(cnthctl_el2);
>> - val &= ~CNTHCTL_EL1PCEN;
>> - val |= CNTHCTL_EL1PCTEN;
>> - write_sysreg(val, cnthctl_el2);
>> + /* Those bits are already configured at boot on VHE-system */
>> + if (!has_vhe()) {
>> + /*
>> + * Disallow physical timer access for the guest
>> + * Physical counter access is allowed
>> + */
>> + val = read_sysreg(cnthctl_el2);
>> + val &= ~CNTHCTL_EL1PCEN;
>> + val |= CNTHCTL_EL1PCTEN;
>> + write_sysreg(val, cnthctl_el2);
>> + }
>>
>> if (timer->enabled) {
>> write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
>>
>
> Otherwise, this looks good, and the generated code is quite nice.
>
> Thanks,
>
> M.
> --
> Jazz is not dead. It just smells funny...
>
^ permalink raw reply
* [PATCH v3] KVM: arm/arm64: Access CNTHCTL_EL2 bit fields correctly
From: Jintack Lim @ 2016-12-01 19:32 UTC (permalink / raw)
To: linux-arm-kernel
Current KVM world switch code is unintentionally setting wrong bits to
CNTHCTL_EL2 when E2H == 1, which may allow guest OS to access physical
timer. Bit positions of CNTHCTL_EL2 are changing depending on
HCR_EL2.E2H bit. EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is
not set, but they are 11th and 10th bits respectively when E2H is set.
In fact, on VHE we only need to set those bits once, not for every world
switch. This is because the host kernel runs in EL2 with HCR_EL2.TGE ==
1, which makes those bits have no effect for the host kernel execution.
So we just set those bits once for guests, and that's it.
Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
---
v2->v3:
- Perform the initialization including CPU hotplug case.
- Move has_vhe() to asm/virt.h
v1->v2:
- Skip configuring cnthctl_el2 in world switch path on VHE system.
- Write patch based on linux-next.
---
arch/arm/include/asm/virt.h | 5 +++++
arch/arm/kvm/arm.c | 3 +++
arch/arm64/include/asm/virt.h | 10 ++++++++++
include/kvm/arm_arch_timer.h | 1 +
virt/kvm/arm/arch_timer.c | 23 +++++++++++++++++++++++
virt/kvm/arm/hyp/timer-sr.c | 33 +++++++++++++++++++++------------
6 files changed, 63 insertions(+), 12 deletions(-)
diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h
index a2e75b8..6dae195 100644
--- a/arch/arm/include/asm/virt.h
+++ b/arch/arm/include/asm/virt.h
@@ -80,6 +80,11 @@ static inline bool is_kernel_in_hyp_mode(void)
return false;
}
+static inline bool has_vhe(void)
+{
+ return false;
+}
+
/* The section containing the hypervisor idmap text */
extern char __hyp_idmap_text_start[];
extern char __hyp_idmap_text_end[];
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 8f92efa..13e54e8 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -1099,6 +1099,9 @@ static void cpu_init_hyp_mode(void *dummy)
__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
__cpu_init_stage2();
+ if (is_kernel_in_hyp_mode())
+ kvm_timer_init_vhe();
+
kvm_arm_init_debug();
}
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index fea1073..b043cfd 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -47,6 +47,7 @@
#include <asm/ptrace.h>
#include <asm/sections.h>
#include <asm/sysreg.h>
+#include <asm/cpufeature.h>
/*
* __boot_cpu_mode records what mode CPUs were booted in.
@@ -80,6 +81,15 @@ static inline bool is_kernel_in_hyp_mode(void)
return read_sysreg(CurrentEL) == CurrentEL_EL2;
}
+static inline bool has_vhe(void)
+{
+#ifdef CONFIG_ARM64_VHE
+ if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
+ return true;
+#endif
+ return false;
+}
+
#ifdef CONFIG_ARM64_VHE
extern void verify_cpu_run_el(void);
#else
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index dda39d8..2d54903 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -76,4 +76,5 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
+void kvm_timer_init_vhe(void);
#endif
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 17b8fa5..c7c3bfd 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -24,6 +24,7 @@
#include <clocksource/arm_arch_timer.h>
#include <asm/arch_timer.h>
+#include <asm/kvm_hyp.h>
#include <kvm/arm_vgic.h>
#include <kvm/arm_arch_timer.h>
@@ -507,3 +508,25 @@ void kvm_timer_init(struct kvm *kvm)
{
kvm->arch.timer.cntvoff = kvm_phys_timer_read();
}
+
+/*
+ * On VHE system, we only need to configure trap on physical timer and counter
+ * accesses in EL0 and EL1 once, not for every world switch.
+ * The host kernel runs at EL2 with HCR_EL2.TGE == 1,
+ * and this makes those bits have no effect for the host kernel execution.
+ */
+void kvm_timer_init_vhe(void)
+{
+ /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
+ u32 cnthctl_shift = 10;
+ u64 val;
+
+ /*
+ * Disallow physical timer access for the guest.
+ * Physical counter access is allowed.
+ */
+ val = read_sysreg(cnthctl_el2);
+ val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
+ val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
+ write_sysreg(val, cnthctl_el2);
+}
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index 798866a..63e28dd 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -35,10 +35,16 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
/* Disable the virtual timer */
write_sysreg_el0(0, cntv_ctl);
- /* Allow physical timer/counter access for the host */
- val = read_sysreg(cnthctl_el2);
- val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
- write_sysreg(val, cnthctl_el2);
+ /*
+ * We don't need to do this for VHE since the host kernel runs in EL2
+ * with HCR_EL2.TGE ==1, which makes those bits have no impact.
+ */
+ if (!has_vhe()) {
+ /* Allow physical timer/counter access for the host */
+ val = read_sysreg(cnthctl_el2);
+ val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+ write_sysreg(val, cnthctl_el2);
+ }
/* Clear cntvoff for the host */
write_sysreg(0, cntvoff_el2);
@@ -50,14 +56,17 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
u64 val;
- /*
- * Disallow physical timer access for the guest
- * Physical counter access is allowed
- */
- val = read_sysreg(cnthctl_el2);
- val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
- write_sysreg(val, cnthctl_el2);
+ /* Those bits are already configured at boot on VHE-system */
+ if (!has_vhe()) {
+ /*
+ * Disallow physical timer access for the guest
+ * Physical counter access is allowed
+ */
+ val = read_sysreg(cnthctl_el2);
+ val &= ~CNTHCTL_EL1PCEN;
+ val |= CNTHCTL_EL1PCTEN;
+ write_sysreg(val, cnthctl_el2);
+ }
if (timer->enabled) {
write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
--
1.9.1
^ permalink raw reply related
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Bjorn Helgaas @ 2016-12-01 19:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480620053.4751.30.camel@redhat.com>
On Thu, Dec 01, 2016 at 02:20:53PM -0500, Mark Salter wrote:
> On Thu, 2016-12-01 at 12:33 -0600, Bjorn Helgaas wrote:
> > On Wed, Nov 30, 2016 at 03:42:53PM -0800, Duc Dang wrote:
> > > +static struct resource xgene_v1_csr_res[] = {
> > > + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
> > > + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
> > > + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
> > > + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
> > > + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
> > I assume these ranges are not the actual ECAM space, right?
> > If they *were* ECAM, I assume you would have included them in the
> > quirk itself in the mcfg_quirks[] table.
>
> These are base addresses for some RC mmio registers.
> >
> > >
> > > +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
> > > +{
> > > + struct acpi_device *adev = to_acpi_device(cfg->parent);
> > > + struct acpi_pci_root *root = acpi_driver_data(adev);
> > > + struct device *dev = cfg->parent;
> > > + struct xgene_pcie_port *port;
> > > + struct resource *csr;
> > > +
> > > + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > > + if (!port)
> > > + return -ENOMEM;
> > > +
> > > + csr = &xgene_v1_csr_res[root->segment];
> > This makes me nervous because root->segment comes from the ACPI _SEG,
> > and if firmware gives us junk in _SEG, we will reference something in
> > the weeds.
>
> The SoC provide some number of RC bridges, each with a different base
> for some mmio registers. Even if segment is legitimate in MCFG, there
> is still a problem if a platform doesn't use the segment ordering
> implied by the code. But the PNP0A03 _CRS does have this base address
> as the first memory resource, so we could get it from there and not
> have hard-coded addresses and implied ording in the quirk code.
I'm confused. Doesn't the current code treat every item in PNP0A03
_CRS as a window? Do you mean the first resource is handled
differently somehow? The Consumer/Producer bit could allow us to do
this by marking the RC MMIO space as "Consumer", but I didn't think
that strategy was quite working yet.
> I have tested a modified version of these quirks using this to
> get the CSR base and it works on the 3 different platforms I have
> access to.
>
> static int xgene_pcie_get_csr(struct device *dev, struct resource *r)
> {
> struct acpi_device *adev = to_acpi_device(dev);
> unsigned long flags;
> struct list_head list;
> struct resource_entry *entry;
> int ret;
>
> INIT_LIST_HEAD(&list);
> flags = IORESOURCE_MEM;
> ret = acpi_dev_get_resources(adev, &list,
> ?????acpi_dev_filter_resource_type_cb,
> ?????(void *)flags);
> if (ret < 0) {
> dev_err(dev, "failed to parse _CRS, error: %d\n", ret);
> return ret;
> } else if (ret == 0) {
> dev_err(dev, "no memory resources present in _CRS\n");
> return -EINVAL;
> }
>
> entry = list_first_entry(&list, struct resource_entry, node);
> *r = *entry->res;
> acpi_dev_free_resource_list(&list);
> return 0;
> }
The code above is identical to acpi_get_rc_addr(), which is used in
the acpi_get_rc_resources() path by the other quirks. Can you use
that path, too, instead of reimplementing it here?
^ permalink raw reply
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Duc Dang @ 2016-12-01 19:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f4b949c0-f992-b0fb-5f23-f71cb1f9713e@redhat.com>
On Thu, Dec 1, 2016 at 11:17 AM, Jon Masters <jcm@redhat.com> wrote:
> On 12/01/2016 10:08 AM, Mark Salter wrote:
>> On Wed, 2016-11-30 at 15:42 -0800, Duc Dang wrote:
>
>>> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
>>> +{
>>> + struct acpi_device *adev = to_acpi_device(cfg->parent);
>>> + struct acpi_pci_root *root = acpi_driver_data(adev);
>>> + struct device *dev = cfg->parent;
>>> + struct xgene_pcie_port *port;
>>> + struct resource *csr;
>>> +
>>> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>>> + if (!port)
>>> + return -ENOMEM;
>>> +
>>> + csr = &xgene_v1_csr_res[root->segment];
>>
>> This hard-coded assumption that segment N uses controller N breaks
>> for m400 where segment 0 is using controller 3.
I think the latest firmware released from us a few months back use
segment 3 for PCIe controller 3 in MCFG table.
>
> This seems very fragile. So in addition to Bjorn's comment about not
> trusting firmware provided data for the segment offset in the CSR list,
> you will want to also determine the controller from the ACPI tree. The
> existing code walks the ACPI hierarchy and finds the CSR that way.
> Obviously, the goal is to avoid that in the latest incarnation, but you
> could still determine which controller matches a given device.
Yes, I will look into that more.
>
> Jon.
>
> --
> Computer Architect | Sent from my Fedora powered laptop
>
Regards,
Duc Dang.
^ permalink raw reply
* [PATCH v2 0/7] drm/vc4: VEC (SDTV) output support
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
Here is the 2nd version of the VC4/VEC series.
We still miss the two clock patches mentioned by Eric in the first
version to make the encoder work no matter the setting applied by the
bootloader.
Regards,
Boris
Boris Brezillon (7):
drm/vc4: Fix ->clock_select setting for the VEC encoder
drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
drm: Add TV connector states to drm_connector_state
drm/vc4: Add support for the VEC (Video Encoder) IP
drm/vc4: Document VEC DT binding
ARM: bcm/dt: Add VEC node in bcm283x.dtsi
ARM: bcm/dt: Enable the VEC IP on all RaspeberryPi boards
.../devicetree/bindings/display/brcm,bcm-vc4.txt | 14 +
arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +
arch/arm/boot/dts/bcm283x.dtsi | 8 +
drivers/gpu/drm/drm_atomic.c | 50 ++
drivers/gpu/drm/vc4/Makefile | 1 +
drivers/gpu/drm/vc4/vc4_crtc.c | 38 +-
drivers/gpu/drm/vc4/vc4_debugfs.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.h | 6 +
drivers/gpu/drm/vc4/vc4_regs.h | 3 +-
drivers/gpu/drm/vc4/vc4_vec.c | 657 +++++++++++++++++++++
include/drm/drm_connector.h | 32 +
include/uapi/drm/drm_mode.h | 18 +-
13 files changed, 810 insertions(+), 24 deletions(-)
create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c
--
2.7.4
^ permalink raw reply
* [PATCH v2 1/7] drm/vc4: Fix ->clock_select setting for the VEC encoder
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>
PV_CONTROL_CLK_SELECT_VEC is actually 2 and not 0. Fix the definition and
rework the vc4_set_crtc_possible_masks() to cover the full range of the
PV_CONTROL_CLK_SELECT field.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/gpu/drm/vc4/vc4_crtc.c | 38 +++++++++++++++++++++++---------------
drivers/gpu/drm/vc4/vc4_drv.h | 1 +
drivers/gpu/drm/vc4/vc4_regs.h | 3 ++-
3 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7f08d681a74b..c317e9103f9b 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -83,8 +83,7 @@ struct vc4_crtc_data {
/* Which channel of the HVS this pixelvalve sources from. */
int hvs_channel;
- enum vc4_encoder_type encoder0_type;
- enum vc4_encoder_type encoder1_type;
+ enum vc4_encoder_type encoder_types[4];
};
#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
@@ -859,20 +858,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
static const struct vc4_crtc_data pv0_data = {
.hvs_channel = 0,
- .encoder0_type = VC4_ENCODER_TYPE_DSI0,
- .encoder1_type = VC4_ENCODER_TYPE_DPI,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
+ },
};
static const struct vc4_crtc_data pv1_data = {
.hvs_channel = 2,
- .encoder0_type = VC4_ENCODER_TYPE_DSI1,
- .encoder1_type = VC4_ENCODER_TYPE_SMI,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
+ },
};
static const struct vc4_crtc_data pv2_data = {
.hvs_channel = 1,
- .encoder0_type = VC4_ENCODER_TYPE_VEC,
- .encoder1_type = VC4_ENCODER_TYPE_HDMI,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
+ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
+ },
};
static const struct of_device_id vc4_crtc_dt_match[] = {
@@ -886,17 +891,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
struct drm_crtc *crtc)
{
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ const struct vc4_crtc_data *crtc_data = vc4_crtc->data;
+ const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types;
struct drm_encoder *encoder;
drm_for_each_encoder(encoder, drm) {
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
-
- if (vc4_encoder->type == vc4_crtc->data->encoder0_type) {
- vc4_encoder->clock_select = 0;
- encoder->possible_crtcs |= drm_crtc_mask(crtc);
- } else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) {
- vc4_encoder->clock_select = 1;
- encoder->possible_crtcs |= drm_crtc_mask(crtc);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) {
+ if (vc4_encoder->type == encoder_types[i]) {
+ vc4_encoder->clock_select = i;
+ encoder->possible_crtcs |= drm_crtc_mask(crtc);
+ break;
+ }
}
}
}
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 7c1e4d97486f..946d48c33668 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -194,6 +194,7 @@ to_vc4_plane(struct drm_plane *plane)
}
enum vc4_encoder_type {
+ VC4_ENCODER_TYPE_NONE,
VC4_ENCODER_TYPE_HDMI,
VC4_ENCODER_TYPE_VEC,
VC4_ENCODER_TYPE_DSI0,
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 1aa44c2db556..39f6886b2410 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -177,8 +177,9 @@
# define PV_CONTROL_WAIT_HSTART BIT(12)
# define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4)
# define PV_CONTROL_PIXEL_REP_SHIFT 4
-# define PV_CONTROL_CLK_SELECT_DSI_VEC 0
+# define PV_CONTROL_CLK_SELECT_DSI 0
# define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1
+# define PV_CONTROL_CLK_SELECT_VEC 2
# define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2)
# define PV_CONTROL_CLK_SELECT_SHIFT 2
# define PV_CONTROL_FIFO_CLR BIT(1)
--
2.7.4
^ permalink raw reply related
* [PATCH v2 2/7] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>
List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better
represented with enums.
Turn the DRM_MODE_SUBCONNECTOR_xx macros into an enum.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
include/uapi/drm/drm_mode.h | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index df0e3504c349..970bfc0d7107 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -220,14 +220,16 @@ struct drm_mode_get_encoder {
/* This is for connectors with multiple signal types. */
/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
-#define DRM_MODE_SUBCONNECTOR_Automatic 0
-#define DRM_MODE_SUBCONNECTOR_Unknown 0
-#define DRM_MODE_SUBCONNECTOR_DVID 3
-#define DRM_MODE_SUBCONNECTOR_DVIA 4
-#define DRM_MODE_SUBCONNECTOR_Composite 5
-#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
-#define DRM_MODE_SUBCONNECTOR_Component 8
-#define DRM_MODE_SUBCONNECTOR_SCART 9
+enum drm_mode_subconnector {
+ DRM_MODE_SUBCONNECTOR_Automatic = 0,
+ DRM_MODE_SUBCONNECTOR_Unknown = 0,
+ DRM_MODE_SUBCONNECTOR_DVID = 3,
+ DRM_MODE_SUBCONNECTOR_DVIA = 4,
+ DRM_MODE_SUBCONNECTOR_Composite = 5,
+ DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
+ DRM_MODE_SUBCONNECTOR_Component = 8,
+ DRM_MODE_SUBCONNECTOR_SCART = 9,
+};
#define DRM_MODE_CONNECTOR_Unknown 0
#define DRM_MODE_CONNECTOR_VGA 1
--
2.7.4
^ permalink raw reply related
* [PATCH v2 3/7] drm: Add TV connector states to drm_connector_state
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>
Some generic TV connector properties are exposed in drm_mode_config, but
they are currently handled independently in each DRM encoder driver.
Extend the drm_connector_state to store TV related states, and modify the
drm_atomic_connector_{set,get}_property() helpers to fill the connector
state accordingly.
Each driver is then responsible for checking and applying the new config
in its ->atomic_mode_{check,set}() operations.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
Changes in v2
- fix copy/paste errors
- use an enum for the subconnector field
- switch all fields to unsigned int
---
drivers/gpu/drm/drm_atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 32 ++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e6862a744210..f93395c3c181 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -989,12 +989,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
* now?) atomic writes to DPMS property:
*/
return -EINVAL;
+ } else if (property == config->tv_select_subconnector_property) {
+ state->tv.subconnector = val;
+ } else if (property == config->tv_left_margin_property) {
+ state->tv.margins.left = val;
+ } else if (property == config->tv_right_margin_property) {
+ state->tv.margins.right = val;
+ } else if (property == config->tv_top_margin_property) {
+ state->tv.margins.top = val;
+ } else if (property == config->tv_bottom_margin_property) {
+ state->tv.margins.bottom = val;
+ } else if (property == config->tv_mode_property) {
+ state->tv.mode = val;
+ } else if (property == config->tv_brightness_property) {
+ state->tv.brightness = val;
+ } else if (property == config->tv_contrast_property) {
+ state->tv.contrast = val;
+ } else if (property == config->tv_flicker_reduction_property) {
+ state->tv.flicker_reduction = val;
+ } else if (property == config->tv_overscan_property) {
+ state->tv.overscan = val;
+ } else if (property == config->tv_saturation_property) {
+ state->tv.saturation = val;
+ } else if (property == config->tv_hue_property) {
+ state->tv.hue = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
} else {
return -EINVAL;
}
+
+ return 0;
}
EXPORT_SYMBOL(drm_atomic_connector_set_property);
@@ -1025,6 +1051,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = (state->crtc) ? state->crtc->base.id : 0;
} else if (property == config->dpms_property) {
*val = connector->dpms;
+ } else if (property == config->tv_select_subconnector_property) {
+ *val = state->tv.subconnector;
+ } else if (property == config->tv_left_margin_property) {
+ *val = state->tv.margins.left;
+ } else if (property == config->tv_right_margin_property) {
+ *val = state->tv.margins.right;
+ } else if (property == config->tv_top_margin_property) {
+ *val = state->tv.margins.top;
+ } else if (property == config->tv_bottom_margin_property) {
+ *val = state->tv.margins.bottom;
+ } else if (property == config->tv_mode_property) {
+ *val = state->tv.mode;
+ } else if (property == config->tv_brightness_property) {
+ *val = state->tv.brightness;
+ } else if (property == config->tv_contrast_property) {
+ *val = state->tv.contrast;
+ } else if (property == config->tv_flicker_reduction_property) {
+ *val = state->tv.flicker_reduction;
+ } else if (property == config->tv_overscan_property) {
+ *val = state->tv.overscan;
+ } else if (property == config->tv_saturation_property) {
+ *val = state->tv.saturation;
+ } else if (property == config->tv_hue_property) {
+ *val = state->tv.hue;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ac9d7d8e0e43..2645e8038572 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -194,10 +194,40 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
unsigned int num_formats);
/**
+ * struct drm_tv_connector_state - TV connector related states
+ * @subconnector: selected subconnector
+ * @margins: left/right/top/bottom margins
+ * @mode: TV mode
+ * @brightness: brightness in percent
+ * @contrast: contrast in percent
+ * @flicker_reduction: flicker reduction in percent
+ * @overscan: overscan in percent
+ * @saturation: saturation in percent
+ * @hue: hue in percent
+ */
+struct drm_tv_connector_state {
+ enum drm_mode_subconnector subconnector;
+ struct {
+ unsigned int left;
+ unsigned int right;
+ unsigned int top;
+ unsigned int bottom;
+ } margins;
+ unsigned int mode;
+ unsigned int brightness;
+ unsigned int contrast;
+ unsigned int flicker_reduction;
+ unsigned int overscan;
+ unsigned int saturation;
+ unsigned int hue;
+};
+
+/**
* struct drm_connector_state - mutable connector state
* @connector: backpointer to the connector
* @best_encoder: can be used by helpers and drivers to select the encoder
* @state: backpointer to global drm_atomic_state
+ * @tv: TV connector state
*/
struct drm_connector_state {
struct drm_connector *connector;
@@ -213,6 +243,8 @@ struct drm_connector_state {
struct drm_encoder *best_encoder;
struct drm_atomic_state *state;
+
+ struct drm_tv_connector_state tv;
};
/**
--
2.7.4
^ permalink raw reply related
* [PATCH v2 4/7] drm/vc4: Add support for the VEC (Video Encoder) IP
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>
The VEC IP is a TV DAC, providing support for PAL and NTSC standards.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/gpu/drm/vc4/Makefile | 1 +
drivers/gpu/drm/vc4/vc4_debugfs.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.h | 5 +
drivers/gpu/drm/vc4/vc4_vec.c | 657 ++++++++++++++++++++++++++++++++++++++
5 files changed, 665 insertions(+)
create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index fb77db755e0a..7757f69a8a77 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -11,6 +11,7 @@ vc4-y := \
vc4_kms.o \
vc4_gem.o \
vc4_hdmi.o \
+ vc4_vec.o \
vc4_hvs.o \
vc4_irq.o \
vc4_plane.o \
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index 245115d49c46..caf817bac885 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = {
{"bo_stats", vc4_bo_stats_debugfs, 0},
{"dpi_regs", vc4_dpi_debugfs_regs, 0},
{"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+ {"vec_regs", vc4_vec_debugfs_regs, 0},
{"hvs_regs", vc4_hvs_debugfs_regs, 0},
{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 8703f56b7947..3e6cb78f7381 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -289,6 +289,7 @@ static const struct component_master_ops vc4_drm_ops = {
static struct platform_driver *const component_drivers[] = {
&vc4_hdmi_driver,
+ &vc4_vec_driver,
&vc4_dpi_driver,
&vc4_hvs_driver,
&vc4_crtc_driver,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 946d48c33668..b3a46a51f9d0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -17,6 +17,7 @@ struct vc4_dev {
struct vc4_crtc *crtc[3];
struct vc4_v3d *v3d;
struct vc4_dpi *dpi;
+ struct vc4_vec *vec;
struct drm_fbdev_cma *fbdev;
@@ -484,6 +485,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
extern struct platform_driver vc4_hdmi_driver;
int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
+/* vc4_hdmi.c */
+extern struct platform_driver vc4_vec_driver;
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
+
/* vc4_irq.c */
irqreturn_t vc4_irq(int irq, void *arg);
void vc4_irq_preinstall(struct drm_device *dev);
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
new file mode 100644
index 000000000000..2d4256fcc6f2
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2016 Broadcom Limited
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * DOC: VC4 SDTV module
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_panel.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+/* WSE Registers */
+#define VEC_WSE_RESET 0xc0
+
+#define VEC_WSE_CONTROL 0xc4
+#define VEC_WSE_WSS_ENABLE BIT(7)
+
+#define VEC_WSE_WSS_DATA 0xc8
+#define VEC_WSE_VPS_DATA1 0xcc
+#define VEC_WSE_VPS_CONTROL 0xd0
+
+/* VEC Registers */
+#define VEC_REVID 0x100
+
+#define VEC_CONFIG0 0x104
+#define VEC_CONFIG0_YDEL_MASK GENMASK(28, 26)
+#define VEC_CONFIG0_YDEL(x) ((x) << 26)
+#define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24)
+#define VEC_CONFIG0_CDEL(x) ((x) << 24)
+#define VEC_CONFIG0_PBPR_FIL BIT(18)
+#define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16)
+#define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_32 (1 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_16 (2 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_8 (3 << 16)
+#define VEC_CONFIG0_CBURST_GAIN_MASK GENMASK(14, 13)
+#define VEC_CONFIG0_CBURST_GAIN_UNITY (0 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_128 (1 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_64 (2 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_32 (3 << 13)
+#define VEC_CONFIG0_CHRBW1 BIT(11)
+#define VEC_CONFIG0_CHRBW0 BIT(10)
+#define VEC_CONFIG0_SYNCDIS BIT(9)
+#define VEC_CONFIG0_BURDIS BIT(8)
+#define VEC_CONFIG0_CHRDIS BIT(7)
+#define VEC_CONFIG0_PDEN BIT(6)
+#define VEC_CONFIG0_YCDELAY BIT(4)
+#define VEC_CONFIG0_RAMPEN BIT(2)
+#define VEC_CONFIG0_YCDIS BIT(2)
+#define VEC_CONFIG0_STD_MASK GENMASK(1, 0)
+#define VEC_CONFIG0_NTSC_STD 0
+#define VEC_CONFIG0_PAL_BDGHI_STD 1
+#define VEC_CONFIG0_PAL_N_STD 3
+
+#define VEC_SCHPH 0x108
+#define VEC_SOFT_RESET 0x10c
+#define VEC_CLMP0_START 0x144
+#define VEC_CLMP0_END 0x148
+#define VEC_FREQ3_2 0x180
+#define VEC_FREQ1_0 0x184
+
+#define VEC_CONFIG1 0x188
+#define VEC_CONFIG_VEC_RESYNC_OFF BIT(18)
+#define VEC_CONFIG_RGB219 BIT(17)
+#define VEC_CONFIG_CBAR_EN BIT(16)
+#define VEC_CONFIG_TC_OBB BIT(15)
+#define VEC_CONFIG1_OUTPUT_MODE_MASK GENMASK(12, 10)
+#define VEC_CONFIG1_C_Y_CVBS (0 << 10)
+#define VEC_CONFIG1_CVBS_Y_C (1 << 10)
+#define VEC_CONFIG1_PR_Y_PB (2 << 10)
+#define VEC_CONFIG1_RGB (4 << 10)
+#define VEC_CONFIG1_Y_C_CVBS (5 << 10)
+#define VEC_CONFIG1_C_CVBS_Y (6 << 10)
+#define VEC_CONFIG1_C_CVBS_CVBS (7 << 10)
+#define VEC_CONFIG1_DIS_CHR BIT(9)
+#define VEC_CONFIG1_DIS_LUMA BIT(8)
+#define VEC_CONFIG1_YCBCR_IN BIT(6)
+#define VEC_CONFIG1_DITHER_TYPE_LFSR 0
+#define VEC_CONFIG1_DITHER_TYPE_COUNTER BIT(5)
+#define VEC_CONFIG1_DITHER_EN BIT(4)
+#define VEC_CONFIG1_CYDELAY BIT(3)
+#define VEC_CONFIG1_LUMADIS BIT(2)
+#define VEC_CONFIG1_COMPDIS BIT(1)
+#define VEC_CONFIG1_CUSTOM_FREQ BIT(0)
+
+#define VEC_CONFIG2 0x18c
+#define VEC_CONFIG2_PROG_SCAN BIT(15)
+#define VEC_CONFIG2_SYNC_ADJ_MASK GENMASK(14, 12)
+#define VEC_CONFIG2_SYNC_ADJ(x) (((x) / 2) << 12)
+#define VEC_CONFIG2_PBPR_EN BIT(10)
+#define VEC_CONFIG2_UV_DIG_DIS BIT(6)
+#define VEC_CONFIG2_RGB_DIG_DIS BIT(5)
+#define VEC_CONFIG2_TMUX_MASK GENMASK(3, 2)
+#define VEC_CONFIG2_TMUX_DRIVE0 (0 << 2)
+#define VEC_CONFIG2_TMUX_RG_COMP (1 << 2)
+#define VEC_CONFIG2_TMUX_UV_YC (2 << 2)
+#define VEC_CONFIG2_TMUX_SYNC_YC (3 << 2)
+
+#define VEC_INTERRUPT_CONTROL 0x190
+#define VEC_INTERRUPT_STATUS 0x194
+#define VEC_FCW_SECAM_B 0x198
+#define VEC_SECAM_GAIN_VAL 0x19c
+
+#define VEC_CONFIG3 0x1a0
+#define VEC_CONFIG3_HORIZ_LEN_STD (0 << 0)
+#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF (1 << 0)
+#define VEC_CONFIG3_SHAPE_NON_LINEAR BIT(1)
+
+#define VEC_STATUS0 0x200
+#define VEC_MASK0 0x204
+
+#define VEC_CFG 0x208
+#define VEC_CFG_SG_MODE_MASK GENMASK(6, 5)
+#define VEC_CFG_SG_MODE(x) ((x) << 5)
+#define VEC_CFG_SG_EN BIT(4)
+#define VEC_CFG_VEC_EN BIT(3)
+#define VEC_CFG_MB_EN BIT(2)
+#define VEC_CFG_ENABLE BIT(1)
+#define VEC_CFG_TB_EN BIT(0)
+
+#define VEC_DAC_TEST 0x20c
+
+#define VEC_DAC_CONFIG 0x210
+#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x) ((x) << 24)
+#define VEC_DAC_CONFIG_DRIVER_CTRL(x) ((x) << 16)
+#define VEC_DAC_CONFIG_DAC_CTRL(x) (x)
+
+#define VEC_DAC_MISC 0x214
+#define VEC_DAC_MISC_VCD_CTRL_MASK GENMASK(31, 16)
+#define VEC_DAC_MISC_VCD_CTRL(x) ((x) << 16)
+#define VEC_DAC_MISC_VID_ACT BIT(8)
+#define VEC_DAC_MISC_VCD_PWRDN BIT(6)
+#define VEC_DAC_MISC_BIAS_PWRDN BIT(5)
+#define VEC_DAC_MISC_DAC_PWRDN BIT(2)
+#define VEC_DAC_MISC_LDO_PWRDN BIT(1)
+#define VEC_DAC_MISC_DAC_RST_N BIT(0)
+
+
+/* General VEC hardware state. */
+struct vc4_vec {
+ struct platform_device *pdev;
+
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+
+ void __iomem *regs;
+
+ struct clk *clock;
+
+ const struct vc4_vec_tv_mode *tv_mode;
+};
+
+#define VEC_READ(offset) readl(vec->regs + (offset))
+#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
+
+/* VC4 VEC encoder KMS struct */
+struct vc4_vec_encoder {
+ struct vc4_encoder base;
+ struct vc4_vec *vec;
+};
+
+static inline struct vc4_vec_encoder *
+to_vc4_vec_encoder(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct vc4_vec_encoder, base.base);
+}
+
+/* VC4 VEC connector KMS struct */
+struct vc4_vec_connector {
+ struct drm_connector base;
+ struct vc4_vec *vec;
+
+ /* Since the connector is attached to just the one encoder,
+ * this is the reference to it so we can do the best_encoder()
+ * hook.
+ */
+ struct drm_encoder *encoder;
+};
+
+static inline struct vc4_vec_connector *
+to_vc4_vec_connector(struct drm_connector *connector)
+{
+ return container_of(connector, struct vc4_vec_connector, base);
+}
+
+enum vc4_vec_tv_mode_id {
+ VC4_VEC_TV_MODE_NTSC,
+ VC4_VEC_TV_MODE_NTSC_J,
+ VC4_VEC_TV_MODE_PAL,
+ VC4_VEC_TV_MODE_PAL_M,
+};
+
+struct vc4_vec_tv_mode {
+ const struct drm_display_mode *mode;
+ void (*mode_set)(struct vc4_vec *vec);
+};
+
+#define VEC_REG(reg) { reg, #reg }
+static const struct {
+ u32 reg;
+ const char *name;
+} vec_regs[] = {
+ VEC_REG(VEC_WSE_CONTROL),
+ VEC_REG(VEC_WSE_WSS_DATA),
+ VEC_REG(VEC_WSE_VPS_DATA1),
+ VEC_REG(VEC_WSE_VPS_CONTROL),
+ VEC_REG(VEC_REVID),
+ VEC_REG(VEC_CONFIG0),
+ VEC_REG(VEC_SCHPH),
+ VEC_REG(VEC_CLMP0_START),
+ VEC_REG(VEC_CLMP0_END),
+ VEC_REG(VEC_FREQ3_2),
+ VEC_REG(VEC_FREQ1_0),
+ VEC_REG(VEC_CONFIG1),
+ VEC_REG(VEC_CONFIG2),
+ VEC_REG(VEC_INTERRUPT_CONTROL),
+ VEC_REG(VEC_INTERRUPT_STATUS),
+ VEC_REG(VEC_FCW_SECAM_B),
+ VEC_REG(VEC_SECAM_GAIN_VAL),
+ VEC_REG(VEC_CONFIG3),
+ VEC_REG(VEC_STATUS0),
+ VEC_REG(VEC_MASK0),
+ VEC_REG(VEC_CFG),
+ VEC_REG(VEC_DAC_TEST),
+ VEC_REG(VEC_DAC_CONFIG),
+ VEC_REG(VEC_DAC_MISC),
+};
+
+#ifdef CONFIG_DEBUG_FS
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_vec *vec = vc4->vec;
+ int i;
+
+ if (!vec)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(vec_regs); i++) {
+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
+ vec_regs[i].name, vec_regs[i].reg,
+ VEC_READ(vec_regs[i].reg));
+ }
+
+ return 0;
+}
+#endif
+
+static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
+ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
+ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static const struct drm_display_mode ntsc_mode = {
+ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
+ 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
+ 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+ DRM_MODE_FLAG_INTERLACE)
+};
+
+static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+ VEC_WRITE(VEC_CONFIG1,
+ VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
+ VEC_WRITE(VEC_FREQ3_2, 0x223b);
+ VEC_WRITE(VEC_FREQ1_0, 0x61d1);
+}
+
+static const struct drm_display_mode pal_mode = {
+ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
+ 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
+ 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+ DRM_MODE_FLAG_INTERLACE)
+};
+
+static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
+ [VC4_VEC_TV_MODE_NTSC] = {
+ .mode = &ntsc_mode,
+ .mode_set = vc4_vec_ntsc_mode_set,
+ },
+ [VC4_VEC_TV_MODE_NTSC_J] = {
+ .mode = &ntsc_mode,
+ .mode_set = vc4_vec_ntsc_j_mode_set,
+ },
+ [VC4_VEC_TV_MODE_PAL] = {
+ .mode = &pal_mode,
+ .mode_set = vc4_vec_pal_mode_set,
+ },
+ [VC4_VEC_TV_MODE_PAL_M] = {
+ .mode = &pal_mode,
+ .mode_set = vc4_vec_pal_m_mode_set,
+ },
+};
+
+static enum drm_connector_status
+vc4_vec_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_unknown;
+}
+
+static void vc4_vec_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static int vc4_vec_connector_get_modes(struct drm_connector *connector)
+{
+ struct drm_connector_state *state = connector->state;
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev,
+ vc4_vec_tv_modes[state->tv.mode].mode);
+ if (!mode) {
+ DRM_ERROR("Failed to create a new display mode\n");
+ return -ENOMEM;
+ }
+
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_connector_funcs vc4_vec_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = vc4_vec_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = drm_atomic_helper_connector_set_property,
+ .destroy = vc4_vec_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
+ .get_modes = vc4_vec_connector_get_modes,
+};
+
+static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
+ struct vc4_vec *vec)
+{
+ struct drm_connector *connector = NULL;
+ struct vc4_vec_connector *vec_connector;
+
+ vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
+ GFP_KERNEL);
+ if (!vec_connector)
+ return ERR_PTR(-ENOMEM);
+
+ connector = &vec_connector->base;
+ connector->interlace_allowed = true;
+
+ vec_connector->encoder = vec->encoder;
+ vec_connector->vec = vec;
+
+ drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
+ DRM_MODE_CONNECTOR_Composite);
+ drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
+
+ drm_object_attach_property(&connector->base,
+ dev->mode_config.tv_mode_property,
+ VC4_VEC_TV_MODE_NTSC);
+ vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
+
+ drm_mode_connector_attach_encoder(connector, vec->encoder);
+
+ return connector;
+}
+
+static const struct drm_encoder_funcs vc4_vec_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
+{
+ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+ struct vc4_vec *vec = vc4_vec_encoder->vec;
+ int ret;
+
+ VEC_WRITE(VEC_CFG, 0);
+ VEC_WRITE(VEC_DAC_MISC,
+ VEC_DAC_MISC_VCD_PWRDN |
+ VEC_DAC_MISC_BIAS_PWRDN |
+ VEC_DAC_MISC_DAC_PWRDN |
+ VEC_DAC_MISC_LDO_PWRDN);
+
+ clk_disable_unprepare(vec->clock);
+
+ ret = pm_runtime_put(&vec->pdev->dev);
+ if (ret < 0) {
+ DRM_ERROR("Failed to release power domain: %d\n", ret);
+ return;
+ }
+}
+
+static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
+{
+ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+ struct vc4_vec *vec = vc4_vec_encoder->vec;
+ int ret;
+
+ ret = pm_runtime_get_sync(&vec->pdev->dev);
+ if (ret < 0) {
+ DRM_ERROR("Failed to retain power domain: %d\n", ret);
+ return;
+ }
+
+ /*
+ * We need to set the clock rate each time we enable the encoder
+ * because there's a chance we share the same parent with the HDMI
+ * clock, and both drivers are requesting different rates.
+ * The good news is, these 2 encoders cannot be enabled@the same
+ * time, thus preventing incompatible rate requests.
+ */
+ ret = clk_set_rate(vec->clock, 108000000);
+ if (ret) {
+ DRM_ERROR("Failed to set clock rate: %d\n", ret);
+ return;
+ }
+
+ ret = clk_prepare_enable(vec->clock);
+ if (ret) {
+ DRM_ERROR("Failed to turn on core clock: %d\n", ret);
+ return;
+ }
+
+ /* Reset the different blocks */
+ VEC_WRITE(VEC_WSE_RESET, 1);
+ VEC_WRITE(VEC_SOFT_RESET, 1);
+
+ /* Disable the CGSM-A and WSE blocks */
+ VEC_WRITE(VEC_WSE_CONTROL, 0);
+
+ /* Write config common to all modes. */
+
+ /*
+ * Color subcarrier phase: phase = 360 * SCHPH / 256.
+ * 0x28 <=> 39.375 deg.
+ */
+ VEC_WRITE(VEC_SCHPH, 0x28);
+
+ /*
+ * Reset to default values.
+ */
+ VEC_WRITE(VEC_CLMP0_START, 0xac);
+ VEC_WRITE(VEC_CLMP0_END, 0xec);
+ VEC_WRITE(VEC_CONFIG2,
+ VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
+ VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
+ VEC_WRITE(VEC_DAC_CONFIG,
+ VEC_DAC_CONFIG_DAC_CTRL(0xc) |
+ VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
+ VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
+
+ /* Mask all interrupts. */
+ VEC_WRITE(VEC_MASK0, 0);
+
+ vec->tv_mode->mode_set(vec);
+
+ VEC_WRITE(VEC_DAC_MISC,
+ VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
+ VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
+}
+
+
+static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+ struct vc4_vec *vec = vc4_vec_encoder->vec;
+
+ vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+}
+
+static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ const struct vc4_vec_tv_mode *vec_mode;
+
+ vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+
+ if (conn_state->crtc &&
+ !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
+ .disable = vc4_vec_encoder_disable,
+ .enable = vc4_vec_encoder_enable,
+ .mode_fixup = vc4_vec_encoder_mode_fixup,
+ .atomic_check = vc4_vec_encoder_atomic_check,
+ .atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
+};
+
+static const struct of_device_id vc4_vec_dt_match[] = {
+ { .compatible = "brcm,bcm2835-vec", .data = NULL },
+ { /* sentinel */ },
+};
+
+static const char * const tv_mode_names[] = {
+ [VC4_VEC_TV_MODE_NTSC] = "NTSC",
+ [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
+ [VC4_VEC_TV_MODE_PAL] = "PAL",
+ [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
+};
+
+static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_vec *vec;
+ struct vc4_vec_encoder *vc4_vec_encoder;
+ int ret;
+
+ ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
+ tv_mode_names);
+ if (ret)
+ return ret;
+
+ vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
+ if (!vec)
+ return -ENOMEM;
+
+ vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
+ GFP_KERNEL);
+ if (!vc4_vec_encoder)
+ return -ENOMEM;
+ vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
+ vc4_vec_encoder->vec = vec;
+ vec->encoder = &vc4_vec_encoder->base.base;
+
+ vec->pdev = pdev;
+ vec->regs = vc4_ioremap_regs(pdev, 0);
+ if (IS_ERR(vec->regs))
+ return PTR_ERR(vec->regs);
+
+ vec->clock = devm_clk_get(dev, NULL);
+ if (IS_ERR(vec->clock)) {
+ ret = PTR_ERR(vec->clock);
+ if (ret != -EPROBE_DEFER)
+ DRM_ERROR("Failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+
+ drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs,
+ DRM_MODE_ENCODER_TVDAC, NULL);
+ drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
+
+ vec->connector = vc4_vec_connector_init(drm, vec);
+ if (IS_ERR(vec->connector)) {
+ ret = PTR_ERR(vec->connector);
+ goto err_destroy_encoder;
+ }
+
+ dev_set_drvdata(dev, vec);
+
+ vc4->vec = vec;
+
+ return 0;
+
+err_destroy_encoder:
+ drm_encoder_cleanup(vec->encoder);
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static void vc4_vec_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_vec *vec = dev_get_drvdata(dev);
+
+ vc4_vec_connector_destroy(vec->connector);
+ drm_encoder_cleanup(vec->encoder);
+ pm_runtime_disable(dev);
+
+ vc4->vec = NULL;
+}
+
+static const struct component_ops vc4_vec_ops = {
+ .bind = vc4_vec_bind,
+ .unbind = vc4_vec_unbind,
+};
+
+static int vc4_vec_dev_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &vc4_vec_ops);
+}
+
+static int vc4_vec_dev_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &vc4_vec_ops);
+ return 0;
+}
+
+struct platform_driver vc4_vec_driver = {
+ .probe = vc4_vec_dev_probe,
+ .remove = vc4_vec_dev_remove,
+ .driver = {
+ .name = "vc4_vec",
+ .of_match_table = vc4_vec_dt_match,
+ },
+};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 5/7] drm/vc4: Document VEC DT binding
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>
Document the DT binding for the VEC (Video EnCoder) IP.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
index a5ea451e67fc..e2768703ac2b 100644
--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
+++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
@@ -43,6 +43,13 @@ Required properties for DPI:
- port: Port node with a single endpoint connecting to the panel
device, as defined in [1]
+Required properties for VEC:
+- compatible: Should be "brcm,bcm2835-vec"
+- reg: Physical base address and length of the registers
+- clocks: The core clock the unit runs on
+- interrupts: The interrupt number
+ See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
Required properties for V3D:
- compatible: Should be "brcm,bcm2835-v3d"
- reg: Physical base address and length of the V3D's registers
@@ -92,6 +99,13 @@ dpi: dpi at 7e208000 {
};
};
+vec: vec at 7e806000 {
+ compatible = "brcm,bcm2835-vec";
+ reg = <0x7e806000 0x1000>;
+ clocks = <&clocks BCM2835_CLOCK_VEC>;
+ interrupts = <2 27>;
+};
+
v3d: v3d at 7ec00000 {
compatible = "brcm,bcm2835-v3d";
reg = <0x7ec00000 0x1000>;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 6/7] ARM: bcm/dt: Add VEC node in bcm283x.dtsi
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>
Add the VEC (Video EnCoder) node definition in bcm283x.dtsi.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
arch/arm/boot/dts/bcm283x.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index 46d46d894a44..44a9c0539437 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -266,6 +266,14 @@
status = "disabled";
};
+ vec: vec at 7e806000 {
+ compatible = "brcm,bcm2835-vec";
+ reg = <0x7e806000 0x1000>;
+ clocks = <&clocks BCM2835_CLOCK_VEC>;
+ interrupts = <2 27>;
+ status = "disabled";
+ };
+
pixelvalve at 7e807000 {
compatible = "brcm,bcm2835-pixelvalve2";
reg = <0x7e807000 0x100>;
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox