summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Robinson <pbrobinson@gmail.com>2016-04-11 22:36:23 +0100
committerPeter Robinson <pbrobinson@gmail.com>2016-04-11 22:36:23 +0100
commitdf1a50892b8faf073790cfcacb73a81a23a0162a (patch)
treeabd0eae6364bdf5fe9b615028424881c455b0604
parent1fd1a427cc84c1b82713d48a09cfc1dffb2090aa (diff)
downloadkernel-df1a50892b8faf073790cfcacb73a81a23a0162a.tar.gz
kernel-df1a50892b8faf073790cfcacb73a81a23a0162a.tar.xz
kernel-df1a50892b8faf073790cfcacb73a81a23a0162a.zip
change the means of bcm238x patch set. NFC
-rw-r--r--bcm283x-Pull-upstream-fixes-plus-iproc-mmc-driver.patch3887
1 files changed, 2626 insertions, 1261 deletions
diff --git a/bcm283x-Pull-upstream-fixes-plus-iproc-mmc-driver.patch b/bcm283x-Pull-upstream-fixes-plus-iproc-mmc-driver.patch
index 35c6e524b..56f2a3981 100644
--- a/bcm283x-Pull-upstream-fixes-plus-iproc-mmc-driver.patch
+++ b/bcm283x-Pull-upstream-fixes-plus-iproc-mmc-driver.patch
@@ -1,523 +1,726 @@
-From 19778e51ab57b1a7e310c2efedbe8d9df1b81672 Mon Sep 17 00:00:00 2001
-From: Peter Robinson <pbrobinson@gmail.com>
-Date: Mon, 11 Apr 2016 11:10:17 +0100
-Subject: [PATCH] bcm283x: Pull upstream fixes plus iproc mmc driver
+From 735f01326873349426f041a4fa2f5703a1ed43a4 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 5 Feb 2016 15:06:15 -0800
+Subject: [PATCH 01/36] drm/vc4: Fix a framebuffer reference leak on async flip
+ interrupt.
+
+We'd need X to queue up an async pageflip while another is
+outstanding, and then take a SIGIO. I think X actually avoids sending
+out the next pageflip while one's already queued, but I'm not sure.
+Signed-off-by: Eric Anholt <eric@anholt.net>
---
- .../devicetree/bindings/arm/bcm/brcm,bcm2835.txt | 4 +
- .../bindings/serial/brcm,bcm2835-aux-uart.txt | 18 +
- arch/arm/boot/dts/Makefile | 4 +-
- arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 4 +
- arch/arm/boot/dts/bcm2835-rpi-a.dts | 28 +
- arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 4 +
- arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 4 +
- arch/arm/boot/dts/bcm2835-rpi-b.dts | 4 +
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 21 +
- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 4 +
- arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 22 +
- arch/arm/boot/dts/bcm2837.dtsi | 68 +++
- arch/arm/boot/dts/bcm283x.dtsi | 90 ++-
- drivers/clk/bcm/clk-bcm2835.c | 12 +-
- drivers/gpu/drm/vc4/vc4_bo.c | 7 +-
- drivers/gpu/drm/vc4/vc4_crtc.c | 134 +++--
- drivers/gpu/drm/vc4/vc4_drv.h | 12 +-
- drivers/gpu/drm/vc4/vc4_hdmi.c | 42 +-
- drivers/gpu/drm/vc4/vc4_hvs.c | 97 ++++
- drivers/gpu/drm/vc4/vc4_kms.c | 9 +
- drivers/gpu/drm/vc4/vc4_plane.c | 603 +++++++++++++++++++--
- drivers/gpu/drm/vc4/vc4_regs.h | 120 +++-
- drivers/gpu/drm/vc4/vc4_v3d.c | 1 +
- drivers/mmc/host/Kconfig | 6 +-
- drivers/mmc/host/sdhci-iproc.c | 33 +-
- drivers/tty/serial/8250/8250_bcm2835aux.c | 146 +++++
- drivers/tty/serial/8250/Kconfig | 24 +
- drivers/tty/serial/8250/Makefile | 1 +
- 28 files changed, 1394 insertions(+), 128 deletions(-)
- create mode 100644 Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
- create mode 100644 arch/arm/boot/dts/bcm2835-rpi-a.dts
- create mode 100644 arch/arm/boot/dts/bcm2837-rpi-3-b.dts
- create mode 100644 arch/arm/boot/dts/bcm2837.dtsi
- create mode 100644 drivers/tty/serial/8250/8250_bcm2835aux.c
+ drivers/gpu/drm/vc4/vc4_crtc.c | 1 +
+ 1 file changed, 1 insertion(+)
-diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
-index 11d3056..6ffe087 100644
---- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
-+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
-@@ -30,6 +30,10 @@ Raspberry Pi 2 Model B
- Required root node properties:
- compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
+index 018145e..989ee72 100644
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -544,6 +544,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc,
+ /* Make sure all other async modesetes have landed. */
+ ret = down_interruptible(&vc4->async_modeset);
+ if (ret) {
++ drm_framebuffer_unreference(fb);
+ kfree(flip_state);
+ return ret;
+ }
+--
+2.7.3
+
+From e1ceac2cefbda12d1d9d9ee547fc0cc8bfeebde6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 12 Feb 2016 14:15:14 -0800
+Subject: [PATCH 02/36] drm/vc4: Bring HDMI up from power off if necessary.
+
+If the firmware hadn't brought up HDMI for us, we need to do its
+power-on reset sequence (reset HD and and clear its STANDBY bits,
+reset HDMI, and leave the PHY disabled).
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 29 ++++++++++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc4_regs.h | 2 ++
+ 2 files changed, 30 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
+index c69c046..6e55760 100644
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -495,6 +495,16 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
+ goto err_put_i2c;
+ }
-+Raspberry Pi 3 Model B
-+Required root node properties:
-+compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
-+
- Raspberry Pi Compute Module
- Required root node properties:
- compatible = "raspberrypi,compute-module", "brcm,bcm2835";
-diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
-new file mode 100644
-index 0000000..b5cc629
---- /dev/null
-+++ b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
-@@ -0,0 +1,18 @@
-+* BCM2835 AUXILIAR UART
-+
-+Required properties:
-+
-+- compatible: "brcm,bcm2835-aux-uart"
-+- reg: The base address of the UART register bank.
-+- interrupts: A single interrupt specifier.
-+- clocks: Clock driving the hardware; used to figure out the baud rate
-+ divisor.
-+
-+Example:
-+
-+ uart1: serial@7e215040 {
-+ compatible = "brcm,bcm2835-aux-uart";
-+ reg = <0x7e215040 0x40>;
-+ interrupts = <1 29>;
-+ clocks = <&aux BCM2835_AUX_CLOCK_UART>;
-+ };
-diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
-index a4a6d70..a8a0767 100644
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -60,10 +60,12 @@ dtb-$(CONFIG_ARCH_AXXIA) += \
- axm5516-amarillo.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2835-rpi-b.dtb \
-+ bcm2835-rpi-a.dtb \
- bcm2835-rpi-b-rev2.dtb \
- bcm2835-rpi-b-plus.dtb \
- bcm2835-rpi-a-plus.dtb \
-- bcm2836-rpi-2-b.dtb
-+ bcm2836-rpi-2-b.dtb \
-+ bcm2837-rpi-3-b.dtb
- dtb-$(CONFIG_ARCH_BCM_5301X) += \
- bcm4708-asus-rt-ac56u.dtb \
- bcm4708-asus-rt-ac68u.dtb \
-diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-index 228614f..35ff4e7a 100644
---- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-@@ -29,3 +29,7 @@
- brcm,function = <BCM2835_FSEL_ALT0>;
- };
- };
-+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts
-new file mode 100644
-index 0000000..306a84e
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
-@@ -0,0 +1,28 @@
-+/dts-v1/;
-+#include "bcm2835.dtsi"
-+#include "bcm2835-rpi.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,model-a", "brcm,bcm2835";
-+ model = "Raspberry Pi Model A";
-+
-+ leds {
-+ act {
-+ gpios = <&gpio 16 1>;
-+ };
-+ };
-+};
++ /* This is the rate that is set by the firmware. The number
++ * needs to be a bit higher than the pixel clock rate
++ * (generally 148.5Mhz).
++ */
++ ret = clk_set_rate(hdmi->hsm_clock, 163682864);
++ if (ret) {
++ DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
++ goto err_unprepare_pix;
++ }
+
-+&gpio {
-+ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>;
+ ret = clk_prepare_enable(hdmi->hsm_clock);
+ if (ret) {
+ DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n",
+@@ -516,7 +526,24 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
+ vc4->hdmi = hdmi;
+
+ /* HDMI core must be enabled. */
+- WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0);
++ if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) {
++ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST);
++ udelay(1);
++ HD_WRITE(VC4_HD_M_CTL, 0);
+
-+ /* I2S interface */
-+ i2s_alt2: i2s_alt2 {
-+ brcm,pins = <28 29 30 31>;
-+ brcm,function = <BCM2835_FSEL_ALT2>;
-+ };
-+};
++ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE);
+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+};
-diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-index ef54050..57d313b 100644
---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-@@ -29,3 +29,7 @@
- brcm,function = <BCM2835_FSEL_ALT0>;
- };
- };
++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL,
++ VC4_HDMI_SW_RESET_HDMI |
++ VC4_HDMI_SW_RESET_FORMAT_DETECT);
+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-index 86f1f2f..cf2774e 100644
---- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-@@ -22,3 +22,7 @@
- brcm,function = <BCM2835_FSEL_ALT2>;
- };
- };
++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0);
+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
-index 4859e9d..8b15f9c 100644
---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
-@@ -16,3 +16,7 @@
- &gpio {
- pinctrl-0 = <&gpioout &alt0 &alt3>;
- };
++ /* PHY should be in reset, like
++ * vc4_hdmi_encoder_disable() does.
++ */
++ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
++ }
+
+ drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
+diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
+index 4e52a0a..85c36d2 100644
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -456,6 +456,8 @@
+ #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
+
+ #define VC4_HD_M_CTL 0x00c
++# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
++# define VC4_HD_M_RAM_STANDBY (3 << 4)
+ # define VC4_HD_M_SW_RST BIT(2)
+ # define VC4_HD_M_ENABLE BIT(0)
+
+--
+2.7.3
+
+From 63d38d99739736480b24c9f9bd7880ce4e49eb0c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 12 Feb 2016 15:16:56 -0800
+Subject: [PATCH 03/36] drm/vc4: Add another reg to HDMI debug dumping.
+
+This is also involved in the HDMI setup sequence so it's nice to see
+it.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
+index 6e55760..56272ca 100644
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -95,6 +95,7 @@ static const struct {
+ HDMI_REG(VC4_HDMI_SW_RESET_CONTROL),
+ HDMI_REG(VC4_HDMI_HOTPLUG_INT),
+ HDMI_REG(VC4_HDMI_HOTPLUG),
++ HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG),
+ HDMI_REG(VC4_HDMI_HORZA),
+ HDMI_REG(VC4_HDMI_HORZB),
+ HDMI_REG(VC4_HDMI_FIFO_CTL),
+--
+2.7.3
+
+From 46e96facb9b67486285c26f88ee747b8d9f4abc9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 15 Feb 2016 17:06:02 -0800
+Subject: [PATCH 04/36] drm/vc4: Fix the name of the VSYNCD_EVEN register.
+
+It's used for delaying vsync in interlaced mode.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 2 +-
+ drivers/gpu/drm/vc4/vc4_regs.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
+index 989ee72..5e84be2 100644
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -83,7 +83,7 @@ static const struct {
+ } crtc_regs[] = {
+ CRTC_REG(PV_CONTROL),
+ CRTC_REG(PV_V_CONTROL),
+- CRTC_REG(PV_VSYNCD),
++ CRTC_REG(PV_VSYNCD_EVEN),
+ CRTC_REG(PV_HORZA),
+ CRTC_REG(PV_HORZB),
+ CRTC_REG(PV_VERTA),
+diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
+index 85c36d2..d529665 100644
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -187,7 +187,7 @@
+ # define PV_VCONTROL_CONTINUOUS BIT(1)
+ # define PV_VCONTROL_VIDEN BIT(0)
+
+-#define PV_VSYNCD 0x08
++#define PV_VSYNCD_EVEN 0x08
+
+ #define PV_HORZA 0x0c
+ # define PV_HORZA_HBP_MASK VC4_MASK(31, 16)
+--
+2.7.3
+
+From baff41935a7b4c1b6015a99a0ca222fd0a5552b9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 15 Feb 2016 17:31:41 -0800
+Subject: [PATCH 05/36] drm/vc4: Fix setting of vertical timings in the CRTC.
+
+It looks like when I went to add the interlaced bits, I just took the
+existing PV_VERT* block and indented it, instead of copy and pasting
+it first. Without this, changing resolution never worked.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
+index 5e84be2..93d53c2 100644
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -212,6 +212,16 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+ PV_HORZB_HFP) |
+ VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
+
++ CRTC_WRITE(PV_VERTA,
++ VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
++ PV_VERTA_VBP) |
++ VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
++ PV_VERTA_VSYNC));
++ CRTC_WRITE(PV_VERTB,
++ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
++ PV_VERTB_VFP) |
++ VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+};
-diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-index 3afb9fe..b1e8145 100644
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -1,3 +1,5 @@
-+#include <dt-bindings/power/raspberrypi-power.h>
+ if (interlace) {
+ CRTC_WRITE(PV_VERTA_EVEN,
+ VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1,
+--
+2.7.3
+
+From 6f7cde6ad6e866660b8e5607a213872e5f34e8fd Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 16 Feb 2016 10:24:08 -0800
+Subject: [PATCH 06/36] drm/vc4: Initialize scaler DISPBKGND on modeset.
+
+We weren't updating the interlaced bit, so we'd scan out incorrectly
+if the firmware had brought up the TV encoder and we were switching to
+HDMI.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 6 ++++++
+ drivers/gpu/drm/vc4/vc4_regs.h | 14 ++++++++++++++
+ 2 files changed, 20 insertions(+)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
+index 93d53c2..6ae5abc 100644
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -183,6 +183,8 @@ static int vc4_get_clock_select(struct drm_crtc *crtc)
+
+ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+ {
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_crtc_state *state = crtc->state;
+ struct drm_display_mode *mode = &state->adjusted_mode;
+@@ -251,6 +253,10 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+ PV_CONTROL_FIFO_CLR |
+ PV_CONTROL_EN);
+
++ HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
++ SCALER_DISPBKGND_AUTOHS |
++ (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
+
- / {
- memory {
- reg = <0 0x10000000>;
-@@ -18,6 +20,12 @@
- compatible = "raspberrypi,bcm2835-firmware";
- mboxes = <&mailbox>;
- };
+ if (debug_dump_regs) {
+ DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc));
+ vc4_crtc_dump_regs(vc4_crtc);
+diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
+index d529665..7c29993 100644
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -350,6 +350,17 @@
+ # define SCALER_DISPCTRLX_HEIGHT_SHIFT 0
+
+ #define SCALER_DISPBKGND0 0x00000044
++# define SCALER_DISPBKGND_AUTOHS BIT(31)
++# define SCALER_DISPBKGND_INTERLACE BIT(30)
++# define SCALER_DISPBKGND_GAMMA BIT(29)
++# define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25)
++# define SCALER_DISPBKGND_TESTMODE_SHIFT 25
++/* Enables filling the scaler line with the RGB value in the low 24
++ * bits before compositing. Costs cycles, so should be skipped if
++ * opaque display planes will cover everything.
++ */
++# define SCALER_DISPBKGND_FILL BIT(24)
+
-+ power: power {
-+ compatible = "raspberrypi,bcm2835-power";
-+ firmware = <&firmware>;
-+ #power-domain-cells = <1>;
-+ };
- };
+ #define SCALER_DISPSTAT0 0x00000048
+ #define SCALER_DISPBASE0 0x0000004c
+ # define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30)
+@@ -362,6 +373,9 @@
+ # define SCALER_DISPSTATX_EMPTY BIT(28)
+ #define SCALER_DISPCTRL1 0x00000050
+ #define SCALER_DISPBKGND1 0x00000054
++#define SCALER_DISPBKGNDX(x) (SCALER_DISPBKGND0 + \
++ (x) * (SCALER_DISPBKGND1 - \
++ SCALER_DISPBKGND0))
+ #define SCALER_DISPSTAT1 0x00000058
+ #define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \
+ (x) * (SCALER_DISPSTAT1 - \
+--
+2.7.3
+
+From 449c91f1f06a573ad4a3edd18d7b493bf44478f6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:14:09 -0800
+Subject: [PATCH 07/36] drm/vc4: Improve comments on vc4_plane_state members.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index 0addbad..45e353d 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -26,16 +26,19 @@
+
+ struct vc4_plane_state {
+ struct drm_plane_state base;
++ /* System memory copy of the display list for this element, computed
++ * at atomic_check time.
++ */
+ u32 *dlist;
+- u32 dlist_size; /* Number of dwords in allocated for the display list */
++ u32 dlist_size; /* Number of dwords allocated for the display list */
+ u32 dlist_count; /* Number of used dwords in the display list. */
+
+ /* Offset in the dlist to pointer word 0. */
+ u32 pw0_offset;
+
+ /* Offset where the plane's dlist was last stored in the
+- hardware at vc4_crtc_atomic_flush() time.
+- */
++ * hardware at vc4_crtc_atomic_flush() time.
++ */
+ u32 *hw_dlist;
};
-@@ -58,3 +66,16 @@
- status = "okay";
- bus-width = <4>;
+--
+2.7.3
+
+From 4c8b2ce80659e1c7a75b7b54430dab320aeb440b Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:14:57 -0800
+Subject: [PATCH 08/36] drm/vc4: Add missing __iomem annotation to hw_dlist.
+
+This is the pointer to the HVS device's memory where we stored the
+contents of *dlist.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index 45e353d..ed07ee5 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -39,7 +39,7 @@ struct vc4_plane_state {
+ /* Offset where the plane's dlist was last stored in the
+ * hardware at vc4_crtc_atomic_flush() time.
+ */
+- u32 *hw_dlist;
++ u32 __iomem *hw_dlist;
};
+
+ static inline struct vc4_plane_state *
+--
+2.7.3
+
+From f792f380190638916b495f3051547a849fc97fd2 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:34:44 -0800
+Subject: [PATCH 09/36] drm/vc4: Move the plane clipping/scaling setup to a
+ separate function.
+
+As we add actual scaling, this is going to get way more complicated.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 78 +++++++++++++++++++++++++++--------------
+ 1 file changed, 52 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index ed07ee5..554ed54 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -40,6 +40,14 @@ struct vc4_plane_state {
+ * hardware at vc4_crtc_atomic_flush() time.
+ */
+ u32 __iomem *hw_dlist;
+
-+&pwm {
-+ status = "okay";
-+};
-+
-+&v3d {
-+ power-domains = <&power RPI_POWER_DOMAIN_V3D>;
-+};
++ /* Clipped coordinates of the plane on the display. */
++ int crtc_x, crtc_y, crtc_w, crtc_h;
+
-+&hdmi {
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
-+};
-diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-index ff94666..c4743f4 100644
---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-@@ -33,3 +33,7 @@
- brcm,function = <BCM2835_FSEL_ALT0>;
- };
++ /* Offset to start scanning out from the start of the plane's
++ * BO.
++ */
++ u32 offset;
};
+
+ static inline struct vc4_plane_state *
+@@ -151,22 +159,17 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
+ vc4_state->dlist[vc4_state->dlist_count++] = val;
+ }
+
+-/* Writes out a full display list for an active plane to the plane's
+- * private dlist state.
+- */
+-static int vc4_plane_mode_set(struct drm_plane *plane,
+- struct drm_plane_state *state)
++static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ {
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- u32 ctl0_offset = vc4_state->dlist_count;
+- const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
+- uint32_t offset = fb->offsets[0];
+- int crtc_x = state->crtc_x;
+- int crtc_y = state->crtc_y;
+- int crtc_w = state->crtc_w;
+- int crtc_h = state->crtc_h;
+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-new file mode 100644
-index 0000000..5e8eafd
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-@@ -0,0 +1,22 @@
-+/dts-v1/;
-+#include "bcm2837.dtsi"
-+#include "bcm2835-rpi.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
-+ model = "Raspberry Pi 3 Model B";
-+
-+ memory {
-+ reg = <0 0x40000000>;
-+ };
-+};
-+
-+&gpio {
-+ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
-+
-+ /* I2S interface */
-+ i2s_alt0: i2s_alt0 {
-+ brcm,pins = <28 29 30 31>;
-+ brcm,function = <BCM2835_FSEL_ALT2>;
-+ };
-+};
-diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi
-new file mode 100644
-index 0000000..2f36722
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2837.dtsi
-@@ -0,0 +1,68 @@
-+#include "bcm283x.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2836";
-+
-+ soc {
-+ ranges = <0x7e000000 0x3f000000 0x1000000>,
-+ <0x40000000 0x40000000 0x00001000>;
-+ dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
-+
-+ local_intc: local_intc {
-+ compatible = "brcm,bcm2836-l1-intc";
-+ reg = <0x40000000 0x100>;
-+ interrupt-controller;
-+ #interrupt-cells = <1>;
-+ interrupt-parent = <&local_intc>;
-+ };
-+ };
++ vc4_state->offset = fb->offsets[0];
+
-+ timer {
-+ compatible = "arm,armv7-timer";
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <0>, // PHYS_SECURE_PPI
-+ <1>, // PHYS_NONSECURE_PPI
-+ <3>, // VIRT_PPI
-+ <2>; // HYP_PPI
-+ always-on;
-+ };
-+
-+ cpus: cpus {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
++ vc4_state->crtc_x = state->crtc_x;
++ vc4_state->crtc_y = state->crtc_y;
++ vc4_state->crtc_w = state->crtc_w;
++ vc4_state->crtc_h = state->crtc_h;
+
+ if (state->crtc_w << 16 != state->src_w ||
+ state->crtc_h << 16 != state->src_h) {
+@@ -178,18 +181,41 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ return -EINVAL;
+ }
+
+- if (crtc_x < 0) {
+- offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x;
+- crtc_w += crtc_x;
+- crtc_x = 0;
++ if (vc4_state->crtc_x < 0) {
++ vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
++ 0) *
++ -vc4_state->crtc_x);
++ vc4_state->crtc_w += vc4_state->crtc_x;
++ vc4_state->crtc_x = 0;
+ }
+
+- if (crtc_y < 0) {
+- offset += fb->pitches[0] * -crtc_y;
+- crtc_h += crtc_y;
+- crtc_y = 0;
++ if (vc4_state->crtc_y < 0) {
++ vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y;
++ vc4_state->crtc_h += vc4_state->crtc_y;
++ vc4_state->crtc_y = 0;
+ }
+
++ return 0;
++}
+
-+ cpu0: cpu@0 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a53";
-+ reg = <0>;
-+ };
+
-+ cpu1: cpu@1 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a53";
-+ reg = <1>;
-+ };
++/* Writes out a full display list for an active plane to the plane's
++ * private dlist state.
++ */
++static int vc4_plane_mode_set(struct drm_plane *plane,
++ struct drm_plane_state *state)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
++ struct drm_framebuffer *fb = state->fb;
++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
++ u32 ctl0_offset = vc4_state->dlist_count;
++ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
++ int ret;
+
-+ cpu2: cpu@2 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a53";
-+ reg = <2>;
-+ };
++ ret = vc4_plane_setup_clipping_and_scaling(state);
++ if (ret)
++ return ret;
+
-+ cpu3: cpu@3 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a53";
-+ reg = <3>;
-+ };
-+ };
-+};
+ vc4_dlist_write(vc4_state,
+ SCALER_CTL0_VALID |
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+@@ -199,8 +225,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ /* Position Word 0: Image Positions and Alpha Value */
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) |
+- VC4_SET_FIELD(crtc_x, SCALER_POS0_START_X) |
+- VC4_SET_FIELD(crtc_y, SCALER_POS0_START_Y));
++ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
++ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
+
+ /* Position Word 1: Scaled Image Dimensions.
+ * Skipped due to SCALER_CTL0_UNITY scaling.
+@@ -212,8 +238,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+ SCALER_POS2_ALPHA_MODE_FIXED,
+ SCALER_POS2_ALPHA_MODE) |
+- VC4_SET_FIELD(crtc_w, SCALER_POS2_WIDTH) |
+- VC4_SET_FIELD(crtc_h, SCALER_POS2_HEIGHT));
++ VC4_SET_FIELD(vc4_state->crtc_w, SCALER_POS2_WIDTH) |
++ VC4_SET_FIELD(vc4_state->crtc_h, SCALER_POS2_HEIGHT));
+
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+@@ -221,7 +247,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ vc4_state->pw0_offset = vc4_state->dlist_count;
+
+ /* Pointer Word 0: RGB / Y Pointer */
+- vc4_dlist_write(vc4_state, bo->paddr + offset);
++ vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset);
+
+ /* Pointer Context Word 0: Written by the HVS */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+--
+2.7.3
+
+From 696f1db279f08e58bc94172818209d5914e0e2d8 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 30 Dec 2015 11:50:22 -0800
+Subject: [PATCH 10/36] drm/vc4: Add a proper short-circut path for legacy
+ cursor updates.
+
+Previously, on every modeset we would allocate new display list
+memory, recompute changed planes, write all of them to the new memory,
+and pointed scanout at the new list (which will latch approximately at
+the next line of scanout). We let
+drm_atomic_helper_wait_for_vblanks() decide whether we needed to wait
+for a vblank after a modeset before cleaning up the old state and
+letting the next modeset proceed, and on legacy cursor updates we
+wouldn't wait. If you moved the cursor fast enough, we could
+potentially wrap around the display list memory area and overwrite the
+existing display list while it was still being scanned out, resulting
+in the HVS scanning out garbage or just halting.
+
+Instead of making cursor updates wait for scanout to move to the new
+display list area (which introduces significant cursor lag in X), we
+just rewrite our current display list.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 9 ++++
+ drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 96 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
+index f95f2df..4718ae5 100644
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -49,6 +49,15 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
++ /* Make sure that drm_atomic_helper_wait_for_vblanks()
++ * actually waits for vblank. If we're doing a full atomic
++ * modeset (as opposed to a vc4_update_plane() short circuit),
++ * then we need to wait for scanout to be done with our
++ * display lists before we free it and potentially reallocate
++ * and overwrite the dlist memory with a new modeset.
++ */
++ state->legacy_cursor_update = false;
+
-+/* Make the BCM2835-style global interrupt controller be a child of the
-+ * CPU-local interrupt controller.
-+ */
-+&intc {
-+ compatible = "brcm,bcm2836-armctrl-ic";
-+ reg = <0x7e00b200 0x200>;
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <8>;
-+};
-diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
-index 971e741..31cc2f2 100644
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -1,5 +1,7 @@
- #include <dt-bindings/pinctrl/bcm2835.h>
- #include <dt-bindings/clock/bcm2835.h>
-+#include <dt-bindings/clock/bcm2835-aux.h>
-+#include <dt-bindings/gpio/gpio.h>
- #include "skeleton.dtsi"
+ drm_atomic_helper_wait_for_vblanks(dev, state);
- /* This include file covers the common peripherals and configuration between
-@@ -111,7 +113,7 @@
- #interrupt-cells = <2>;
- };
+ drm_atomic_helper_cleanup_planes(dev, state);
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index 554ed54..713ec00 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -33,8 +33,12 @@ struct vc4_plane_state {
+ u32 dlist_size; /* Number of dwords allocated for the display list */
+ u32 dlist_count; /* Number of used dwords in the display list. */
-- uart0: uart@7e201000 {
-+ uart0: serial@7e201000 {
- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
- reg = <0x7e201000 0x1000>;
- interrupts = <2 25>;
-@@ -152,6 +154,18 @@
- status = "disabled";
- };
+- /* Offset in the dlist to pointer word 0. */
+- u32 pw0_offset;
++ /* Offset in the dlist to various words, for pageflip or
++ * cursor updates.
++ */
++ u32 pos0_offset;
++ u32 pos2_offset;
++ u32 ptr0_offset;
-+ pixelvalve@7e206000 {
-+ compatible = "brcm,bcm2835-pixelvalve0";
-+ reg = <0x7e206000 0x100>;
-+ interrupts = <2 13>; /* pwa0 */
-+ };
+ /* Offset where the plane's dlist was last stored in the
+ * hardware at vc4_crtc_atomic_flush() time.
+@@ -223,6 +227,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ SCALER_CTL0_UNITY);
+
+ /* Position Word 0: Image Positions and Alpha Value */
++ vc4_state->pos0_offset = vc4_state->dlist_count;
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) |
+ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
+@@ -233,6 +238,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ */
+
+ /* Position Word 2: Source Image Size, Alpha Mode */
++ vc4_state->pos2_offset = vc4_state->dlist_count;
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(format->has_alpha ?
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+@@ -244,9 +250,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
+- vc4_state->pw0_offset = vc4_state->dlist_count;
+-
+ /* Pointer Word 0: RGB / Y Pointer */
++ vc4_state->ptr0_offset = vc4_state->dlist_count;
+ vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset);
+
+ /* Pointer Context Word 0: Written by the HVS */
+@@ -332,13 +337,13 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
+ * scanout will start from this address as soon as the FIFO
+ * needs to refill with pixels.
+ */
+- writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
++ writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
+
+ /* Also update the CPU-side dlist copy, so that any later
+ * atomic updates that don't do a new modeset on our plane
+ * also use our updated address.
+ */
+- vc4_state->dlist[vc4_state->pw0_offset] = addr;
++ vc4_state->dlist[vc4_state->ptr0_offset] = addr;
+ }
+
+ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+@@ -354,8 +359,83 @@ static void vc4_plane_destroy(struct drm_plane *plane)
+ drm_plane_cleanup(plane);
+ }
+
++/* Implements immediate (non-vblank-synced) updates of the cursor
++ * position, or falls back to the atomic helper otherwise.
++ */
++static int
++vc4_update_plane(struct drm_plane *plane,
++ struct drm_crtc *crtc,
++ struct drm_framebuffer *fb,
++ int crtc_x, int crtc_y,
++ unsigned int crtc_w, unsigned int crtc_h,
++ uint32_t src_x, uint32_t src_y,
++ uint32_t src_w, uint32_t src_h)
++{
++ struct drm_plane_state *plane_state;
++ struct vc4_plane_state *vc4_state;
+
-+ pixelvalve@7e207000 {
-+ compatible = "brcm,bcm2835-pixelvalve1";
-+ reg = <0x7e207000 0x100>;
-+ interrupts = <2 14>; /* pwa1 */
-+ };
++ if (plane != crtc->cursor)
++ goto out;
+
- aux: aux@0x7e215000 {
- compatible = "brcm,bcm2835-aux";
- #clock-cells = <1>;
-@@ -159,6 +173,44 @@
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- };
-
-+ uart1: serial@7e215040 {
-+ compatible = "brcm,bcm2835-aux-uart";
-+ reg = <0x7e215040 0x40>;
-+ interrupts = <1 29>;
-+ clocks = <&aux BCM2835_AUX_CLOCK_UART>;
-+ status = "disabled";
-+ };
++ plane_state = plane->state;
++ vc4_state = to_vc4_plane_state(plane_state);
+
-+ spi1: spi@7e215080 {
-+ compatible = "brcm,bcm2835-aux-spi";
-+ reg = <0x7e215080 0x40>;
-+ interrupts = <1 29>;
-+ clocks = <&aux BCM2835_AUX_CLOCK_SPI1>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
++ if (!plane_state)
++ goto out;
+
-+ spi2: spi@7e2150c0 {
-+ compatible = "brcm,bcm2835-aux-spi";
-+ reg = <0x7e2150c0 0x40>;
-+ interrupts = <1 29>;
-+ clocks = <&aux BCM2835_AUX_CLOCK_SPI2>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
++ /* If we're changing the cursor contents, do that in the
++ * normal vblank-synced atomic path.
++ */
++ if (fb != plane_state->fb)
++ goto out;
+
-+ pwm: pwm@7e20c000 {
-+ compatible = "brcm,bcm2835-pwm";
-+ reg = <0x7e20c000 0x28>;
-+ clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clock-rates = <10000000>;
-+ #pwm-cells = <2>;
-+ status = "disabled";
-+ };
++ /* No configuring new scaling in the fast path. */
++ if (crtc_w != plane_state->crtc_w ||
++ crtc_h != plane_state->crtc_h ||
++ src_w != plane_state->src_w ||
++ src_h != plane_state->src_h) {
++ goto out;
++ }
+
- sdhci: sdhci@7e300000 {
- compatible = "brcm,bcm2835-sdhci";
- reg = <0x7e300000 0x100>;
-@@ -167,6 +219,12 @@
- status = "disabled";
- };
-
-+ hvs@7e400000 {
-+ compatible = "brcm,bcm2835-hvs";
-+ reg = <0x7e400000 0x6000>;
-+ interrupts = <2 1>;
-+ };
++ /* Set the cursor's position on the screen. This is the
++ * expected change from the drm_mode_cursor_universal()
++ * helper.
++ */
++ plane_state->crtc_x = crtc_x;
++ plane_state->crtc_y = crtc_y;
+
- i2c1: i2c@7e804000 {
- compatible = "brcm,bcm2835-i2c";
- reg = <0x7e804000 0x1000>;
-@@ -187,11 +245,39 @@
- status = "disabled";
- };
-
-- usb@7e980000 {
-+ pixelvalve@7e807000 {
-+ compatible = "brcm,bcm2835-pixelvalve2";
-+ reg = <0x7e807000 0x100>;
-+ interrupts = <2 10>; /* pixelvalve */
-+ };
++ /* Allow changing the start position within the cursor BO, if
++ * that matters.
++ */
++ plane_state->src_x = src_x;
++ plane_state->src_y = src_y;
+
-+ hdmi: hdmi@7e902000 {
-+ compatible = "brcm,bcm2835-hdmi";
-+ reg = <0x7e902000 0x600>,
-+ <0x7e808000 0x100>;
-+ interrupts = <2 8>, <2 9>;
-+ ddc = <&i2c2>;
-+ clocks = <&clocks BCM2835_PLLH_PIX>,
-+ <&clocks BCM2835_CLOCK_HSM>;
-+ clock-names = "pixel", "hdmi";
-+ status = "disabled";
-+ };
++ /* Update the display list based on the new crtc_x/y. */
++ vc4_plane_atomic_check(plane, plane_state);
+
-+ usb: usb@7e980000 {
- compatible = "brcm,bcm2835-usb";
- reg = <0x7e980000 0x10000>;
- interrupts = <1 9>;
- };
++ /* Note that we can't just call vc4_plane_write_dlist()
++ * because that would smash the context data that the HVS is
++ * currently using.
++ */
++ writel(vc4_state->dlist[vc4_state->pos0_offset],
++ &vc4_state->hw_dlist[vc4_state->pos0_offset]);
++ writel(vc4_state->dlist[vc4_state->pos2_offset],
++ &vc4_state->hw_dlist[vc4_state->pos2_offset]);
++ writel(vc4_state->dlist[vc4_state->ptr0_offset],
++ &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
+
-+ v3d: v3d@7ec00000 {
-+ compatible = "brcm,bcm2835-v3d";
-+ reg = <0x7ec00000 0x1000>;
-+ interrupts = <1 10>;
-+ };
++ return 0;
+
-+ vc4: gpu {
-+ compatible = "brcm,bcm2835-vc4";
-+ };
- };
-
- clocks {
-diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
-index 015e687..9f4df8f 100644
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1107,13 +1107,15 @@ static int bcm2835_pll_divider_set_rate(struct clk_hw *hw,
- struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
- struct bcm2835_cprman *cprman = divider->cprman;
- const struct bcm2835_pll_divider_data *data = divider->data;
-- u32 cm;
-- int ret;
-+ u32 cm, div, max_div = 1 << A2W_PLL_DIV_BITS;
-
-- ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
-- if (ret)
-- return ret;
-+ div = DIV_ROUND_UP_ULL(parent_rate, rate);
++out:
++ return drm_atomic_helper_update_plane(plane, crtc, fb,
++ crtc_x, crtc_y,
++ crtc_w, crtc_h,
++ src_x, src_y,
++ src_w, src_h);
++}
+
-+ div = min(div, max_div);
-+ if (div == max_div)
-+ div = 0;
-
-+ cprman_write(cprman, data->a2w_reg, div);
- cm = cprman_read(cprman, data->cm_reg);
- cprman_write(cprman, data->cm_reg, cm | data->load_mask);
- cprman_write(cprman, data->cm_reg, cm & ~data->load_mask);
-diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
-index 22278bc..ac8eafe 100644
---- a/drivers/gpu/drm/vc4/vc4_bo.c
-+++ b/drivers/gpu/drm/vc4/vc4_bo.c
-@@ -499,11 +499,12 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
- if (IS_ERR(bo))
- return PTR_ERR(bo);
-
-- ret = copy_from_user(bo->base.vaddr,
-+ if (copy_from_user(bo->base.vaddr,
- (void __user *)(uintptr_t)args->data,
-- args->size);
-- if (ret != 0)
-+ args->size)) {
-+ ret = -EFAULT;
- goto fail;
-+ }
- /* Clear the rest of the memory from allocating from the BO
- * cache.
- */
+ static const struct drm_plane_funcs vc4_plane_funcs = {
+- .update_plane = drm_atomic_helper_update_plane,
++ .update_plane = vc4_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = vc4_plane_destroy,
+ .set_property = NULL,
+--
+2.7.3
+
+From cd30019db690e3a92fe5d7d771352f118a105f82 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 13:25:41 -0800
+Subject: [PATCH 11/36] drm/vc4: Make the CRTCs cooperate on allocating display
+ lists.
+
+So far, we've only ever lit up one CRTC, so this has been fine. To
+extend to more displays or more planes, we need to make sure we don't
+run our display lists into each other.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 115 +++++++++++++++++++++++------------------
+ drivers/gpu/drm/vc4/vc4_drv.h | 8 ++-
+ drivers/gpu/drm/vc4/vc4_hvs.c | 13 +++++
+ 3 files changed, 84 insertions(+), 52 deletions(-)
+
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
-index 018145e..9032c06 100644
+index 6ae5abc..9032c06 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -49,22 +49,27 @@ struct vc4_crtc {
@@ -555,53 +758,7 @@ index 018145e..9032c06 100644
struct vc4_crtc_data {
/* Which channel of the HVS this pixelvalve sources from. */
int hvs_channel;
-@@ -83,7 +88,7 @@ static const struct {
- } crtc_regs[] = {
- CRTC_REG(PV_CONTROL),
- CRTC_REG(PV_V_CONTROL),
-- CRTC_REG(PV_VSYNCD),
-+ CRTC_REG(PV_VSYNCD_EVEN),
- CRTC_REG(PV_HORZA),
- CRTC_REG(PV_HORZB),
- CRTC_REG(PV_VERTA),
-@@ -183,6 +188,8 @@ static int vc4_get_clock_select(struct drm_crtc *crtc)
-
- static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
- {
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- struct drm_crtc_state *state = crtc->state;
- struct drm_display_mode *mode = &state->adjusted_mode;
-@@ -212,6 +219,16 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
- PV_HORZB_HFP) |
- VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
-
-+ CRTC_WRITE(PV_VERTA,
-+ VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
-+ PV_VERTA_VBP) |
-+ VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
-+ PV_VERTA_VSYNC));
-+ CRTC_WRITE(PV_VERTB,
-+ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
-+ PV_VERTB_VFP) |
-+ VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
-+
- if (interlace) {
- CRTC_WRITE(PV_VERTA_EVEN,
- VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1,
-@@ -241,6 +258,10 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
- PV_CONTROL_FIFO_CLR |
- PV_CONTROL_EN);
-
-+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
-+ SCALER_DISPBKGND_AUTOHS |
-+ (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
-+
- if (debug_dump_regs) {
- DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc));
- vc4_crtc_dump_regs(vc4_crtc);
-@@ -319,11 +340,13 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
+@@ -335,11 +340,13 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -616,7 +773,7 @@ index 018145e..9032c06 100644
/* The pixelvalve can only feed one encoder (and encoders are
* 1:1 with connectors.)
-@@ -346,18 +369,12 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+@@ -362,18 +369,12 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
dlist_count++; /* Account for SCALER_CTL0_END. */
@@ -641,7 +798,7 @@ index 018145e..9032c06 100644
return 0;
}
-@@ -368,47 +385,29 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
+@@ -384,47 +385,29 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
@@ -700,15 +857,7 @@ index 018145e..9032c06 100644
if (debug_dump_regs) {
DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
-@@ -544,6 +543,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc,
- /* Make sure all other async modesetes have landed. */
- ret = down_interruptible(&vc4->async_modeset);
- if (ret) {
-+ drm_framebuffer_unreference(fb);
- kfree(flip_state);
- return ret;
- }
-@@ -573,6 +573,36 @@ static int vc4_page_flip(struct drm_crtc *crtc,
+@@ -590,6 +573,36 @@ static int vc4_page_flip(struct drm_crtc *crtc,
return drm_atomic_helper_page_flip(crtc, fb, event, flags);
}
@@ -745,7 +894,7 @@ index 018145e..9032c06 100644
static const struct drm_crtc_funcs vc4_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.destroy = vc4_crtc_destroy,
-@@ -581,8 +611,8 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
+@@ -598,8 +611,8 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
.cursor_set = NULL, /* handled by drm_mode_cursor_universal */
.cursor_move = NULL, /* handled by drm_mode_cursor_universal */
.reset = drm_atomic_helper_crtc_reset,
@@ -757,10 +906,10 @@ index 018145e..9032c06 100644
static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
-index 51a6333..83db0b7 100644
+index 51a6333..38a31c7 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -154,7 +154,17 @@ struct vc4_v3d {
+@@ -154,7 +154,13 @@ struct vc4_v3d {
struct vc4_hvs {
struct platform_device *pdev;
void __iomem *regs;
@@ -771,106 +920,160 @@ index 51a6333..83db0b7 100644
+ * list. Units are dwords.
+ */
+ struct drm_mm dlist_mm;
-+ /* Memory manager for the LBM memory used by HVS scaling. */
-+ struct drm_mm lbm_mm;
+ spinlock_t mm_lock;
-+
-+ struct drm_mm_node mitchell_netravali_filter;
};
struct vc4_plane {
-diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
-index c69c046..d8b8649 100644
---- a/drivers/gpu/drm/vc4/vc4_hdmi.c
-+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
-@@ -47,6 +47,7 @@ struct vc4_hdmi {
- void __iomem *hdmicore_regs;
- void __iomem *hd_regs;
- int hpd_gpio;
-+ bool hpd_active_low;
-
- struct clk *pixel_clock;
- struct clk *hsm_clock;
-@@ -95,6 +96,7 @@ static const struct {
- HDMI_REG(VC4_HDMI_SW_RESET_CONTROL),
- HDMI_REG(VC4_HDMI_HOTPLUG_INT),
- HDMI_REG(VC4_HDMI_HOTPLUG),
-+ HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG),
- HDMI_REG(VC4_HDMI_HORZA),
- HDMI_REG(VC4_HDMI_HORZB),
- HDMI_REG(VC4_HDMI_FIFO_CTL),
-@@ -165,7 +167,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
- struct vc4_dev *vc4 = to_vc4_dev(dev);
+diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
+index 8098c5b..9e43554 100644
+--- a/drivers/gpu/drm/vc4/vc4_hvs.c
++++ b/drivers/gpu/drm/vc4/vc4_hvs.c
+@@ -119,6 +119,17 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
- if (vc4->hdmi->hpd_gpio) {
-- if (gpio_get_value(vc4->hdmi->hpd_gpio))
-+ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
-+ vc4->hdmi->hpd_active_low)
- return connector_status_connected;
- else
- return connector_status_disconnected;
-@@ -495,6 +498,16 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
- goto err_put_i2c;
- }
+ hvs->dlist = hvs->regs + SCALER_DLIST_START;
-+ /* This is the rate that is set by the firmware. The number
-+ * needs to be a bit higher than the pixel clock rate
-+ * (generally 148.5Mhz).
-+ */
-+ ret = clk_set_rate(hdmi->hsm_clock, 163682864);
-+ if (ret) {
-+ DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
-+ goto err_unprepare_pix;
-+ }
++ spin_lock_init(&hvs->mm_lock);
+
- ret = clk_prepare_enable(hdmi->hsm_clock);
- if (ret) {
- DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n",
-@@ -506,17 +519,40 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
- * we'll use the HDMI core's register.
- */
- if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
-- hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0);
-+ enum of_gpio_flags hpd_gpio_flags;
++ /* Set up the HVS display list memory manager. We never
++ * overwrite the setup from the bootloader (just 128b out of
++ * our 16K), since we don't want to scramble the screen when
++ * transitioning from the firmware's boot setup to runtime.
++ */
++ drm_mm_init(&hvs->dlist_mm,
++ HVS_BOOTLOADER_DLIST_END,
++ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
+
-+ hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
-+ "hpd-gpios", 0,
-+ &hpd_gpio_flags);
- if (hdmi->hpd_gpio < 0) {
- ret = hdmi->hpd_gpio;
- goto err_unprepare_hsm;
- }
+ vc4->hvs = hvs;
+ return 0;
+ }
+@@ -129,6 +140,8 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = drm->dev_private;
+
++ drm_mm_takedown(&vc4->hvs->dlist_mm);
+
-+ hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
- }
+ vc4->hvs = NULL;
+ }
- vc4->hdmi = hdmi;
+--
+2.7.3
+
+From 7934fe9bdbbe2ffb4bcfe656a22a8f9f4e3d266a Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:45:25 -0800
+Subject: [PATCH 12/36] drm/vc4: Fix which value is being used for source image
+ size.
+
+This doesn't matter yet since we only allow 1:1 scaling, but the
+comment clearly says we should be using the source size.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index 713ec00..d9c9290 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -47,6 +47,8 @@ struct vc4_plane_state {
- /* HDMI core must be enabled. */
-- WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0);
-+ if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) {
-+ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST);
-+ udelay(1);
-+ HD_WRITE(VC4_HD_M_CTL, 0);
-+
-+ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE);
+ /* Clipped coordinates of the plane on the display. */
+ int crtc_x, crtc_y, crtc_w, crtc_h;
++ /* Clipped size of the area scanned from in the FB. */
++ u32 src_w, src_h;
+
+ /* Offset to start scanning out from the start of the plane's
+ * BO.
+@@ -170,11 +172,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+
+ vc4_state->offset = fb->offsets[0];
+
+- vc4_state->crtc_x = state->crtc_x;
+- vc4_state->crtc_y = state->crtc_y;
+- vc4_state->crtc_w = state->crtc_w;
+- vc4_state->crtc_h = state->crtc_h;
+-
+ if (state->crtc_w << 16 != state->src_w ||
+ state->crtc_h << 16 != state->src_h) {
+ /* We don't support scaling yet, which involves
+@@ -185,17 +182,25 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ return -EINVAL;
+ }
+
++ vc4_state->src_w = state->src_w >> 16;
++ vc4_state->src_h = state->src_h >> 16;
+
-+ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL,
-+ VC4_HDMI_SW_RESET_HDMI |
-+ VC4_HDMI_SW_RESET_FORMAT_DETECT);
++ vc4_state->crtc_x = state->crtc_x;
++ vc4_state->crtc_y = state->crtc_y;
++ vc4_state->crtc_w = state->crtc_w;
++ vc4_state->crtc_h = state->crtc_h;
+
-+ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0);
+ if (vc4_state->crtc_x < 0) {
+ vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
+ 0) *
+ -vc4_state->crtc_x);
+- vc4_state->crtc_w += vc4_state->crtc_x;
++ vc4_state->src_w += vc4_state->crtc_x;
+ vc4_state->crtc_x = 0;
+ }
+
+ if (vc4_state->crtc_y < 0) {
+ vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y;
+- vc4_state->crtc_h += vc4_state->crtc_y;
++ vc4_state->src_h += vc4_state->crtc_y;
+ vc4_state->crtc_y = 0;
+ }
+
+@@ -244,8 +249,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+ SCALER_POS2_ALPHA_MODE_FIXED,
+ SCALER_POS2_ALPHA_MODE) |
+- VC4_SET_FIELD(vc4_state->crtc_w, SCALER_POS2_WIDTH) |
+- VC4_SET_FIELD(vc4_state->crtc_h, SCALER_POS2_HEIGHT));
++ VC4_SET_FIELD(vc4_state->src_w, SCALER_POS2_WIDTH) |
++ VC4_SET_FIELD(vc4_state->src_h, SCALER_POS2_HEIGHT));
+
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+--
+2.7.3
+
+From e710e8e1d13c85a635c09168df6d008955ac5a4e Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 20 Oct 2015 16:06:57 +0100
+Subject: [PATCH 13/36] drm/vc4: Add support for scaling of display planes.
+
+This implements a simple policy for choosing scaling modes
+(trapezoidal for decimation, PPF for magnification), and a single PPF
+filter (Mitchell/Netravali's recommendation).
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 4 +
+ drivers/gpu/drm/vc4/vc4_hvs.c | 84 +++++++++++++
+ drivers/gpu/drm/vc4/vc4_plane.c | 253 +++++++++++++++++++++++++++++++++++++---
+ drivers/gpu/drm/vc4/vc4_regs.h | 46 ++++++++
+ 4 files changed, 374 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
+index 38a31c7..83db0b7 100644
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -160,7 +160,11 @@ struct vc4_hvs {
+ * list. Units are dwords.
+ */
+ struct drm_mm dlist_mm;
++ /* Memory manager for the LBM memory used by HVS scaling. */
++ struct drm_mm lbm_mm;
+ spinlock_t mm_lock;
+
-+ /* PHY should be in reset, like
-+ * vc4_hdmi_encoder_disable() does.
-+ */
-+ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
-+ }
++ struct drm_mm_node mitchell_netravali_filter;
+ };
- drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS, NULL);
+ struct vc4_plane {
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
-index 8098c5b..6fbab1c 100644
+index 9e43554..6fbab1c 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -100,12 +100,76 @@ int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused)
@@ -950,21 +1153,10 @@ index 8098c5b..6fbab1c 100644
hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
if (!hvs)
-@@ -119,6 +183,33 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
-
- hvs->dlist = hvs->regs + SCALER_DLIST_START;
+@@ -130,6 +194,22 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
+ HVS_BOOTLOADER_DLIST_END,
+ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
-+ spin_lock_init(&hvs->mm_lock);
-+
-+ /* Set up the HVS display list memory manager. We never
-+ * overwrite the setup from the bootloader (just 128b out of
-+ * our 16K), since we don't want to scramble the screen when
-+ * transitioning from the firmware's boot setup to runtime.
-+ */
-+ drm_mm_init(&hvs->dlist_mm,
-+ HVS_BOOTLOADER_DLIST_END,
-+ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
-+
+ /* Set up the HVS LBM memory manager. We could have some more
+ * complicated data structure that allowed reuse of LBM areas
+ * between planes when they don't overlap on the screen, but
@@ -984,44 +1176,23 @@ index 8098c5b..6fbab1c 100644
vc4->hvs = hvs;
return 0;
}
-@@ -129,6 +220,12 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
+@@ -140,7 +220,11 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
struct drm_device *drm = dev_get_drvdata(master);
struct vc4_dev *vc4 = drm->dev_private;
+ if (vc4->hvs->mitchell_netravali_filter.allocated)
+ drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
+
-+ drm_mm_takedown(&vc4->hvs->dlist_mm);
+ drm_mm_takedown(&vc4->hvs->dlist_mm);
+ drm_mm_takedown(&vc4->hvs->lbm_mm);
-+
+
vc4->hvs = NULL;
}
-
-diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
-index f95f2df..4718ae5 100644
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -49,6 +49,15 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
-
- drm_atomic_helper_commit_modeset_enables(dev, state);
-
-+ /* Make sure that drm_atomic_helper_wait_for_vblanks()
-+ * actually waits for vblank. If we're doing a full atomic
-+ * modeset (as opposed to a vc4_update_plane() short circuit),
-+ * then we need to wait for scanout to be done with our
-+ * display lists before we free it and potentially reallocate
-+ * and overwrite the dlist memory with a new modeset.
-+ */
-+ state->legacy_cursor_update = false;
-+
- drm_atomic_helper_wait_for_vblanks(dev, state);
-
- drm_atomic_helper_cleanup_planes(dev, state);
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
-index 0addbad..7b0c72a 100644
+index d9c9290..7c2d697 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -24,19 +24,52 @@
+@@ -24,6 +24,12 @@
#include "drm_fb_cma_helper.h"
#include "drm_plane_helper.h"
@@ -1033,111 +1204,30 @@ index 0addbad..7b0c72a 100644
+
struct vc4_plane_state {
struct drm_plane_state base;
-+ /* System memory copy of the display list for this element, computed
-+ * at atomic_check time.
-+ */
- u32 *dlist;
-- u32 dlist_size; /* Number of dwords in allocated for the display list */
-+ u32 dlist_size; /* Number of dwords allocated for the display list */
- u32 dlist_count; /* Number of used dwords in the display list. */
+ /* System memory copy of the display list for this element, computed
+@@ -47,13 +53,19 @@ struct vc4_plane_state {
-- /* Offset in the dlist to pointer word 0. */
-- u32 pw0_offset;
-+ /* Offset in the dlist to various words, for pageflip or
-+ * cursor updates.
-+ */
-+ u32 pos0_offset;
-+ u32 pos2_offset;
-+ u32 ptr0_offset;
-
- /* Offset where the plane's dlist was last stored in the
-- hardware at vc4_crtc_atomic_flush() time.
-- */
-- u32 *hw_dlist;
-+ * hardware at vc4_crtc_atomic_flush() time.
-+ */
-+ u32 __iomem *hw_dlist;
-+
-+ /* Clipped coordinates of the plane on the display. */
-+ int crtc_x, crtc_y, crtc_w, crtc_h;
+ /* Clipped coordinates of the plane on the display. */
+ int crtc_x, crtc_y, crtc_w, crtc_h;
+- /* Clipped size of the area scanned from in the FB. */
+- u32 src_w, src_h;
+ /* Clipped area being scanned from in the FB. */
-+ u32 src_x, src_y;
-+
-+ u32 src_w[2], src_h[2];
++ u32 src_x, src_y, src_w, src_h;
+
-+ /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
-+ enum vc4_scaling_mode x_scaling[2], y_scaling[2];
++ enum vc4_scaling_mode x_scaling, y_scaling;
+ bool is_unity;
-+ bool is_yuv;
-+
-+ /* Offset to start scanning out from the start of the plane's
-+ * BO.
-+ */
-+ u32 offsets[3];
+
+ /* Offset to start scanning out from the start of the plane's
+ * BO.
+ */
+ u32 offset;
+
+ /* Our allocation in LBM for temporary storage during scaling. */
+ struct drm_mm_node lbm;
};
static inline struct vc4_plane_state *
-@@ -50,6 +83,7 @@ static const struct hvs_format {
- u32 hvs; /* HVS_FORMAT_* */
- u32 pixel_order;
- bool has_alpha;
-+ bool flip_cbcr;
- } hvs_formats[] = {
- {
- .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
-@@ -59,6 +93,48 @@ static const struct hvs_format {
- .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
- .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
- },
-+ {
-+ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
-+ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
-+ },
-+ {
-+ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
-+ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
-+ },
-+ {
-+ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
-+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
-+ },
-+ {
-+ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
-+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YUV422,
-+ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YVU422,
-+ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
-+ .flip_cbcr = true,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YUV420,
-+ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YVU420,
-+ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
-+ .flip_cbcr = true,
-+ },
-+ {
-+ .drm = DRM_FORMAT_NV12,
-+ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
-+ },
-+ {
-+ .drm = DRM_FORMAT_NV16,
-+ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
-+ },
- };
-
- static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
-@@ -73,6 +149,16 @@ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
+@@ -90,6 +102,16 @@ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
return NULL;
}
@@ -1154,7 +1244,7 @@ index 0addbad..7b0c72a 100644
static bool plane_enabled(struct drm_plane_state *state)
{
return state->fb && state->crtc;
-@@ -89,6 +175,8 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
+@@ -106,6 +128,8 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
if (!vc4_state)
return NULL;
@@ -1163,7 +1253,7 @@ index 0addbad..7b0c72a 100644
__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
if (vc4_state->dlist) {
-@@ -108,8 +196,17 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
+@@ -125,8 +149,17 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
static void vc4_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
@@ -1181,7 +1271,7 @@ index 0addbad..7b0c72a 100644
kfree(vc4_state->dlist);
__drm_atomic_helper_plane_destroy_state(plane, &vc4_state->base);
kfree(state);
-@@ -148,84 +245,400 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
+@@ -165,23 +198,60 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
vc4_state->dlist[vc4_state->dlist_count++] = val;
}
@@ -1190,11 +1280,11 @@ index 0addbad..7b0c72a 100644
+ *
+ * This is a replication of a table from the spec.
+ */
-+static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
++static u32 vc4_get_scl_field(struct drm_plane_state *state)
+{
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
-+ switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
++ switch (vc4_state->x_scaling << 2 | vc4_state->y_scaling) {
+ case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
+ return SCALER_CTL0_SCL_H_PPF_V_PPF;
+ case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
@@ -1220,74 +1310,45 @@ index 0addbad..7b0c72a 100644
+ }
+}
+
-+static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
-+{
+ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ {
+ struct drm_plane *plane = state->plane;
-+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
-+ struct drm_framebuffer *fb = state->fb;
-+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+ u32 subpixel_src_mask = (1 << 16) - 1;
-+ u32 format = fb->pixel_format;
-+ int num_planes = drm_format_num_planes(format);
-+ u32 h_subsample = 1;
-+ u32 v_subsample = 1;
-+ int i;
-+
-+ for (i = 0; i < num_planes; i++)
-+ vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
-+
+
+ vc4_state->offset = fb->offsets[0];
+
+- if (state->crtc_w << 16 != state->src_w ||
+- state->crtc_h << 16 != state->src_h) {
+- /* We don't support scaling yet, which involves
+- * allocating the LBM memory for scaling temporary
+- * storage, and putting filter kernels in the HVS
+- * context.
+- */
+ /* We don't support subpixel source positioning for scaling. */
+ if ((state->src_x & subpixel_src_mask) ||
+ (state->src_y & subpixel_src_mask) ||
+ (state->src_w & subpixel_src_mask) ||
+ (state->src_h & subpixel_src_mask)) {
-+ return -EINVAL;
-+ }
-+
+ return -EINVAL;
+ }
+
+ vc4_state->src_x = state->src_x >> 16;
+ vc4_state->src_y = state->src_y >> 16;
-+ vc4_state->src_w[0] = state->src_w >> 16;
-+ vc4_state->src_h[0] = state->src_h >> 16;
-+
-+ vc4_state->crtc_x = state->crtc_x;
-+ vc4_state->crtc_y = state->crtc_y;
-+ vc4_state->crtc_w = state->crtc_w;
-+ vc4_state->crtc_h = state->crtc_h;
-+
-+ vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
-+ vc4_state->crtc_w);
-+ vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
-+ vc4_state->crtc_h);
-+
-+ if (num_planes > 1) {
-+ vc4_state->is_yuv = true;
-+
-+ h_subsample = drm_format_horz_chroma_subsampling(format);
-+ v_subsample = drm_format_vert_chroma_subsampling(format);
-+ vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
-+ vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
-+
-+ vc4_state->x_scaling[1] =
-+ vc4_get_scaling_mode(vc4_state->src_w[1],
-+ vc4_state->crtc_w);
-+ vc4_state->y_scaling[1] =
-+ vc4_get_scaling_mode(vc4_state->src_h[1],
-+ vc4_state->crtc_h);
-+
-+ /* YUV conversion requires that scaling be enabled,
-+ * even on a plane that's otherwise 1:1. Choose TPZ
-+ * for simplicity.
-+ */
-+ if (vc4_state->x_scaling[0] == VC4_SCALING_NONE)
-+ vc4_state->x_scaling[0] = VC4_SCALING_TPZ;
-+ if (vc4_state->y_scaling[0] == VC4_SCALING_NONE)
-+ vc4_state->y_scaling[0] = VC4_SCALING_TPZ;
-+ }
-+
-+ vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
-+ vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
-+ vc4_state->x_scaling[1] == VC4_SCALING_NONE &&
-+ vc4_state->y_scaling[1] == VC4_SCALING_NONE);
+ vc4_state->src_w = state->src_w >> 16;
+ vc4_state->src_h = state->src_h >> 16;
+
+@@ -190,6 +260,23 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ vc4_state->crtc_w = state->crtc_w;
+ vc4_state->crtc_h = state->crtc_h;
+
++ vc4_state->x_scaling = vc4_get_scaling_mode(vc4_state->src_w,
++ vc4_state->crtc_w);
++ vc4_state->y_scaling = vc4_get_scaling_mode(vc4_state->src_h,
++ vc4_state->crtc_h);
++ vc4_state->is_unity = (vc4_state->x_scaling == VC4_SCALING_NONE &&
++ vc4_state->y_scaling == VC4_SCALING_NONE);
+
+ /* No configuring scaling on the cursor plane, since it gets
+ non-vblank-synced updates, and scaling requires requires
@@ -1299,34 +1360,13 @@ index 0addbad..7b0c72a 100644
+ /* Clamp the on-screen start x/y to 0. The hardware doesn't
+ * support negative y, and negative x wastes bandwidth.
+ */
-+ if (vc4_state->crtc_x < 0) {
-+ for (i = 0; i < num_planes; i++) {
-+ u32 cpp = drm_format_plane_cpp(fb->pixel_format, i);
-+ u32 subs = ((i == 0) ? 1 : h_subsample);
-+
-+ vc4_state->offsets[i] += (cpp *
-+ (-vc4_state->crtc_x) / subs);
-+ }
-+ vc4_state->src_w[0] += vc4_state->crtc_x;
-+ vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
-+ vc4_state->crtc_x = 0;
-+ }
-+
-+ if (vc4_state->crtc_y < 0) {
-+ for (i = 0; i < num_planes; i++) {
-+ u32 subs = ((i == 0) ? 1 : v_subsample);
-+
-+ vc4_state->offsets[i] += (fb->pitches[i] *
-+ (-vc4_state->crtc_y) / subs);
-+ }
-+ vc4_state->src_h[0] += vc4_state->crtc_y;
-+ vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
-+ vc4_state->crtc_y = 0;
-+ }
-+
-+ return 0;
-+}
-+
+ if (vc4_state->crtc_x < 0) {
+ vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
+ 0) *
+@@ -207,6 +294,87 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ return 0;
+ }
+
+static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
+{
+ u32 scale, recip;
@@ -1361,23 +1401,15 @@ index 0addbad..7b0c72a 100644
+ /* This is the worst case number. One of the two sizes will
+ * be used depending on the scaling configuration.
+ */
-+ u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
++ u32 pix_per_line = max(vc4_state->src_w, (u32)vc4_state->crtc_w);
+ u32 lbm;
+
-+ if (!vc4_state->is_yuv) {
-+ if (vc4_state->is_unity)
-+ return 0;
-+ else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
-+ lbm = pix_per_line * 8;
-+ else {
-+ /* In special cases, this multiplier might be 12. */
-+ lbm = pix_per_line * 16;
-+ }
-+ } else {
-+ /* There are cases for this going down to a multiplier
-+ * of 2, but according to the firmware source, the
-+ * table in the docs is somewhat wrong.
-+ */
++ if (vc4_state->is_unity)
++ return 0;
++ else if (vc4_state->y_scaling == VC4_SCALING_TPZ)
++ lbm = pix_per_line * 8;
++ else {
++ /* In special cases, this multiplier might be 12. */
+ lbm = pix_per_line * 16;
+ }
+
@@ -1386,74 +1418,58 @@ index 0addbad..7b0c72a 100644
+ return lbm;
+}
+
-+static void vc4_write_scaling_parameters(struct drm_plane_state *state,
-+ int channel)
++static void vc4_write_scaling_parameters(struct drm_plane_state *state)
+{
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
+ /* Ch0 H-PPF Word 0: Scaling Parameters */
-+ if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
++ if (vc4_state->x_scaling == VC4_SCALING_PPF) {
+ vc4_write_ppf(vc4_state,
-+ vc4_state->src_w[channel], vc4_state->crtc_w);
++ vc4_state->src_w, vc4_state->crtc_w);
+ }
+
+ /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
-+ if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
++ if (vc4_state->y_scaling == VC4_SCALING_PPF) {
+ vc4_write_ppf(vc4_state,
-+ vc4_state->src_h[channel], vc4_state->crtc_h);
++ vc4_state->src_h, vc4_state->crtc_h);
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ }
+
+ /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
-+ if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
++ if (vc4_state->x_scaling == VC4_SCALING_TPZ) {
+ vc4_write_tpz(vc4_state,
-+ vc4_state->src_w[channel], vc4_state->crtc_w);
++ vc4_state->src_w, vc4_state->crtc_w);
+ }
+
+ /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
-+ if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
++ if (vc4_state->y_scaling == VC4_SCALING_TPZ) {
+ vc4_write_tpz(vc4_state,
-+ vc4_state->src_h[channel], vc4_state->crtc_h);
++ vc4_state->src_h, vc4_state->crtc_h);
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ }
+}
-+
+
/* Writes out a full display list for an active plane to the plane's
* private dlist state.
- */
+@@ -214,22 +382,50 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
static int vc4_plane_mode_set(struct drm_plane *plane,
struct drm_plane_state *state)
{
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
struct drm_framebuffer *fb = state->fb;
-- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
u32 ctl0_offset = vc4_state->dlist_count;
const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
-- uint32_t offset = fb->offsets[0];
-- int crtc_x = state->crtc_x;
-- int crtc_y = state->crtc_y;
-- int crtc_w = state->crtc_w;
-- int crtc_h = state->crtc_h;
--
-- if (state->crtc_w << 16 != state->src_w ||
-- state->crtc_h << 16 != state->src_h) {
-- /* We don't support scaling yet, which involves
-- * allocating the LBM memory for scaling temporary
-- * storage, and putting filter kernels in the HVS
-- * context.
-- */
-- return -EINVAL;
-+ int num_planes = drm_format_num_planes(format->drm);
-+ u32 scl0, scl1;
++ u32 scl;
+ u32 lbm_size;
+ unsigned long irqflags;
-+ int ret, i;
-+
-+ ret = vc4_plane_setup_clipping_and_scaling(state);
-+ if (ret)
-+ return ret;
-+
+ int ret;
+
+ ret = vc4_plane_setup_clipping_and_scaling(state);
+ if (ret)
+ return ret;
+
+ /* Allocate the LBM memory that the HVS will use for temporary
+ * storage due to our scaling/format conversion.
+ */
@@ -1468,34 +1484,13 @@ index 0addbad..7b0c72a 100644
+ } else {
+ WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
+ }
- }
-
-- if (crtc_x < 0) {
-- offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x;
-- crtc_w += crtc_x;
-- crtc_x = 0;
-- }
++ }
++
+ if (ret)
+ return ret;
-
-- if (crtc_y < 0) {
-- offset += fb->pitches[0] * -crtc_y;
-- crtc_h += crtc_y;
-- crtc_y = 0;
-+ /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
-+ * and 4:4:4, scl1 should be set to scl0 so both channels of
-+ * the scaler do the same thing. For YUV, the Y plane needs
-+ * to be put in channel 1 and Cb/Cr in channel 0, so we swap
-+ * the scl fields here.
-+ */
-+ if (num_planes == 1) {
-+ scl0 = vc4_get_scl_field(state, 1);
-+ scl1 = scl0;
-+ } else {
-+ scl0 = vc4_get_scl_field(state, 1);
-+ scl1 = vc4_get_scl_field(state, 0);
- }
-
++
++ scl = vc4_get_scl_field(state);
++
+ /* Control word */
vc4_dlist_write(vc4_state,
SCALER_CTL0_VALID |
@@ -1503,22 +1498,18 @@ index 0addbad..7b0c72a 100644
(format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
- SCALER_CTL0_UNITY);
+ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
-+ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
-+ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
++ VC4_SET_FIELD(scl, SCALER_CTL0_SCL0) |
++ VC4_SET_FIELD(scl, SCALER_CTL0_SCL1));
/* Position Word 0: Image Positions and Alpha Value */
-+ vc4_state->pos0_offset = vc4_state->dlist_count;
- vc4_dlist_write(vc4_state,
- VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) |
-- VC4_SET_FIELD(crtc_x, SCALER_POS0_START_X) |
-- VC4_SET_FIELD(crtc_y, SCALER_POS0_START_Y));
--
+ vc4_state->pos0_offset = vc4_state->dlist_count;
+@@ -238,9 +434,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
+ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
+
- /* Position Word 1: Scaled Image Dimensions.
- * Skipped due to SCALER_CTL0_UNITY scaling.
- */
-+ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
-+ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
-+
+ /* Position Word 1: Scaled Image Dimensions. */
+ if (!vc4_state->is_unity) {
+ vc4_dlist_write(vc4_state,
@@ -1529,29 +1520,511 @@ index 0addbad..7b0c72a 100644
+ }
/* Position Word 2: Source Image Size, Alpha Mode */
-+ vc4_state->pos2_offset = vc4_state->dlist_count;
+ vc4_state->pos2_offset = vc4_state->dlist_count;
+@@ -266,6 +467,32 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
vc4_dlist_write(vc4_state,
- VC4_SET_FIELD(format->has_alpha ?
+ VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH));
+
++ if (!vc4_state->is_unity) {
++ /* LBM Base Address. */
++ if (vc4_state->y_scaling != VC4_SCALING_NONE)
++ vc4_dlist_write(vc4_state, vc4_state->lbm.start);
++
++ vc4_write_scaling_parameters(state);
++
++ /* If any PPF setup was done, then all the kernel
++ * pointers get uploaded.
++ */
++ if (vc4_state->x_scaling == VC4_SCALING_PPF ||
++ vc4_state->y_scaling == VC4_SCALING_PPF) {
++ u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
++ SCALER_PPF_KERNEL_OFFSET);
++
++ /* HPPF plane 0 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* VPPF plane 0 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* HPPF plane 1 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* VPPF plane 1 */
++ vc4_dlist_write(vc4_state, kernel);
++ }
++ }
++
+ vc4_state->dlist[ctl0_offset] |=
+ VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
+
+diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
+index 7c29993..a5b544d 100644
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -552,6 +552,21 @@ enum hvs_pixel_format {
+ #define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13)
+ #define SCALER_CTL0_ORDER_SHIFT 13
+
++#define SCALER_CTL0_SCL1_MASK VC4_MASK(10, 8)
++#define SCALER_CTL0_SCL1_SHIFT 8
++
++#define SCALER_CTL0_SCL0_MASK VC4_MASK(7, 5)
++#define SCALER_CTL0_SCL0_SHIFT 5
++
++#define SCALER_CTL0_SCL_H_PPF_V_PPF 0
++#define SCALER_CTL0_SCL_H_TPZ_V_PPF 1
++#define SCALER_CTL0_SCL_H_PPF_V_TPZ 2
++#define SCALER_CTL0_SCL_H_TPZ_V_TPZ 3
++#define SCALER_CTL0_SCL_H_PPF_V_NONE 4
++#define SCALER_CTL0_SCL_H_NONE_V_PPF 5
++#define SCALER_CTL0_SCL_H_NONE_V_TPZ 6
++#define SCALER_CTL0_SCL_H_TPZ_V_NONE 7
++
+ /* Set to indicate no scaling. */
+ #define SCALER_CTL0_UNITY BIT(4)
+
+@@ -567,6 +582,12 @@ enum hvs_pixel_format {
+ #define SCALER_POS0_START_X_MASK VC4_MASK(11, 0)
+ #define SCALER_POS0_START_X_SHIFT 0
+
++#define SCALER_POS1_SCL_HEIGHT_MASK VC4_MASK(27, 16)
++#define SCALER_POS1_SCL_HEIGHT_SHIFT 16
++
++#define SCALER_POS1_SCL_WIDTH_MASK VC4_MASK(11, 0)
++#define SCALER_POS1_SCL_WIDTH_SHIFT 0
++
+ #define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30)
+ #define SCALER_POS2_ALPHA_MODE_SHIFT 30
+ #define SCALER_POS2_ALPHA_MODE_PIPELINE 0
+@@ -580,6 +601,31 @@ enum hvs_pixel_format {
+ #define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0)
+ #define SCALER_POS2_WIDTH_SHIFT 0
+
++#define SCALER_TPZ0_VERT_RECALC BIT(31)
++#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
++#define SCALER_TPZ0_SCALE_SHIFT 8
++#define SCALER_TPZ0_IPHASE_MASK VC4_MASK(7, 0)
++#define SCALER_TPZ0_IPHASE_SHIFT 0
++#define SCALER_TPZ1_RECIP_MASK VC4_MASK(15, 0)
++#define SCALER_TPZ1_RECIP_SHIFT 0
++
++/* Skips interpolating coefficients to 64 phases, so just 8 are used.
++ * Required for nearest neighbor.
++ */
++#define SCALER_PPF_NOINTERP BIT(31)
++/* Replaes the highest valued coefficient with one that makes all 4
++ * sum to unity.
++ */
++#define SCALER_PPF_AGC BIT(30)
++#define SCALER_PPF_SCALE_MASK VC4_MASK(24, 8)
++#define SCALER_PPF_SCALE_SHIFT 8
++#define SCALER_PPF_IPHASE_MASK VC4_MASK(6, 0)
++#define SCALER_PPF_IPHASE_SHIFT 0
++
++#define SCALER_PPF_KERNEL_OFFSET_MASK VC4_MASK(13, 0)
++#define SCALER_PPF_KERNEL_OFFSET_SHIFT 0
++#define SCALER_PPF_KERNEL_UNCACHED BIT(31)
++
+ #define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0)
+ #define SCALER_SRC_PITCH_SHIFT 0
+
+--
+2.7.3
+
+From c1f11c3b1a4379841341911c379237d3a3870607 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 20 Oct 2015 13:59:15 +0100
+Subject: [PATCH 14/36] drm/vc4: Add support a few more RGB display plane
+ formats.
+
+These were all touch-tested with modetest.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index 7c2d697..013ebff 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -88,6 +88,22 @@ static const struct hvs_format {
+ .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
+ },
++ {
++ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
++ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
++ },
++ {
++ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
++ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
++ },
++ {
++ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
++ },
++ {
++ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
++ },
+ };
+
+ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
+--
+2.7.3
+
+From 149a88adaedd0bea6c6f2f12dcf893d740be2ebb Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 30 Dec 2015 12:25:44 -0800
+Subject: [PATCH 15/36] drm/vc4: Add support for YUV planes.
+
+This supports 420 and 422 subsampling with 2 or 3 planes, tested with
+modetest. It doesn't set up chroma subsampling position (which it
+appears KMS doesn't deal with yet).
+
+The LBM memory is overallocated in many cases, but apparently the docs
+aren't quite correct and I'll probably need to look at the hardware
+source to really figure it out.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 256 +++++++++++++++++++++++++++++++---------
+ drivers/gpu/drm/vc4/vc4_regs.h | 56 ++++++++-
+ 2 files changed, 253 insertions(+), 59 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
+index 013ebff..7b0c72a 100644
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -54,15 +54,19 @@ struct vc4_plane_state {
+ /* Clipped coordinates of the plane on the display. */
+ int crtc_x, crtc_y, crtc_w, crtc_h;
+ /* Clipped area being scanned from in the FB. */
+- u32 src_x, src_y, src_w, src_h;
++ u32 src_x, src_y;
+
+- enum vc4_scaling_mode x_scaling, y_scaling;
++ u32 src_w[2], src_h[2];
++
++ /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
++ enum vc4_scaling_mode x_scaling[2], y_scaling[2];
+ bool is_unity;
++ bool is_yuv;
+
+ /* Offset to start scanning out from the start of the plane's
+ * BO.
+ */
+- u32 offset;
++ u32 offsets[3];
+
+ /* Our allocation in LBM for temporary storage during scaling. */
+ struct drm_mm_node lbm;
+@@ -79,6 +83,7 @@ static const struct hvs_format {
+ u32 hvs; /* HVS_FORMAT_* */
+ u32 pixel_order;
+ bool has_alpha;
++ bool flip_cbcr;
+ } hvs_formats[] = {
+ {
+ .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+@@ -104,6 +109,32 @@ static const struct hvs_format {
+ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
+ },
++ {
++ .drm = DRM_FORMAT_YUV422,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
++ },
++ {
++ .drm = DRM_FORMAT_YVU422,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
++ .flip_cbcr = true,
++ },
++ {
++ .drm = DRM_FORMAT_YUV420,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
++ },
++ {
++ .drm = DRM_FORMAT_YVU420,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
++ .flip_cbcr = true,
++ },
++ {
++ .drm = DRM_FORMAT_NV12,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
++ },
++ {
++ .drm = DRM_FORMAT_NV16,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
++ },
+ };
+
+ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
+@@ -219,11 +250,11 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
+ *
+ * This is a replication of a table from the spec.
+ */
+-static u32 vc4_get_scl_field(struct drm_plane_state *state)
++static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
+ {
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
+- switch (vc4_state->x_scaling << 2 | vc4_state->y_scaling) {
++ switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
+ case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
+ return SCALER_CTL0_SCL_H_PPF_V_PPF;
+ case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
+@@ -254,9 +285,16 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ struct drm_plane *plane = state->plane;
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ u32 subpixel_src_mask = (1 << 16) - 1;
++ u32 format = fb->pixel_format;
++ int num_planes = drm_format_num_planes(format);
++ u32 h_subsample = 1;
++ u32 v_subsample = 1;
++ int i;
+
+- vc4_state->offset = fb->offsets[0];
++ for (i = 0; i < num_planes; i++)
++ vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
+
+ /* We don't support subpixel source positioning for scaling. */
+ if ((state->src_x & subpixel_src_mask) ||
+@@ -268,20 +306,48 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+
+ vc4_state->src_x = state->src_x >> 16;
+ vc4_state->src_y = state->src_y >> 16;
+- vc4_state->src_w = state->src_w >> 16;
+- vc4_state->src_h = state->src_h >> 16;
++ vc4_state->src_w[0] = state->src_w >> 16;
++ vc4_state->src_h[0] = state->src_h >> 16;
+
+ vc4_state->crtc_x = state->crtc_x;
+ vc4_state->crtc_y = state->crtc_y;
+ vc4_state->crtc_w = state->crtc_w;
+ vc4_state->crtc_h = state->crtc_h;
+
+- vc4_state->x_scaling = vc4_get_scaling_mode(vc4_state->src_w,
+- vc4_state->crtc_w);
+- vc4_state->y_scaling = vc4_get_scaling_mode(vc4_state->src_h,
+- vc4_state->crtc_h);
+- vc4_state->is_unity = (vc4_state->x_scaling == VC4_SCALING_NONE &&
+- vc4_state->y_scaling == VC4_SCALING_NONE);
++ vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
++ vc4_state->crtc_w);
++ vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
++ vc4_state->crtc_h);
++
++ if (num_planes > 1) {
++ vc4_state->is_yuv = true;
++
++ h_subsample = drm_format_horz_chroma_subsampling(format);
++ v_subsample = drm_format_vert_chroma_subsampling(format);
++ vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
++ vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
++
++ vc4_state->x_scaling[1] =
++ vc4_get_scaling_mode(vc4_state->src_w[1],
++ vc4_state->crtc_w);
++ vc4_state->y_scaling[1] =
++ vc4_get_scaling_mode(vc4_state->src_h[1],
++ vc4_state->crtc_h);
++
++ /* YUV conversion requires that scaling be enabled,
++ * even on a plane that's otherwise 1:1. Choose TPZ
++ * for simplicity.
++ */
++ if (vc4_state->x_scaling[0] == VC4_SCALING_NONE)
++ vc4_state->x_scaling[0] = VC4_SCALING_TPZ;
++ if (vc4_state->y_scaling[0] == VC4_SCALING_NONE)
++ vc4_state->y_scaling[0] = VC4_SCALING_TPZ;
++ }
++
++ vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
++ vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
++ vc4_state->x_scaling[1] == VC4_SCALING_NONE &&
++ vc4_state->y_scaling[1] == VC4_SCALING_NONE);
+
+ /* No configuring scaling on the cursor plane, since it gets
+ non-vblank-synced updates, and scaling requires requires
+@@ -294,16 +360,27 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ * support negative y, and negative x wastes bandwidth.
+ */
+ if (vc4_state->crtc_x < 0) {
+- vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
+- 0) *
+- -vc4_state->crtc_x);
+- vc4_state->src_w += vc4_state->crtc_x;
++ for (i = 0; i < num_planes; i++) {
++ u32 cpp = drm_format_plane_cpp(fb->pixel_format, i);
++ u32 subs = ((i == 0) ? 1 : h_subsample);
++
++ vc4_state->offsets[i] += (cpp *
++ (-vc4_state->crtc_x) / subs);
++ }
++ vc4_state->src_w[0] += vc4_state->crtc_x;
++ vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
+ vc4_state->crtc_x = 0;
+ }
+
+ if (vc4_state->crtc_y < 0) {
+- vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y;
+- vc4_state->src_h += vc4_state->crtc_y;
++ for (i = 0; i < num_planes; i++) {
++ u32 subs = ((i == 0) ? 1 : v_subsample);
++
++ vc4_state->offsets[i] += (fb->pitches[i] *
++ (-vc4_state->crtc_y) / subs);
++ }
++ vc4_state->src_h[0] += vc4_state->crtc_y;
++ vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
+ vc4_state->crtc_y = 0;
+ }
+
+@@ -344,15 +421,23 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
+ /* This is the worst case number. One of the two sizes will
+ * be used depending on the scaling configuration.
+ */
+- u32 pix_per_line = max(vc4_state->src_w, (u32)vc4_state->crtc_w);
++ u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
+ u32 lbm;
+
+- if (vc4_state->is_unity)
+- return 0;
+- else if (vc4_state->y_scaling == VC4_SCALING_TPZ)
+- lbm = pix_per_line * 8;
+- else {
+- /* In special cases, this multiplier might be 12. */
++ if (!vc4_state->is_yuv) {
++ if (vc4_state->is_unity)
++ return 0;
++ else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
++ lbm = pix_per_line * 8;
++ else {
++ /* In special cases, this multiplier might be 12. */
++ lbm = pix_per_line * 16;
++ }
++ } else {
++ /* There are cases for this going down to a multiplier
++ * of 2, but according to the firmware source, the
++ * table in the docs is somewhat wrong.
++ */
+ lbm = pix_per_line * 16;
+ }
+
+@@ -361,33 +446,34 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
+ return lbm;
+ }
+
+-static void vc4_write_scaling_parameters(struct drm_plane_state *state)
++static void vc4_write_scaling_parameters(struct drm_plane_state *state,
++ int channel)
+ {
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
+ /* Ch0 H-PPF Word 0: Scaling Parameters */
+- if (vc4_state->x_scaling == VC4_SCALING_PPF) {
++ if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
+ vc4_write_ppf(vc4_state,
+- vc4_state->src_w, vc4_state->crtc_w);
++ vc4_state->src_w[channel], vc4_state->crtc_w);
+ }
+
+ /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
+- if (vc4_state->y_scaling == VC4_SCALING_PPF) {
++ if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
+ vc4_write_ppf(vc4_state,
+- vc4_state->src_h, vc4_state->crtc_h);
++ vc4_state->src_h[channel], vc4_state->crtc_h);
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ }
+
+ /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
+- if (vc4_state->x_scaling == VC4_SCALING_TPZ) {
++ if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
+ vc4_write_tpz(vc4_state,
+- vc4_state->src_w, vc4_state->crtc_w);
++ vc4_state->src_w[channel], vc4_state->crtc_w);
+ }
+
+ /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
+- if (vc4_state->y_scaling == VC4_SCALING_TPZ) {
++ if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
+ vc4_write_tpz(vc4_state,
+- vc4_state->src_h, vc4_state->crtc_h);
++ vc4_state->src_h[channel], vc4_state->crtc_h);
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ }
+ }
+@@ -401,13 +487,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ u32 ctl0_offset = vc4_state->dlist_count;
+ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
+- u32 scl;
++ int num_planes = drm_format_num_planes(format->drm);
++ u32 scl0, scl1;
+ u32 lbm_size;
+ unsigned long irqflags;
+- int ret;
++ int ret, i;
+
+ ret = vc4_plane_setup_clipping_and_scaling(state);
+ if (ret)
+@@ -432,7 +518,19 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ if (ret)
+ return ret;
+
+- scl = vc4_get_scl_field(state);
++ /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
++ * and 4:4:4, scl1 should be set to scl0 so both channels of
++ * the scaler do the same thing. For YUV, the Y plane needs
++ * to be put in channel 1 and Cb/Cr in channel 0, so we swap
++ * the scl fields here.
++ */
++ if (num_planes == 1) {
++ scl0 = vc4_get_scl_field(state, 1);
++ scl1 = scl0;
++ } else {
++ scl0 = vc4_get_scl_field(state, 1);
++ scl1 = vc4_get_scl_field(state, 0);
++ }
+
+ /* Control word */
+ vc4_dlist_write(vc4_state,
+@@ -440,8 +538,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+ (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
+- VC4_SET_FIELD(scl, SCALER_CTL0_SCL0) |
+- VC4_SET_FIELD(scl, SCALER_CTL0_SCL1));
++ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
++ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
+
+ /* Position Word 0: Image Positions and Alpha Value */
+ vc4_state->pos0_offset = vc4_state->dlist_count;
+@@ -466,35 +564,68 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
SCALER_POS2_ALPHA_MODE_PIPELINE :
SCALER_POS2_ALPHA_MODE_FIXED,
SCALER_POS2_ALPHA_MODE) |
-- VC4_SET_FIELD(crtc_w, SCALER_POS2_WIDTH) |
-- VC4_SET_FIELD(crtc_h, SCALER_POS2_HEIGHT));
+- VC4_SET_FIELD(vc4_state->src_w, SCALER_POS2_WIDTH) |
+- VC4_SET_FIELD(vc4_state->src_h, SCALER_POS2_HEIGHT));
+ VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
+ VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
/* Position Word 3: Context. Written by the HVS. */
vc4_dlist_write(vc4_state, 0xc0c0c0c0);
-- vc4_state->pw0_offset = vc4_state->dlist_count;
-
- /* Pointer Word 0: RGB / Y Pointer */
-- vc4_dlist_write(vc4_state, bo->paddr + offset);
++
+ /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
+ *
+ * The pointers may be any byte address.
+ */
-+ vc4_state->ptr0_offset = vc4_state->dlist_count;
+ vc4_state->ptr0_offset = vc4_state->dlist_count;
+- vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset);
+ if (!format->flip_cbcr) {
+ for (i = 0; i < num_planes; i++)
+ vc4_dlist_write(vc4_state, vc4_state->offsets[i]);
@@ -1583,14 +2056,16 @@ index 0addbad..7b0c72a 100644
+ vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
+ vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
+ }
-+
-+ if (!vc4_state->is_unity) {
-+ /* LBM Base Address. */
+
+ if (!vc4_state->is_unity) {
+ /* LBM Base Address. */
+- if (vc4_state->y_scaling != VC4_SCALING_NONE)
+ if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
+ vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
-+ vc4_dlist_write(vc4_state, vc4_state->lbm.start);
+ vc4_dlist_write(vc4_state, vc4_state->lbm.start);
+ }
-+
+
+- vc4_write_scaling_parameters(state);
+ if (num_planes > 1) {
+ /* Emit Cb/Cr as channel 0 and Y as channel
+ * 1. This matches how we set up scl0/scl1
@@ -1599,132 +2074,20 @@ index 0addbad..7b0c72a 100644
+ vc4_write_scaling_parameters(state, 1);
+ }
+ vc4_write_scaling_parameters(state, 0);
-+
-+ /* If any PPF setup was done, then all the kernel
-+ * pointers get uploaded.
-+ */
+
+ /* If any PPF setup was done, then all the kernel
+ * pointers get uploaded.
+ */
+- if (vc4_state->x_scaling == VC4_SCALING_PPF ||
+- vc4_state->y_scaling == VC4_SCALING_PPF) {
+ if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
+ vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
+ vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
+ vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
-+ u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
-+ SCALER_PPF_KERNEL_OFFSET);
-+
-+ /* HPPF plane 0 */
-+ vc4_dlist_write(vc4_state, kernel);
-+ /* VPPF plane 0 */
-+ vc4_dlist_write(vc4_state, kernel);
-+ /* HPPF plane 1 */
-+ vc4_dlist_write(vc4_state, kernel);
-+ /* VPPF plane 1 */
-+ vc4_dlist_write(vc4_state, kernel);
-+ }
-+ }
-
- vc4_state->dlist[ctl0_offset] |=
- VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
-@@ -303,13 +716,13 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
- * scanout will start from this address as soon as the FIFO
- * needs to refill with pixels.
- */
-- writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
-+ writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
+ u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
+ SCALER_PPF_KERNEL_OFFSET);
- /* Also update the CPU-side dlist copy, so that any later
- * atomic updates that don't do a new modeset on our plane
- * also use our updated address.
- */
-- vc4_state->dlist[vc4_state->pw0_offset] = addr;
-+ vc4_state->dlist[vc4_state->ptr0_offset] = addr;
- }
-
- static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
-@@ -325,8 +738,83 @@ static void vc4_plane_destroy(struct drm_plane *plane)
- drm_plane_cleanup(plane);
- }
-
-+/* Implements immediate (non-vblank-synced) updates of the cursor
-+ * position, or falls back to the atomic helper otherwise.
-+ */
-+static int
-+vc4_update_plane(struct drm_plane *plane,
-+ struct drm_crtc *crtc,
-+ struct drm_framebuffer *fb,
-+ int crtc_x, int crtc_y,
-+ unsigned int crtc_w, unsigned int crtc_h,
-+ uint32_t src_x, uint32_t src_y,
-+ uint32_t src_w, uint32_t src_h)
-+{
-+ struct drm_plane_state *plane_state;
-+ struct vc4_plane_state *vc4_state;
-+
-+ if (plane != crtc->cursor)
-+ goto out;
-+
-+ plane_state = plane->state;
-+ vc4_state = to_vc4_plane_state(plane_state);
-+
-+ if (!plane_state)
-+ goto out;
-+
-+ /* If we're changing the cursor contents, do that in the
-+ * normal vblank-synced atomic path.
-+ */
-+ if (fb != plane_state->fb)
-+ goto out;
-+
-+ /* No configuring new scaling in the fast path. */
-+ if (crtc_w != plane_state->crtc_w ||
-+ crtc_h != plane_state->crtc_h ||
-+ src_w != plane_state->src_w ||
-+ src_h != plane_state->src_h) {
-+ goto out;
-+ }
-+
-+ /* Set the cursor's position on the screen. This is the
-+ * expected change from the drm_mode_cursor_universal()
-+ * helper.
-+ */
-+ plane_state->crtc_x = crtc_x;
-+ plane_state->crtc_y = crtc_y;
-+
-+ /* Allow changing the start position within the cursor BO, if
-+ * that matters.
-+ */
-+ plane_state->src_x = src_x;
-+ plane_state->src_y = src_y;
-+
-+ /* Update the display list based on the new crtc_x/y. */
-+ vc4_plane_atomic_check(plane, plane_state);
-+
-+ /* Note that we can't just call vc4_plane_write_dlist()
-+ * because that would smash the context data that the HVS is
-+ * currently using.
-+ */
-+ writel(vc4_state->dlist[vc4_state->pos0_offset],
-+ &vc4_state->hw_dlist[vc4_state->pos0_offset]);
-+ writel(vc4_state->dlist[vc4_state->pos2_offset],
-+ &vc4_state->hw_dlist[vc4_state->pos2_offset]);
-+ writel(vc4_state->dlist[vc4_state->ptr0_offset],
-+ &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
-+
-+ return 0;
-+
-+out:
-+ return drm_atomic_helper_update_plane(plane, crtc, fb,
-+ crtc_x, crtc_y,
-+ crtc_w, crtc_h,
-+ src_x, src_y,
-+ src_w, src_h);
-+}
-+
- static const struct drm_plane_funcs vc4_plane_funcs = {
-- .update_plane = drm_atomic_helper_update_plane,
-+ .update_plane = vc4_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = vc4_plane_destroy,
- .set_property = NULL,
-@@ -341,6 +829,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
+@@ -698,6 +829,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
struct drm_plane *plane = NULL;
struct vc4_plane *vc4_plane;
u32 formats[ARRAY_SIZE(hvs_formats)];
@@ -1732,7 +2095,7 @@ index 0addbad..7b0c72a 100644
int ret = 0;
unsigned i;
-@@ -351,12 +840,20 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
+@@ -708,12 +840,20 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
goto fail;
}
@@ -1757,56 +2120,10 @@ index 0addbad..7b0c72a 100644
drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
-index 4e52a0a..bf42a8e 100644
+index a5b544d..bf42a8e 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -187,7 +187,7 @@
- # define PV_VCONTROL_CONTINUOUS BIT(1)
- # define PV_VCONTROL_VIDEN BIT(0)
-
--#define PV_VSYNCD 0x08
-+#define PV_VSYNCD_EVEN 0x08
-
- #define PV_HORZA 0x0c
- # define PV_HORZA_HBP_MASK VC4_MASK(31, 16)
-@@ -350,6 +350,17 @@
- # define SCALER_DISPCTRLX_HEIGHT_SHIFT 0
-
- #define SCALER_DISPBKGND0 0x00000044
-+# define SCALER_DISPBKGND_AUTOHS BIT(31)
-+# define SCALER_DISPBKGND_INTERLACE BIT(30)
-+# define SCALER_DISPBKGND_GAMMA BIT(29)
-+# define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25)
-+# define SCALER_DISPBKGND_TESTMODE_SHIFT 25
-+/* Enables filling the scaler line with the RGB value in the low 24
-+ * bits before compositing. Costs cycles, so should be skipped if
-+ * opaque display planes will cover everything.
-+ */
-+# define SCALER_DISPBKGND_FILL BIT(24)
-+
- #define SCALER_DISPSTAT0 0x00000048
- #define SCALER_DISPBASE0 0x0000004c
- # define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30)
-@@ -362,6 +373,9 @@
- # define SCALER_DISPSTATX_EMPTY BIT(28)
- #define SCALER_DISPCTRL1 0x00000050
- #define SCALER_DISPBKGND1 0x00000054
-+#define SCALER_DISPBKGNDX(x) (SCALER_DISPBKGND0 + \
-+ (x) * (SCALER_DISPBKGND1 - \
-+ SCALER_DISPBKGND0))
- #define SCALER_DISPSTAT1 0x00000058
- #define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \
- (x) * (SCALER_DISPSTAT1 - \
-@@ -456,6 +470,8 @@
- #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
-
- #define VC4_HD_M_CTL 0x00c
-+# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
-+# define VC4_HD_M_RAM_STANDBY (3 << 4)
- # define VC4_HD_M_SW_RST BIT(2)
- # define VC4_HD_M_ENABLE BIT(0)
-
-@@ -503,7 +519,12 @@ enum hvs_pixel_format {
+@@ -519,7 +519,12 @@ enum hvs_pixel_format {
HVS_PIXEL_FORMAT_RGB888 = 5,
HVS_PIXEL_FORMAT_RGBA6666 = 6,
/* 32bpp */
@@ -1820,42 +2137,7 @@ index 4e52a0a..bf42a8e 100644
};
/* Note: the LSB is the rightmost character shown. Only valid for
-@@ -536,6 +557,21 @@ enum hvs_pixel_format {
- #define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13)
- #define SCALER_CTL0_ORDER_SHIFT 13
-
-+#define SCALER_CTL0_SCL1_MASK VC4_MASK(10, 8)
-+#define SCALER_CTL0_SCL1_SHIFT 8
-+
-+#define SCALER_CTL0_SCL0_MASK VC4_MASK(7, 5)
-+#define SCALER_CTL0_SCL0_SHIFT 5
-+
-+#define SCALER_CTL0_SCL_H_PPF_V_PPF 0
-+#define SCALER_CTL0_SCL_H_TPZ_V_PPF 1
-+#define SCALER_CTL0_SCL_H_PPF_V_TPZ 2
-+#define SCALER_CTL0_SCL_H_TPZ_V_TPZ 3
-+#define SCALER_CTL0_SCL_H_PPF_V_NONE 4
-+#define SCALER_CTL0_SCL_H_NONE_V_PPF 5
-+#define SCALER_CTL0_SCL_H_NONE_V_TPZ 6
-+#define SCALER_CTL0_SCL_H_TPZ_V_NONE 7
-+
- /* Set to indicate no scaling. */
- #define SCALER_CTL0_UNITY BIT(4)
-
-@@ -551,6 +587,12 @@ enum hvs_pixel_format {
- #define SCALER_POS0_START_X_MASK VC4_MASK(11, 0)
- #define SCALER_POS0_START_X_SHIFT 0
-
-+#define SCALER_POS1_SCL_HEIGHT_MASK VC4_MASK(27, 16)
-+#define SCALER_POS1_SCL_HEIGHT_SHIFT 16
-+
-+#define SCALER_POS1_SCL_WIDTH_MASK VC4_MASK(11, 0)
-+#define SCALER_POS1_SCL_WIDTH_SHIFT 0
-+
- #define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30)
- #define SCALER_POS2_ALPHA_MODE_SHIFT 30
- #define SCALER_POS2_ALPHA_MODE_PIPELINE 0
-@@ -564,6 +606,80 @@ enum hvs_pixel_format {
+@@ -601,6 +606,55 @@ enum hvs_pixel_format {
#define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0)
#define SCALER_POS2_WIDTH_SHIFT 0
@@ -1908,34 +2190,162 @@ index 4e52a0a..bf42a8e 100644
+#define SCALER_CSC2_ITR_R_709_3 0x00072a1c
+#define SCALER_CSC2_JPEG_JFIF 0x000599c5
+
-+#define SCALER_TPZ0_VERT_RECALC BIT(31)
-+#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
-+#define SCALER_TPZ0_SCALE_SHIFT 8
-+#define SCALER_TPZ0_IPHASE_MASK VC4_MASK(7, 0)
-+#define SCALER_TPZ0_IPHASE_SHIFT 0
-+#define SCALER_TPZ1_RECIP_MASK VC4_MASK(15, 0)
-+#define SCALER_TPZ1_RECIP_SHIFT 0
-+
-+/* Skips interpolating coefficients to 64 phases, so just 8 are used.
-+ * Required for nearest neighbor.
-+ */
-+#define SCALER_PPF_NOINTERP BIT(31)
-+/* Replaes the highest valued coefficient with one that makes all 4
-+ * sum to unity.
-+ */
-+#define SCALER_PPF_AGC BIT(30)
-+#define SCALER_PPF_SCALE_MASK VC4_MASK(24, 8)
-+#define SCALER_PPF_SCALE_SHIFT 8
-+#define SCALER_PPF_IPHASE_MASK VC4_MASK(6, 0)
-+#define SCALER_PPF_IPHASE_SHIFT 0
+ #define SCALER_TPZ0_VERT_RECALC BIT(31)
+ #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
+ #define SCALER_TPZ0_SCALE_SHIFT 8
+--
+2.7.3
+
+From 47ed1ee3dbfde89297b81bc09f1b483f4da1b06d Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 29 Feb 2016 17:53:00 -0800
+Subject: [PATCH 16/36] drm/vc4: Let gpiolib know that we're OK with sleeping
+ for HPD.
+
+Fixes an error thrown every few seconds when we poll HPD when it's on
+a I2C to GPIO expander.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Tested-by: Daniel Stone <daniels@collabora.com>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
+index 56272ca..6bcf51d 100644
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -166,7 +166,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ if (vc4->hdmi->hpd_gpio) {
+- if (gpio_get_value(vc4->hdmi->hpd_gpio))
++ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio))
+ return connector_status_connected;
+ else
+ return connector_status_disconnected;
+--
+2.7.3
+
+From 24b28acef42486c282bc58e977cbfc66191a8f38 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 29 Feb 2016 17:53:01 -0800
+Subject: [PATCH 17/36] drm/vc4: Respect GPIO_ACTIVE_LOW on HDMI HPD if set in
+ the devicetree.
+
+The original Raspberry Pi had the GPIO active high, but the later
+models are active low. The DT GPIO bindings allow specifying the
+active flag, except that it doesn't get propagated to the gpiodesc, so
+you have to handle it yourself.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Tested-by: Daniel Stone <daniels@collabora.com>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
+index 6bcf51d..d8b8649 100644
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -47,6 +47,7 @@ struct vc4_hdmi {
+ void __iomem *hdmicore_regs;
+ void __iomem *hd_regs;
+ int hpd_gpio;
++ bool hpd_active_low;
+
+ struct clk *pixel_clock;
+ struct clk *hsm_clock;
+@@ -166,7 +167,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ if (vc4->hdmi->hpd_gpio) {
+- if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio))
++ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
++ vc4->hdmi->hpd_active_low)
+ return connector_status_connected;
+ else
+ return connector_status_disconnected;
+@@ -517,11 +519,17 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
+ * we'll use the HDMI core's register.
+ */
+ if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
+- hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0);
++ enum of_gpio_flags hpd_gpio_flags;
+
-+#define SCALER_PPF_KERNEL_OFFSET_MASK VC4_MASK(13, 0)
-+#define SCALER_PPF_KERNEL_OFFSET_SHIFT 0
-+#define SCALER_PPF_KERNEL_UNCACHED BIT(31)
++ hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
++ "hpd-gpios", 0,
++ &hpd_gpio_flags);
+ if (hdmi->hpd_gpio < 0) {
+ ret = hdmi->hpd_gpio;
+ goto err_unprepare_hsm;
+ }
+
- #define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0)
- #define SCALER_SRC_PITCH_SHIFT 0
++ hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
+ }
+ vc4->hdmi = hdmi;
+--
+2.7.3
+
+From d258332b618af0136386d4fb8f738caedae8c71d Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 8 Mar 2016 15:09:41 +0300
+Subject: [PATCH 18/36] drm/vc4: Return -EFAULT on copy_from_user() failure
+
+The copy_from_user() function returns the number of bytes not copied but
+we want to return a negative error code.
+
+Fixes: 463873d57014 ('drm/vc4: Add an API for creating GPU shaders in GEM BOs.')
+Cc: stable@vger.kernel.org
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_bo.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
+index 22278bc..ac8eafe 100644
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -499,11 +499,12 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
+
+- ret = copy_from_user(bo->base.vaddr,
++ if (copy_from_user(bo->base.vaddr,
+ (void __user *)(uintptr_t)args->data,
+- args->size);
+- if (ret != 0)
++ args->size)) {
++ ret = -EFAULT;
+ goto fail;
++ }
+ /* Clear the rest of the memory from allocating from the BO
+ * cache.
+ */
+--
+2.7.3
+
+From ed6836e411dd559a811dd063509a01772f4fe00f Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 4 Mar 2016 12:32:07 -0800
+Subject: [PATCH 19/36] drm/vc4: Recognize a more specific compatible string
+ for V3D.
+
+The Raspberry Pi Foundation's firmware updates are shipping device
+trees using the old string, so we'll keep recognizing that as this rev
+of V3D. Still, we should use a more specific name in the upstream DT
+to clarify which board is being supported, in case we do other revs of
+V3D in the future.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+---
+ drivers/gpu/drm/vc4/vc4_v3d.c | 1 +
+ 1 file changed, 1 insertion(+)
+
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 31de5d1..e6d3c60 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -1948,103 +2358,811 @@ index 31de5d1..e6d3c60 100644
{ .compatible = "brcm,vc4-v3d" },
{}
};
-diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
-index 1526b8a..60de1e4 100644
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -318,15 +318,15 @@ config MMC_SDHCI_F_SDH30
- If unsure, say N.
+--
+2.7.3
+
+From 142ad4bd29558b85f269a02b74c5149b514acf88 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 15 Feb 2016 19:03:57 -0800
+Subject: [PATCH 20/36] clk: bcm2835: Fix setting of PLL divider clock rates
+
+Our dividers weren't being set successfully because CM_PASSWORD wasn't
+included in the register write. It looks easier to just compute the
+divider to write ourselves than to update clk-divider for the ability
+to OR in some arbitrary bits on write.
+
+Fixes about half of the video modes on my HDMI monitor (everything
+except 720x400).
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 015e687..9f4df8f 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1107,13 +1107,15 @@ static int bcm2835_pll_divider_set_rate(struct clk_hw *hw,
+ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
+ struct bcm2835_cprman *cprman = divider->cprman;
+ const struct bcm2835_pll_divider_data *data = divider->data;
+- u32 cm;
+- int ret;
++ u32 cm, div, max_div = 1 << A2W_PLL_DIV_BITS;
- config MMC_SDHCI_IPROC
-- tristate "SDHCI platform support for the iProc SD/MMC Controller"
-- depends on ARCH_BCM_IPROC || COMPILE_TEST
-+ tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"
-+ depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST
- depends on MMC_SDHCI_PLTFM
- default ARCH_BCM_IPROC
- select MMC_SDHCI_IO_ACCESSORS
- help
- This selects the iProc SD/MMC controller.
+- ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+- if (ret)
+- return ret;
++ div = DIV_ROUND_UP_ULL(parent_rate, rate);
++
++ div = min(div, max_div);
++ if (div == max_div)
++ div = 0;
-- If you have an IPROC platform with SD or MMC devices,
-+ If you have a BCM2835 or IPROC platform with SD or MMC devices,
- say Y or M here.
++ cprman_write(cprman, data->a2w_reg, div);
+ cm = cprman_read(cprman, data->cm_reg);
+ cprman_write(cprman, data->cm_reg, cm | data->load_mask);
+ cprman_write(cprman, data->cm_reg, cm & ~data->load_mask);
+--
+2.7.3
+
+From 55acd7db60c8247d926969b705373765c26c1f44 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Fri, 11 Sep 2015 11:22:05 +0000
+Subject: [PATCH 21/36] ARM: bcm2835: add the auxiliary spi1 and spi2 to the
+ device tree
+
+This enables the use of the auxiliary spi1 and spi2 devices
+on the bcm2835 SOC.
+
+Note that this requires the use of the new clk-bcm2835-aux to work.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+[anholt: Rebased on 2835.dtsi -> 283x.dtsi change]
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
+index 971e741..f0d4573 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -1,5 +1,6 @@
+ #include <dt-bindings/pinctrl/bcm2835.h>
+ #include <dt-bindings/clock/bcm2835.h>
++#include <dt-bindings/clock/bcm2835-aux.h>
+ #include "skeleton.dtsi"
- If unsure, say N.
-diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
-index 3b423b0..871c92c 100644
---- a/drivers/mmc/host/sdhci-iproc.c
-+++ b/drivers/mmc/host/sdhci-iproc.c
-@@ -26,6 +26,7 @@ struct sdhci_iproc_data {
- const struct sdhci_pltfm_data *pdata;
- u32 caps;
- u32 caps1;
-+ u32 mmc_caps;
+ /* This include file covers the common peripherals and configuration between
+@@ -159,6 +160,26 @@
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ };
+
++ spi1: spi@7e215080 {
++ compatible = "brcm,bcm2835-aux-spi";
++ reg = <0x7e215080 0x40>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_SPI1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi2: spi@7e2150c0 {
++ compatible = "brcm,bcm2835-aux-spi";
++ reg = <0x7e2150c0 0x40>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_SPI2>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ sdhci: sdhci@7e300000 {
+ compatible = "brcm,bcm2835-sdhci";
+ reg = <0x7e300000 0x100>;
+--
+2.7.3
+
+From 3e0a385cebe3b0d9338cab356c6a11daaa64f808 Mon Sep 17 00:00:00 2001
+From: Remi Pommarel <repk@triplefau.lt>
+Date: Mon, 21 Dec 2015 21:12:59 +0100
+Subject: [PATCH 22/36] ARM: bcm2835: Add PWM clock support to the device tree
+
+Signed-off-by: Remi Pommarel <repk@triplefau.lt>
+[anholt: Rebased on 2835.dtsi -> 283x.dtsi change]
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 ++++
+ arch/arm/boot/dts/bcm283x.dtsi | 10 ++++++++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+index 3afb9fe..a584a93 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -58,3 +58,7 @@
+ status = "okay";
+ bus-width = <4>;
};
++
++&pwm {
++ status = "okay";
++};
+diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
+index f0d4573..e4a2792 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -180,6 +180,16 @@
+ status = "disabled";
+ };
- struct sdhci_iproc_host {
-@@ -165,9 +166,25 @@ static const struct sdhci_iproc_data iproc_data = {
- .pdata = &sdhci_iproc_pltfm_data,
- .caps = 0x05E90000,
- .caps1 = 0x00000064,
-+ .mmc_caps = MMC_CAP_1_8V_DDR,
++ pwm: pwm@7e20c000 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7e20c000 0x28>;
++ clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clock-rates = <10000000>;
++ #pwm-cells = <2>;
++ status = "disabled";
++ };
++
+ sdhci: sdhci@7e300000 {
+ compatible = "brcm,bcm2835-sdhci";
+ reg = <0x7e300000 0x100>;
+--
+2.7.3
+
+From 84416a8360e7c31e6ba9f7775c077bd5f3fe32de Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Mon, 25 Jan 2016 21:40:06 +0100
+Subject: [PATCH 23/36] ARM: bcm2835: dt: Add Raspberry Pi Model A
+
+This one is essentially the same as revision 2 B board (with the I2S on
+P5 header).
+
+Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+[anholt: Rebased on bcm2835.dtsi -> bcm283x.dtsi change]
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2835-rpi-a.dts | 24 ++++++++++++++++++++++++
+ 2 files changed, 25 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2835-rpi-a.dts
+
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index a4a6d70..d000814 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -60,6 +60,7 @@ dtb-$(CONFIG_ARCH_AXXIA) += \
+ axm5516-amarillo.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2835-rpi-b.dtb \
++ bcm2835-rpi-a.dtb \
+ bcm2835-rpi-b-rev2.dtb \
+ bcm2835-rpi-b-plus.dtb \
+ bcm2835-rpi-a-plus.dtb \
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+new file mode 100644
+index 0000000..ddbbbbd
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+@@ -0,0 +1,24 @@
++/dts-v1/;
++#include "bcm2835.dtsi"
++#include "bcm2835-rpi.dtsi"
++
++/ {
++ compatible = "raspberrypi,model-a", "brcm,bcm2835";
++ model = "Raspberry Pi Model A";
++
++ leds {
++ act {
++ gpios = <&gpio 16 1>;
++ };
++ };
+};
+
-+static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
-+ .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-+ SDHCI_QUIRK_MISSING_CAPS,
-+ .ops = &sdhci_iproc_ops,
++&gpio {
++ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>;
++
++ /* I2S interface */
++ i2s_alt2: i2s_alt2 {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
+};
+--
+2.7.3
+
+From f6fd06c97f0d6d8398b8caba1b6879fa7e0284ba Mon Sep 17 00:00:00 2001
+From: Alexander Aring <alex.aring@gmail.com>
+Date: Wed, 16 Dec 2015 16:26:49 -0800
+Subject: [PATCH 24/36] ARM: bcm2835: Add the Raspberry Pi power domain driver
+ to the DT.
+
+This connects the USB driver to the USB power domain, so that USB can
+actually be turned on at boot if the bootloader didn't do it for us.
+
+Signed-off-by: Alexander Aring <alex.aring@gmail.com>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Kevin Hilman <khilman@linaro.org>
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 12 ++++++++++++
+ arch/arm/boot/dts/bcm283x.dtsi | 2 +-
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+index a584a93..76bdbca 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -1,3 +1,5 @@
++#include <dt-bindings/power/raspberrypi-power.h>
+
-+static const struct sdhci_iproc_data bcm2835_data = {
-+ .pdata = &sdhci_bcm2835_pltfm_data,
-+ .caps = SDHCI_CAN_VDD_330,
-+ .caps1 = 0x00000000,
-+ .mmc_caps = 0x00000000,
+ / {
+ memory {
+ reg = <0 0x10000000>;
+@@ -18,6 +20,12 @@
+ compatible = "raspberrypi,bcm2835-firmware";
+ mboxes = <&mailbox>;
+ };
++
++ power: power {
++ compatible = "raspberrypi,bcm2835-power";
++ firmware = <&firmware>;
++ #power-domain-cells = <1>;
++ };
+ };
};
- static const struct of_device_id sdhci_iproc_of_match[] = {
-+ { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
- { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data },
- { }
+@@ -62,3 +70,7 @@
+ &pwm {
+ status = "okay";
};
-@@ -199,22 +216,32 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
- mmc_of_parse(host->mmc);
- sdhci_get_of_property(pdev);
++
++&usb {
++ power-domains = <&power RPI_POWER_DOMAIN_USB>;
++};
+diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
+index e4a2792..e69a6cf 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -218,7 +218,7 @@
+ status = "disabled";
+ };
-- /* Enable EMMC 1/8V DDR capable */
-- host->mmc->caps |= MMC_CAP_1_8V_DDR;
-+ host->mmc->caps |= iproc_host->data->mmc_caps;
+- usb@7e980000 {
++ usb: usb@7e980000 {
+ compatible = "brcm,bcm2835-usb";
+ reg = <0x7e980000 0x10000>;
+ interrupts = <1 9>;
+--
+2.7.3
+
+From 580146c680ac7b706ac54d7d7db8204bee3d2e93 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Fri, 12 Feb 2016 11:14:25 +0000
+Subject: [PATCH 25/36] ARM: bcm2835: add bcm2835-aux-uart support to DT
+
+Add bcm2835-aux-uart support to the device tree.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ 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 e69a6cf..fc67964 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -160,6 +160,14 @@
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ };
- pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(pltfm_host->clk)) {
- ret = PTR_ERR(pltfm_host->clk);
- goto err;
- }
-+ ret = clk_prepare_enable(pltfm_host->clk);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to enable host clk\n");
-+ goto err;
-+ }
++ uart1: serial@7e215040 {
++ compatible = "brcm,bcm2835-aux-uart";
++ reg = <0x7e215040 0x40>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_UART>;
++ status = "disabled";
++ };
++
+ spi1: spi@7e215080 {
+ compatible = "brcm,bcm2835-aux-spi";
+ reg = <0x7e215080 0x40>;
+--
+2.7.3
+
+From 41135d2ce60509e53306e5b76afab98ddc15951b Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 2 Mar 2015 14:36:16 -0800
+Subject: [PATCH 26/36] ARM: bcm2835: Add VC4 to the device tree.
+
+VC4 is the GPU (display and 3D) present on the 283x.
+
+v2: Sort by register address, mark HDMI as disabled by default in the
+ SoC file and enable it from -rpi.
+v3: Add references to the pixel/HSM clocks for HDMI. Rename
+ compatibility strings and clean up node names.
+v4: Fix comment marking pv0's interrupt as pwa2 instead of pwa0.
+ Rename hpd-gpio to hpd-gpios.
+v5: Rebase on bcm283x.dtsi change, add v3d.
+v6: Make HDMI reference the power domain.
+v7: Fix the HDMI HPD gpios active value and HDMI enable for each RPI
+ board. Change V3D compatible string to 2835.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 4 +++
+ arch/arm/boot/dts/bcm2835-rpi-a.dts | 4 +++
+ arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 4 +++
+ arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 4 +++
+ arch/arm/boot/dts/bcm2835-rpi-b.dts | 4 +++
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 9 ++++++
+ arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 4 +++
+ arch/arm/boot/dts/bcm283x.dtsi | 47 ++++++++++++++++++++++++++++++++
+ 8 files changed, 80 insertions(+)
+
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+index 228614f..35ff4e7a 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+@@ -29,3 +29,7 @@
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+index ddbbbbd..306a84e 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+@@ -22,3 +22,7 @@
+ brcm,function = <BCM2835_FSEL_ALT2>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+index ef54050..57d313b 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+@@ -29,3 +29,7 @@
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+index 86f1f2f..cf2774e 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+@@ -22,3 +22,7 @@
+ brcm,function = <BCM2835_FSEL_ALT2>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+index 4859e9d..8b15f9c 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+@@ -16,3 +16,7 @@
+ &gpio {
+ pinctrl-0 = <&gpioout &alt0 &alt3>;
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+index 76bdbca..caf2707 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -74,3 +74,12 @@
+ &usb {
+ power-domains = <&power RPI_POWER_DOMAIN_USB>;
+ };
++
++&v3d {
++ power-domains = <&power RPI_POWER_DOMAIN_V3D>;
++};
++
++&hdmi {
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
++};
+diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+index ff94666..c4743f4 100644
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -33,3 +33,7 @@
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
+index fc67964..bbe4eab 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -1,6 +1,7 @@
+ #include <dt-bindings/pinctrl/bcm2835.h>
+ #include <dt-bindings/clock/bcm2835.h>
+ #include <dt-bindings/clock/bcm2835-aux.h>
++#include <dt-bindings/gpio/gpio.h>
+ #include "skeleton.dtsi"
- if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
- host->caps = iproc_host->data->caps;
- host->caps1 = iproc_host->data->caps1;
- }
+ /* This include file covers the common peripherals and configuration between
+@@ -153,6 +154,18 @@
+ status = "disabled";
+ };
-- return sdhci_add_host(host);
-+ ret = sdhci_add_host(host);
-+ if (ret)
-+ goto err_clk;
++ pixelvalve@7e206000 {
++ compatible = "brcm,bcm2835-pixelvalve0";
++ reg = <0x7e206000 0x100>;
++ interrupts = <2 13>; /* pwa0 */
++ };
+
-+ return 0;
++ pixelvalve@7e207000 {
++ compatible = "brcm,bcm2835-pixelvalve1";
++ reg = <0x7e207000 0x100>;
++ interrupts = <2 14>; /* pwa1 */
++ };
++
+ aux: aux@0x7e215000 {
+ compatible = "brcm,bcm2835-aux";
+ #clock-cells = <1>;
+@@ -206,6 +219,12 @@
+ status = "disabled";
+ };
-+err_clk:
-+ clk_disable_unprepare(pltfm_host->clk);
- err:
- sdhci_pltfm_free(pdev);
- return ret;
++ hvs@7e400000 {
++ compatible = "brcm,bcm2835-hvs";
++ reg = <0x7e400000 0x6000>;
++ interrupts = <2 1>;
++ };
++
+ i2c1: i2c@7e804000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e804000 0x1000>;
+@@ -226,11 +245,39 @@
+ status = "disabled";
+ };
+
++ pixelvalve@7e807000 {
++ compatible = "brcm,bcm2835-pixelvalve2";
++ reg = <0x7e807000 0x100>;
++ interrupts = <2 10>; /* pixelvalve */
++ };
++
++ hdmi: hdmi@7e902000 {
++ compatible = "brcm,bcm2835-hdmi";
++ reg = <0x7e902000 0x600>,
++ <0x7e808000 0x100>;
++ interrupts = <2 8>, <2 9>;
++ ddc = <&i2c2>;
++ clocks = <&clocks BCM2835_PLLH_PIX>,
++ <&clocks BCM2835_CLOCK_HSM>;
++ clock-names = "pixel", "hdmi";
++ status = "disabled";
++ };
++
+ usb: usb@7e980000 {
+ compatible = "brcm,bcm2835-usb";
+ reg = <0x7e980000 0x10000>;
+ interrupts = <1 9>;
+ };
++
++ v3d: v3d@7ec00000 {
++ compatible = "brcm,bcm2835-v3d";
++ reg = <0x7ec00000 0x1000>;
++ interrupts = <1 10>;
++ };
++
++ vc4: gpu {
++ compatible = "brcm,bcm2835-vc4";
++ };
+ };
+
+ clocks {
+--
+2.7.3
+
+From da77f737f9f5a487f3a1f80f8546585ee18cd7b9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 4 Mar 2016 10:39:28 -0800
+Subject: [PATCH 27/36] dt-bindings: Add root properties for Raspberry Pi 3
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Rob Herring <robh@kernel.org>
+---
+ Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+index 11d3056..6ffe087 100644
+--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+@@ -30,6 +30,10 @@ Raspberry Pi 2 Model B
+ Required root node properties:
+ compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+
++Raspberry Pi 3 Model B
++Required root node properties:
++compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
++
+ Raspberry Pi Compute Module
+ Required root node properties:
+ compatible = "raspberrypi,compute-module", "brcm,bcm2835";
+--
+2.7.3
+
+From b76b1cdf2e569cceab41dcf3b3f6a90965d0a02c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 4 Mar 2016 10:39:29 -0800
+Subject: [PATCH 28/36] ARM: bcm2835: Add devicetree for the Raspberry Pi 3.
+
+For now this doesn't support the new hardware present on the Pi 3 (BT,
+wifi, GPIO expander). Since the GPIO expander isn't supported, we
+also don't have the LEDs like the other board files do.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+---
+ arch/arm/boot/dts/Makefile | 3 +-
+ arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 22 ++++++++++++
+ arch/arm/boot/dts/bcm2837.dtsi | 68 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 92 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+ create mode 100644 arch/arm/boot/dts/bcm2837.dtsi
+
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index d000814..a8a0767 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -64,7 +64,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2835-rpi-b-rev2.dtb \
+ bcm2835-rpi-b-plus.dtb \
+ bcm2835-rpi-a-plus.dtb \
+- bcm2836-rpi-2-b.dtb
++ bcm2836-rpi-2-b.dtb \
++ bcm2837-rpi-3-b.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-asus-rt-ac56u.dtb \
+ bcm4708-asus-rt-ac68u.dtb \
+diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+new file mode 100644
+index 0000000..5e8eafd
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -0,0 +1,22 @@
++/dts-v1/;
++#include "bcm2837.dtsi"
++#include "bcm2835-rpi.dtsi"
++
++/ {
++ compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
++ model = "Raspberry Pi 3 Model B";
++
++ memory {
++ reg = <0 0x40000000>;
++ };
++};
++
++&gpio {
++ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
++
++ /* I2S interface */
++ i2s_alt0: i2s_alt0 {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
++};
+diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi
+new file mode 100644
+index 0000000..2f36722
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2837.dtsi
+@@ -0,0 +1,68 @@
++#include "bcm283x.dtsi"
++
++/ {
++ compatible = "brcm,bcm2836";
++
++ soc {
++ ranges = <0x7e000000 0x3f000000 0x1000000>,
++ <0x40000000 0x40000000 0x00001000>;
++ dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
++
++ local_intc: local_intc {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&local_intc>;
++ };
++ };
++
++ timer {
++ compatible = "arm,armv7-timer";
++ interrupt-parent = <&local_intc>;
++ interrupts = <0>, // PHYS_SECURE_PPI
++ <1>, // PHYS_NONSECURE_PPI
++ <3>, // VIRT_PPI
++ <2>; // HYP_PPI
++ always-on;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <0>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <1>;
++ };
++
++ cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <2>;
++ };
++
++ cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <3>;
++ };
++ };
++};
++
++/* Make the BCM2835-style global interrupt controller be a child of the
++ * CPU-local interrupt controller.
++ */
++&intc {
++ compatible = "brcm,bcm2836-armctrl-ic";
++ reg = <0x7e00b200 0x200>;
++ interrupt-parent = <&local_intc>;
++ interrupts = <8>;
++};
+--
+2.7.3
+
+From 43aa67b7bccfb189a3e57832f08710c98fe707c6 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Sun, 17 Jan 2016 12:15:28 +0000
+Subject: [PATCH 29/36] ARM: bcm2835: follow dt uart node-naming convention
+
+This patch fixes the naming of the device tree node: uart@7e201000
+to conform to the standard of: serial@7e201000
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
+index bbe4eab..31cc2f2 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -113,7 +113,7 @@
+ #interrupt-cells = <2>;
+ };
+
+- uart0: uart@7e201000 {
++ uart0: serial@7e201000 {
+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+ reg = <0x7e201000 0x1000>;
+ interrupts = <2 25>;
+--
+2.7.3
+
+From 72b53a14be5ff0bda535faefa09bc9726acbe1ff Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Sun, 17 Jan 2016 12:15:29 +0000
+Subject: [PATCH 30/36] dt/bindings: serial: bcm2835: add binding documentation
+ for bcm2835-aux-uart
+
+Add binding documentation for the bcm2835-aux-uart driver.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+
+Changelog:
+ V2->V3: fixed naming convention for node
+Acked-by: Rob Herring <robh@kernel.org>
+Acked-by: Eric Anholt <eric@anholt.net>
+---
+ .../bindings/serial/brcm,bcm2835-aux-uart.txt | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
+
+diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
+new file mode 100644
+index 0000000..b5cc629
+--- /dev/null
++++ b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
+@@ -0,0 +1,18 @@
++* BCM2835 AUXILIAR UART
++
++Required properties:
++
++- compatible: "brcm,bcm2835-aux-uart"
++- reg: The base address of the UART register bank.
++- interrupts: A single interrupt specifier.
++- clocks: Clock driving the hardware; used to figure out the baud rate
++ divisor.
++
++Example:
++
++ uart1: serial@7e215040 {
++ compatible = "brcm,bcm2835-aux-uart";
++ reg = <0x7e215040 0x40>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_UART>;
++ };
+--
+2.7.3
+
+From 285a4ac466d3712b50f5c0d29bf5874476f00c30 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Sun, 17 Jan 2016 12:15:30 +0000
+Subject: [PATCH 31/36] serial: bcm2835: add driver for bcm2835-aux-uart
+
+The bcm2835 SOC contains an auxiliary uart, which is very close
+to the ns16550 with some differences.
+
+The big difference is that the uart HW is not using an internal divider
+of 16 but 8, which results in an effictive baud-rate being twice
+the requested baud-rate.
+
+This driver handles this device correctly and handles the difference in
+the HW divider by scaling up the clock by a factor of 2.
+
+The approach to write a separate (wrapper) driver instead of using a
+multiplying clock and "ns16550" as compatibility in the device-tree
+has been recommended by Stephen Warren.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+
+Changelog:
+ V1->V2: made an explicit bcm2835-aux-uart driver
+ not conrolling the settings via DT only
+ V2->V3: added comments on UART capabilities
+ applied recommendations by Stefan Wahren
+ keep registered line-id in bcm2835aux_data
+Acked-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/tty/serial/8250/8250_bcm2835aux.c | 146 ++++++++++++++++++++++++++++++
+ drivers/tty/serial/8250/Kconfig | 24 +++++
+ drivers/tty/serial/8250/Makefile | 1 +
+ 3 files changed, 171 insertions(+)
+ create mode 100644 drivers/tty/serial/8250/8250_bcm2835aux.c
+
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
new file mode 100644
index 0000000..ecf89f1
@@ -2247,3 +3365,250 @@ index b9b9bca..5c1869f 100644
--
2.7.3
+From 528285e99c25249456023d28f521689bf9e9eb8b Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Wed, 30 Mar 2016 09:35:13 +0100
+Subject: [PATCH 32/36] drop usb power domain support for the moment, kills usb
+
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+index caf2707..b1e8145 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -71,10 +71,6 @@
+ status = "okay";
+ };
+
+-&usb {
+- power-domains = <&power RPI_POWER_DOMAIN_USB>;
+-};
+-
+ &v3d {
+ power-domains = <&power RPI_POWER_DOMAIN_V3D>;
+ };
+--
+2.7.3
+
+From 6af83c5ff7f5514f32b1b3fa6d8d7dfe77e3acce Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <stefan.wahren@i2se.com>
+Date: Sun, 17 Jan 2016 14:59:00 +0000
+Subject: [PATCH 33/36] mmc: sdhci-iproc: Clean up platform allocations if
+ shdci init fails
+
+This patch adopts the changes from 475c9e43bfa7 ("mmc: sdhci-bcm2835:
+Clean up platform allocations if sdhci init fails") to sdhci-iproc.
+
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+Acked-by: Scott Branden <sbranden@broadcom.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/sdhci-iproc.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
+index 3b423b0..e22060a 100644
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -213,7 +213,11 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
+ host->caps1 = iproc_host->data->caps1;
+ }
+
+- return sdhci_add_host(host);
++ ret = sdhci_add_host(host);
++ if (ret)
++ goto err;
++
++ return 0;
+
+ err:
+ sdhci_pltfm_free(pdev);
+--
+2.7.3
+
+From 1565145761d5d94991e4763001c9e60c655818f1 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <stefan.wahren@i2se.com>
+Date: Sun, 17 Jan 2016 14:59:01 +0000
+Subject: [PATCH 34/36] mmc: sdhci-iproc: Actually enable the clock
+
+The RPi firmware-based clocks driver can actually disable
+unused clocks, so when switching to use it we ended up losing
+our MMC clock once all devices were probed.
+
+This patch adopts the changes from 1e5a0a9a58e2 ("mmc: sdhci-bcm2835:
+Actually enable the clock") to sdhci-iproc.
+
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+Acked-by: Scott Branden <sbranden@broadcom.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/sdhci-iproc.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
+index e22060a..55bc348 100644
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -207,6 +207,11 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
+ ret = PTR_ERR(pltfm_host->clk);
+ goto err;
+ }
++ ret = clk_prepare_enable(pltfm_host->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to enable host clk\n");
++ goto err;
++ }
+
+ if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
+ host->caps = iproc_host->data->caps;
+@@ -215,10 +220,12 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
+
+ ret = sdhci_add_host(host);
+ if (ret)
+- goto err;
++ goto err_clk;
+
+ return 0;
+
++err_clk:
++ clk_disable_unprepare(pltfm_host->clk);
+ err:
+ sdhci_pltfm_free(pdev);
+ return ret;
+--
+2.7.3
+
+From 49ebf153a97a0840c1e54f934411aceb93bbdee4 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <stefan.wahren@i2se.com>
+Date: Wed, 27 Jan 2016 22:25:40 +0000
+Subject: [PATCH 35/36] mmc: sdhci-iproc: define MMC caps in platform data
+
+This patch moves the definition of the MMC capabilities
+from the probe function into iproc platform data. After
+that we are able to add support for another platform more
+easily.
+
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+Suggested-by: Stephen Warren <swarren@wwwdotorg.org>
+Acked-by: Scott Branden <sbranden@broadcom.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/sdhci-iproc.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
+index 55bc348..cdc6c4a 100644
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -26,6 +26,7 @@ struct sdhci_iproc_data {
+ const struct sdhci_pltfm_data *pdata;
+ u32 caps;
+ u32 caps1;
++ u32 mmc_caps;
+ };
+
+ struct sdhci_iproc_host {
+@@ -165,6 +166,7 @@ static const struct sdhci_iproc_data iproc_data = {
+ .pdata = &sdhci_iproc_pltfm_data,
+ .caps = 0x05E90000,
+ .caps1 = 0x00000064,
++ .mmc_caps = MMC_CAP_1_8V_DDR,
+ };
+
+ static const struct of_device_id sdhci_iproc_of_match[] = {
+@@ -199,8 +201,7 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
+ mmc_of_parse(host->mmc);
+ sdhci_get_of_property(pdev);
+
+- /* Enable EMMC 1/8V DDR capable */
+- host->mmc->caps |= MMC_CAP_1_8V_DDR;
++ host->mmc->caps |= iproc_host->data->mmc_caps;
+
+ pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pltfm_host->clk)) {
+--
+2.7.3
+
+From 208897fb02fa78d06f960916bc3781c8a060ab72 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <stefan.wahren@i2se.com>
+Date: Wed, 27 Jan 2016 22:25:41 +0000
+Subject: [PATCH 36/36] mmc: sdhci-iproc: add bcm2835 support
+
+Scott Branden from Broadcom said that the BCM2835 eMMC IP core is
+very similar to IPROC and share most of the quirks. So use this driver
+instead of separate one.
+
+The sdhci-iproc contains a better workaround for the clock domain
+crossing problem which doesn't need any delays. This results in a
+better write performance.
+
+Btw we get the rid of the SDHCI_CAPABILITIES hack in the sdhci_readl
+function.
+
+Suggested-by: Scott Branden <sbranden@broadcom.com>
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+Acked-by: Eric Anholt <eric@anholt.net>
+Acked-by: Scott Branden <sbranden@broadcom.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/Kconfig | 6 +++---
+ drivers/mmc/host/sdhci-iproc.c | 15 +++++++++++++++
+ 2 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 1526b8a..60de1e4 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -318,15 +318,15 @@ config MMC_SDHCI_F_SDH30
+ If unsure, say N.
+
+ config MMC_SDHCI_IPROC
+- tristate "SDHCI platform support for the iProc SD/MMC Controller"
+- depends on ARCH_BCM_IPROC || COMPILE_TEST
++ tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"
++ depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST
+ depends on MMC_SDHCI_PLTFM
+ default ARCH_BCM_IPROC
+ select MMC_SDHCI_IO_ACCESSORS
+ help
+ This selects the iProc SD/MMC controller.
+
+- If you have an IPROC platform with SD or MMC devices,
++ If you have a BCM2835 or IPROC platform with SD or MMC devices,
+ say Y or M here.
+
+ If unsure, say N.
+diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
+index cdc6c4a..871c92c 100644
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -169,7 +169,22 @@ static const struct sdhci_iproc_data iproc_data = {
+ .mmc_caps = MMC_CAP_1_8V_DDR,
+ };
+
++static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
++ .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
++ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
++ SDHCI_QUIRK_MISSING_CAPS,
++ .ops = &sdhci_iproc_ops,
++};
++
++static const struct sdhci_iproc_data bcm2835_data = {
++ .pdata = &sdhci_bcm2835_pltfm_data,
++ .caps = SDHCI_CAN_VDD_330,
++ .caps1 = 0x00000000,
++ .mmc_caps = 0x00000000,
++};
++
+ static const struct of_device_id sdhci_iproc_of_match[] = {
++ { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
+ { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data },
+ { }
+ };
+--
+2.7.3
+