From df1a50892b8faf073790cfcacb73a81a23a0162a Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Mon, 11 Apr 2016 22:36:23 +0100 Subject: change the means of bcm238x patch set. NFC --- ...Pull-upstream-fixes-plus-iproc-mmc-driver.patch | 4189 +++++++++++++------- 1 file changed, 2777 insertions(+), 1412 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 -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 +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 --- - .../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 +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 +--- + 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. ++ /* 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; ++ } + -+Example: + 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); + -+ 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 = ; - }; - }; ++ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE); + -+&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" ++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, ++ VC4_HDMI_SW_RESET_HDMI | ++ VC4_HDMI_SW_RESET_FORMAT_DETECT); + -+/ { -+ compatible = "raspberrypi,model-a", "brcm,bcm2835"; -+ model = "Raspberry Pi Model A"; ++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0); + -+ leds { -+ act { -+ gpios = <&gpio 16 1>; -+ }; -+ }; -+}; ++ /* 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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)); + -+&gpio { -+ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>; + 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 +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 +--- + 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)); + -+ /* I2S interface */ -+ i2s_alt2: i2s_alt2 { -+ brcm,pins = <28 29 30 31>; -+ brcm,function = ; -+ }; -+}; -+ -+&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 = ; - }; - }; -+ -+&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 = ; - }; - }; -+ -+&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 3afb9fe..b1e8145 100644 ---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi -@@ -1,3 +1,5 @@ -+#include -+ - / { - 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 = ; - }; ++ /* 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"; ++ vc4_state->offset = fb->offsets[0]; + -+ memory { -+ reg = <0 0x40000000>; -+ }; -+}; ++ 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; ++} + -+&gpio { -+ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>; + -+ /* I2S interface */ -+ i2s_alt0: i2s_alt0 { -+ brcm,pins = <28 29 30 31>; -+ brcm,function = ; -+ }; -+}; -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" ++/* 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; + -+/ { -+ compatible = "brcm,bcm2836"; ++ ret = vc4_plane_setup_clipping_and_scaling(state); ++ if (ret) ++ return ret; + -+ soc { -+ ranges = <0x7e000000 0x3f000000 0x1000000>, -+ <0x40000000 0x40000000 0x00001000>; -+ dma-ranges = <0xc0000000 0x00000000 0x3f000000>; + 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 +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 +--- + 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; + -+ local_intc: local_intc { -+ compatible = "brcm,bcm2836-l1-intc"; -+ reg = <0x40000000 0x100>; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ interrupt-parent = <&local_intc>; -+ }; -+ }; + 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 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. */ + +- /* 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. +@@ -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; + -+ 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; -+ }; ++ if (plane != crtc->cursor) ++ goto out; + -+ cpus: cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; ++ plane_state = plane->state; ++ vc4_state = to_vc4_plane_state(plane_state); + -+ cpu0: cpu@0 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a53"; -+ reg = <0>; -+ }; ++ if (!plane_state) ++ goto out; + -+ cpu1: cpu@1 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a53"; -+ reg = <1>; -+ }; ++ /* If we're changing the cursor contents, do that in the ++ * normal vblank-synced atomic path. ++ */ ++ if (fb != plane_state->fb) ++ goto out; + -+ cpu2: cpu@2 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a53"; -+ reg = <2>; -+ }; ++ /* 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; ++ } + -+ cpu3: cpu@3 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a53"; -+ reg = <3>; -+ }; -+ }; -+}; ++ /* 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; + -+/* 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 - #include -+#include -+#include - #include "skeleton.dtsi" - - /* This include file covers the common peripherals and configuration between -@@ -111,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>; -@@ -152,6 +154,18 @@ - status = "disabled"; - }; - -+ pixelvalve@7e206000 { -+ compatible = "brcm,bcm2835-pixelvalve0"; -+ reg = <0x7e206000 0x100>; -+ interrupts = <2 13>; /* pwa0 */ -+ }; ++ /* Allow changing the start position within the cursor BO, if ++ * that matters. ++ */ ++ plane_state->src_x = src_x; ++ plane_state->src_y = src_y; + -+ pixelvalve@7e207000 { -+ compatible = "brcm,bcm2835-pixelvalve1"; -+ reg = <0x7e207000 0x100>; -+ interrupts = <2 14>; /* pwa1 */ -+ }; ++ /* Update the display list based on the new crtc_x/y. */ ++ vc4_plane_atomic_check(plane, plane_state); + - 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"; -+ }; ++ /* 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]); + -+ 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"; -+ }; -+ -+ 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>; -@@ -167,6 +219,12 @@ - status = "disabled"; - }; - -+ hvs@7e400000 { -+ compatible = "brcm,bcm2835-hvs"; -+ reg = <0x7e400000 0x6000>; -+ interrupts = <2 1>; -+ }; -+ - 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 */ -+ }; -+ -+ 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>; -+ }; ++ 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 +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 +--- + 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). ++ 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. + */ -+ 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; -+ } ++ drm_mm_init(&hvs->dlist_mm, ++ HVS_BOOTLOADER_DLIST_END, ++ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END); + - 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; -+ -+ 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 +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 +--- + 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 +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 +--- + 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) +@@ -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); - hvs->dlist = hvs->regs + SCALER_DLIST_START; - -+ 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. */ - -- /* 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; + /* System memory copy of the display list for this element, computed +@@ -47,13 +53,19 @@ 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; -+ * 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_x, src_y, src_w, src_h; + -+ 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]; ++ 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,522 +1520,1649 @@ 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 ? - 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[0], SCALER_POS2_WIDTH) | -+ VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); + VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); - /* 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; -+ if (!format->flip_cbcr) { -+ for (i = 0; i < num_planes; i++) -+ vc4_dlist_write(vc4_state, vc4_state->offsets[i]); -+ } else { -+ WARN_ON_ONCE(num_planes != 3); -+ vc4_dlist_write(vc4_state, vc4_state->offsets[0]); -+ vc4_dlist_write(vc4_state, vc4_state->offsets[2]); -+ vc4_dlist_write(vc4_state, vc4_state->offsets[1]); ++ 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); -- /* Pointer Context Word 0: Written by the HVS */ -- vc4_dlist_write(vc4_state, 0xc0c0c0c0); -+ /* Pointer Context Word 0/1/2: Written by the HVS */ -+ for (i = 0; i < num_planes; i++) -+ vc4_dlist_write(vc4_state, 0xc0c0c0c0); +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 -- /* Pitch word 0: Pointer 0 Pitch */ -- vc4_dlist_write(vc4_state, -- VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); -+ /* Pitch word 0/1/2 */ -+ for (i = 0; i < num_planes; i++) { -+ vc4_dlist_write(vc4_state, -+ VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH)); -+ } ++#define SCALER_CTL0_SCL1_MASK VC4_MASK(10, 8) ++#define SCALER_CTL0_SCL1_SHIFT 8 + -+ /* Colorspace conversion words */ -+ if (vc4_state->is_yuv) { -+ vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); -+ vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5); -+ vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); -+ } ++#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 +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 +--- + 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 +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 +--- + 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(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); + +- /* Pointer Word 0: RGB / Y Pointer */ ++ ++ /* 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_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]); ++ } else { ++ WARN_ON_ONCE(num_planes != 3); ++ vc4_dlist_write(vc4_state, vc4_state->offsets[0]); ++ vc4_dlist_write(vc4_state, vc4_state->offsets[2]); ++ vc4_dlist_write(vc4_state, vc4_state->offsets[1]); ++ } + +- /* Pointer Context Word 0: Written by the HVS */ +- vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ /* Pointer Context Word 0/1/2: Written by the HVS */ ++ for (i = 0; i < num_planes; i++) ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); + +- /* Pitch word 0: Pointer 0 Pitch */ +- vc4_dlist_write(vc4_state, +- VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); ++ /* Pitch word 0/1/2 */ ++ for (i = 0; i < num_planes; i++) { ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH)); ++ } ++ ++ /* Colorspace conversion words */ ++ if (vc4_state->is_yuv) { ++ vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); ++ 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->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_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 ++ * above. ++ */ ++ 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 (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); + +@@ -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)]; ++ u32 num_formats = 0; + int ret = 0; + unsigned i; + +@@ -708,12 +840,20 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, + goto fail; + } + +- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) +- formats[i] = hvs_formats[i].drm; ++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { ++ /* Don't allow YUV in cursor planes, since that means ++ * tuning on the scaler, which we don't allow for the ++ * cursor. ++ */ ++ if (type != DRM_PLANE_TYPE_CURSOR || ++ hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { ++ formats[num_formats++] = hvs_formats[i].drm; ++ } ++ } + plane = &vc4_plane->base; + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, +- formats, ARRAY_SIZE(formats), ++ formats, num_formats, + type, NULL); + + 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 a5b544d..bf42a8e 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -519,7 +519,12 @@ enum hvs_pixel_format { + HVS_PIXEL_FORMAT_RGB888 = 5, + HVS_PIXEL_FORMAT_RGBA6666 = 6, + /* 32bpp */ +- HVS_PIXEL_FORMAT_RGBA8888 = 7 ++ HVS_PIXEL_FORMAT_RGBA8888 = 7, ++ ++ HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE = 8, ++ HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE = 9, ++ HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE = 10, ++ HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE = 11, + }; + + /* Note: the LSB is the rightmost character shown. Only valid for +@@ -601,6 +606,55 @@ enum hvs_pixel_format { + #define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) + #define SCALER_POS2_WIDTH_SHIFT 0 + ++/* Color Space Conversion words. Some values are S2.8 signed ++ * integers, except that the 2 integer bits map as {0x0: 0, 0x1: 1, ++ * 0x2: 2, 0x3: -1} ++ */ ++/* bottom 8 bits of S2.8 contribution of Cr to Blue */ ++#define SCALER_CSC0_COEF_CR_BLU_MASK VC4_MASK(31, 24) ++#define SCALER_CSC0_COEF_CR_BLU_SHIFT 24 ++/* Signed offset to apply to Y before CSC. (Y' = Y + YY_OFS) */ ++#define SCALER_CSC0_COEF_YY_OFS_MASK VC4_MASK(23, 16) ++#define SCALER_CSC0_COEF_YY_OFS_SHIFT 16 ++/* Signed offset to apply to CB before CSC (Cb' = Cb - 128 + CB_OFS). */ ++#define SCALER_CSC0_COEF_CB_OFS_MASK VC4_MASK(15, 8) ++#define SCALER_CSC0_COEF_CB_OFS_SHIFT 8 ++/* Signed offset to apply to CB before CSC (Cr' = Cr - 128 + CR_OFS). */ ++#define SCALER_CSC0_COEF_CR_OFS_MASK VC4_MASK(7, 0) ++#define SCALER_CSC0_COEF_CR_OFS_SHIFT 0 ++#define SCALER_CSC0_ITR_R_601_5 0x00f00000 ++#define SCALER_CSC0_ITR_R_709_3 0x00f00000 ++#define SCALER_CSC0_JPEG_JFIF 0x00000000 ++ ++/* S2.8 contribution of Cb to Green */ ++#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22) ++#define SCALER_CSC1_COEF_CB_GRN_SHIFT 22 ++/* S2.8 contribution of Cr to Green */ ++#define SCALER_CSC1_COEF_CR_GRN_MASK VC4_MASK(21, 12) ++#define SCALER_CSC1_COEF_CR_GRN_SHIFT 12 ++/* S2.8 contribution of Y to all of RGB */ ++#define SCALER_CSC1_COEF_YY_ALL_MASK VC4_MASK(11, 2) ++#define SCALER_CSC1_COEF_YY_ALL_SHIFT 2 ++/* top 2 bits of S2.8 contribution of Cr to Blue */ ++#define SCALER_CSC1_COEF_CR_BLU_MASK VC4_MASK(1, 0) ++#define SCALER_CSC1_COEF_CR_BLU_SHIFT 0 ++#define SCALER_CSC1_ITR_R_601_5 0xe73304a8 ++#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8 ++#define SCALER_CSC1_JPEG_JFIF 0xea34a400 ++ ++/* S2.8 contribution of Cb to Red */ ++#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20) ++#define SCALER_CSC2_COEF_CB_RED_SHIFT 20 ++/* S2.8 contribution of Cr to Red */ ++#define SCALER_CSC2_COEF_CR_RED_MASK VC4_MASK(19, 10) ++#define SCALER_CSC2_COEF_CR_RED_SHIFT 10 ++/* S2.8 contribution of Cb to Blue */ ++#define SCALER_CSC2_COEF_CB_BLU_MASK VC4_MASK(19, 10) ++#define SCALER_CSC2_COEF_CB_BLU_SHIFT 10 ++#define SCALER_CSC2_ITR_R_601_5 0x00066204 ++#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 +-- +2.7.3 + +From 47ed1ee3dbfde89297b81bc09f1b483f4da1b06d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +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 +Tested-by: Daniel Stone +--- + 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 +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 +Tested-by: Daniel Stone +--- + 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; ++ ++ 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; + } ++ ++ 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 +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 +Reviewed-by: Eric Anholt +Signed-off-by: Eric Anholt +--- + 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 +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 +Acked-by: Stephen Warren +--- + 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 ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -268,6 +268,7 @@ static int vc4_v3d_dev_remove(struct platform_device *pdev) + } + + static const struct of_device_id vc4_v3d_dt_match[] = { ++ { .compatible = "brcm,bcm2835-v3d" }, + { .compatible = "brcm,vc4-v3d" }, + {} + }; +-- +2.7.3 + +From 142ad4bd29558b85f269a02b74c5149b514acf88 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +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 +Signed-off-by: Michael Turquette +--- + 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; + +- 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; + ++ 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 +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 +Acked-by: Stephen Warren +[anholt: Rebased on 2835.dtsi -> 283x.dtsi change] +Signed-off-by: Eric Anholt +--- + 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 + #include ++#include + #include "skeleton.dtsi" + + /* 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 +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 +[anholt: Rebased on 2835.dtsi -> 283x.dtsi change] +Signed-off-by: Eric Anholt +--- + 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"; + }; + ++ 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"; ++ }; + -+ if (!vc4_state->is_unity) { -+ /* LBM Base Address. */ -+ 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); -+ } + 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 +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 +Acked-by: Stephen Warren +[anholt: Rebased on bcm2835.dtsi -> bcm283x.dtsi change] +Signed-off-by: Eric Anholt +--- + 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" + -+ if (num_planes > 1) { -+ /* Emit Cb/Cr as channel 0 and Y as channel -+ * 1. This matches how we set up scl0/scl1 -+ * above. -+ */ -+ vc4_write_scaling_parameters(state, 1); -+ } -+ vc4_write_scaling_parameters(state, 0); ++/ { ++ compatible = "raspberrypi,model-a", "brcm,bcm2835"; ++ model = "Raspberry Pi Model A"; + -+ /* If any PPF setup was done, then all the kernel -+ * pointers get uploaded. -+ */ -+ 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); ++ leds { ++ act { ++ gpios = <&gpio 16 1>; ++ }; ++ }; ++}; + -+ /* 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]); - - /* 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; ++&gpio { ++ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>; + -+ if (plane != crtc->cursor) -+ goto out; ++ /* I2S interface */ ++ i2s_alt2: i2s_alt2 { ++ brcm,pins = <28 29 30 31>; ++ brcm,function = ; ++ }; ++}; +-- +2.7.3 + +From f6fd06c97f0d6d8398b8caba1b6879fa7e0284ba Mon Sep 17 00:00:00 2001 +From: Alexander Aring +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 +Signed-off-by: Eric Anholt +Reviewed-by: Kevin Hilman +--- + 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 + -+ plane_state = plane->state; -+ vc4_state = to_vc4_plane_state(plane_state); + / { + memory { + reg = <0 0x10000000>; +@@ -18,6 +20,12 @@ + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; + }; + -+ if (!plane_state) -+ goto out; ++ power: power { ++ compatible = "raspberrypi,bcm2835-power"; ++ firmware = <&firmware>; ++ #power-domain-cells = <1>; ++ }; + }; + }; + +@@ -62,3 +70,7 @@ + &pwm { + status = "okay"; + }; + -+ /* If we're changing the cursor contents, do that in the -+ * normal vblank-synced atomic path. -+ */ -+ if (fb != plane_state->fb) -+ goto out; ++&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"; + }; + +- 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 +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 +Signed-off-by: Eric Anholt +--- + 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>; + }; + ++ uart1: serial@7e215040 { ++ compatible = "brcm,bcm2835-aux-uart"; ++ reg = <0x7e215040 0x40>; ++ interrupts = <1 29>; ++ clocks = <&aux BCM2835_AUX_CLOCK_UART>; ++ 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; -+ } + 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 +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 +--- + 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 = ; + }; + }; + -+ /* 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; ++&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 = ; + }; + }; + -+ /* 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 { ++ 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 = ; + }; + }; + -+ /* Update the display list based on the new crtc_x/y. */ -+ vc4_plane_atomic_check(plane, plane_state); ++&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 = ; + }; + }; + -+ /* 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]); ++&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>; + }; + -+ return 0; ++&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>; + }; + -+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); -+} ++&v3d { ++ power-domains = <&power RPI_POWER_DOMAIN_V3D>; ++}; + - 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, - struct drm_plane *plane = NULL; - struct vc4_plane *vc4_plane; - u32 formats[ARRAY_SIZE(hvs_formats)]; -+ u32 num_formats = 0; - int ret = 0; - unsigned i; - -@@ -351,12 +840,20 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, - goto fail; - } - -- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) -- formats[i] = hvs_formats[i].drm; -+ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { -+ /* Don't allow YUV in cursor planes, since that means -+ * tuning on the scaler, which we don't allow for the -+ * cursor. -+ */ -+ if (type != DRM_PLANE_TYPE_CURSOR || -+ hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { -+ formats[num_formats++] = hvs_formats[i].drm; -+ } -+ } - plane = &vc4_plane->base; - ret = drm_universal_plane_init(dev, plane, 0xff, - &vc4_plane_funcs, -- formats, ARRAY_SIZE(formats), -+ formats, num_formats, - type, NULL); ++&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 = ; + }; + }; ++ ++&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 + #include + #include ++#include + #include "skeleton.dtsi" - 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 ---- 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) + /* This include file covers the common peripherals and configuration between +@@ -153,6 +154,18 @@ + status = "disabled"; + }; --#define PV_VSYNCD 0x08 -+#define PV_VSYNCD_EVEN 0x08 ++ pixelvalve@7e206000 { ++ compatible = "brcm,bcm2835-pixelvalve0"; ++ reg = <0x7e206000 0x100>; ++ interrupts = <2 13>; /* pwa0 */ ++ }; ++ ++ 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"; + }; - #define PV_HORZA 0x0c - # define PV_HORZA_HBP_MASK VC4_MASK(31, 16) -@@ -350,6 +350,17 @@ - # define SCALER_DISPCTRLX_HEIGHT_SHIFT 0 ++ 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"; + }; - #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) ++ pixelvalve@7e807000 { ++ compatible = "brcm,bcm2835-pixelvalve2"; ++ reg = <0x7e807000 0x100>; ++ interrupts = <2 10>; /* pixelvalve */ ++ }; + - #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 ++ 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"; ++ }; + }; - #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) + clocks { +-- +2.7.3 + +From da77f737f9f5a487f3a1f80f8546585ee18cd7b9 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +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 +Acked-by: Rob Herring +--- + 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"; -@@ -503,7 +519,12 @@ enum hvs_pixel_format { - HVS_PIXEL_FORMAT_RGB888 = 5, - HVS_PIXEL_FORMAT_RGBA6666 = 6, - /* 32bpp */ -- HVS_PIXEL_FORMAT_RGBA8888 = 7 -+ HVS_PIXEL_FORMAT_RGBA8888 = 7, ++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 +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 +Acked-by: Stephen Warren +--- + 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" + -+ HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE = 8, -+ HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE = 9, -+ HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE = 10, -+ HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE = 11, - }; - - /* 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 ++/ { ++ compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; ++ model = "Raspberry Pi 3 Model B"; + -+#define SCALER_CTL0_SCL0_MASK VC4_MASK(7, 5) -+#define SCALER_CTL0_SCL0_SHIFT 5 ++ memory { ++ reg = <0 0x40000000>; ++ }; ++}; + -+#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 ++&gpio { ++ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>; + - /* 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 ++ /* I2S interface */ ++ i2s_alt0: i2s_alt0 { ++ brcm,pins = <28 29 30 31>; ++ brcm,function = ; ++ }; ++}; +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" + -+#define SCALER_POS1_SCL_WIDTH_MASK VC4_MASK(11, 0) -+#define SCALER_POS1_SCL_WIDTH_SHIFT 0 ++/ { ++ compatible = "brcm,bcm2836"; + - #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 { - #define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) - #define SCALER_POS2_WIDTH_SHIFT 0 - -+/* Color Space Conversion words. Some values are S2.8 signed -+ * integers, except that the 2 integer bits map as {0x0: 0, 0x1: 1, -+ * 0x2: 2, 0x3: -1} -+ */ -+/* bottom 8 bits of S2.8 contribution of Cr to Blue */ -+#define SCALER_CSC0_COEF_CR_BLU_MASK VC4_MASK(31, 24) -+#define SCALER_CSC0_COEF_CR_BLU_SHIFT 24 -+/* Signed offset to apply to Y before CSC. (Y' = Y + YY_OFS) */ -+#define SCALER_CSC0_COEF_YY_OFS_MASK VC4_MASK(23, 16) -+#define SCALER_CSC0_COEF_YY_OFS_SHIFT 16 -+/* Signed offset to apply to CB before CSC (Cb' = Cb - 128 + CB_OFS). */ -+#define SCALER_CSC0_COEF_CB_OFS_MASK VC4_MASK(15, 8) -+#define SCALER_CSC0_COEF_CB_OFS_SHIFT 8 -+/* Signed offset to apply to CB before CSC (Cr' = Cr - 128 + CR_OFS). */ -+#define SCALER_CSC0_COEF_CR_OFS_MASK VC4_MASK(7, 0) -+#define SCALER_CSC0_COEF_CR_OFS_SHIFT 0 -+#define SCALER_CSC0_ITR_R_601_5 0x00f00000 -+#define SCALER_CSC0_ITR_R_709_3 0x00f00000 -+#define SCALER_CSC0_JPEG_JFIF 0x00000000 ++ soc { ++ ranges = <0x7e000000 0x3f000000 0x1000000>, ++ <0x40000000 0x40000000 0x00001000>; ++ dma-ranges = <0xc0000000 0x00000000 0x3f000000>; + -+/* S2.8 contribution of Cb to Green */ -+#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22) -+#define SCALER_CSC1_COEF_CB_GRN_SHIFT 22 -+/* S2.8 contribution of Cr to Green */ -+#define SCALER_CSC1_COEF_CR_GRN_MASK VC4_MASK(21, 12) -+#define SCALER_CSC1_COEF_CR_GRN_SHIFT 12 -+/* S2.8 contribution of Y to all of RGB */ -+#define SCALER_CSC1_COEF_YY_ALL_MASK VC4_MASK(11, 2) -+#define SCALER_CSC1_COEF_YY_ALL_SHIFT 2 -+/* top 2 bits of S2.8 contribution of Cr to Blue */ -+#define SCALER_CSC1_COEF_CR_BLU_MASK VC4_MASK(1, 0) -+#define SCALER_CSC1_COEF_CR_BLU_SHIFT 0 -+#define SCALER_CSC1_ITR_R_601_5 0xe73304a8 -+#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8 -+#define SCALER_CSC1_JPEG_JFIF 0xea34a400 ++ local_intc: local_intc { ++ compatible = "brcm,bcm2836-l1-intc"; ++ reg = <0x40000000 0x100>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-parent = <&local_intc>; ++ }; ++ }; + -+/* S2.8 contribution of Cb to Red */ -+#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20) -+#define SCALER_CSC2_COEF_CB_RED_SHIFT 20 -+/* S2.8 contribution of Cr to Red */ -+#define SCALER_CSC2_COEF_CR_RED_MASK VC4_MASK(19, 10) -+#define SCALER_CSC2_COEF_CR_RED_SHIFT 10 -+/* S2.8 contribution of Cb to Blue */ -+#define SCALER_CSC2_COEF_CB_BLU_MASK VC4_MASK(19, 10) -+#define SCALER_CSC2_COEF_CB_BLU_SHIFT 10 -+#define SCALER_CSC2_ITR_R_601_5 0x00066204 -+#define SCALER_CSC2_ITR_R_709_3 0x00072a1c -+#define SCALER_CSC2_JPEG_JFIF 0x000599c5 ++ 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; ++ }; + -+#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 ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <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 ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <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) ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <1>; ++ }; + - #define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0) - #define SCALER_SRC_PITCH_SHIFT 0 - -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 -+++ b/drivers/gpu/drm/vc4/vc4_v3d.c -@@ -268,6 +268,7 @@ static int vc4_v3d_dev_remove(struct platform_device *pdev) - } - - static const struct of_device_id vc4_v3d_dt_match[] = { -+ { .compatible = "brcm,bcm2835-v3d" }, - { .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. - - 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 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; - }; - - 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, ++ 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 +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 +--- + 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 +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 + +Changelog: + V2->V3: fixed naming convention for node +Acked-by: Rob Herring +Acked-by: Eric Anholt +--- + .../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 + -+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, -+}; ++Required properties: + -+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 }, - { } - }; -@@ -199,22 +216,32 @@ 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)) { - 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; - host->caps1 = iproc_host->data->caps1; - } - -- return sdhci_add_host(host); -+ ret = sdhci_add_host(host); -+ if (ret) -+ goto err_clk; ++- 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. + -+ return 0; - -+err_clk: -+ clk_disable_unprepare(pltfm_host->clk); - err: - sdhci_pltfm_free(pdev); - return ret; ++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 +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 + +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 +--- + 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 +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 +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 +Acked-by: Scott Branden +Signed-off-by: Ulf Hansson +--- + 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 +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 +Acked-by: Scott Branden +Signed-off-by: Ulf Hansson +--- + 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 +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 +Suggested-by: Stephen Warren +Acked-by: Scott Branden +Acked-by: Stephen Warren +Signed-off-by: Ulf Hansson +--- + 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 +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 +Signed-off-by: Stefan Wahren +Acked-by: Eric Anholt +Acked-by: Scott Branden +Acked-by: Stephen Warren +Signed-off-by: Ulf Hansson +--- + 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 + -- cgit