summaryrefslogtreecommitdiffstats
path: root/freed-ora
diff options
context:
space:
mode:
Diffstat (limited to 'freed-ora')
-rw-r--r--freed-ora/current/f24/ALSA-usb-audio-Add-sanity-checks-for-endpoint-access.patch80
-rw-r--r--freed-ora/current/f24/ALSA-usb-audio-Fix-NULL-dereference-in-create_fixed_.patch40
-rw-r--r--freed-ora/current/f24/USB-input-powermate-fix-oops-with-malicious-USB-desc.patch38
-rw-r--r--freed-ora/current/f24/USB-iowarrior-fix-oops-with-malicious-USB-descriptor.patch40
-rw-r--r--freed-ora/current/f24/bcm283x-add-aux-uart-support-extra-DT-bits-initial-r.patch2155
-rw-r--r--freed-ora/current/f24/cdc-acm-more-sanity-checking.patch33
-rw-r--r--freed-ora/current/f24/config-armv742
-rw-r--r--freed-ora/current/f24/config-armv7-generic13
-rw-r--r--freed-ora/current/f24/cypress_m8-add-sanity-checking.patch50
-rw-r--r--freed-ora/current/f24/digi_acceleport-do-sanity-checking-for-the-number-of.patch34
-rw-r--r--freed-ora/current/f24/geekbox-v4-device-tree-support.patch (renamed from freed-ora/current/f24/Geekbox-device-tree-support.patch)77
-rw-r--r--freed-ora/current/f24/ims-pcu-sanity-check-against-missing-interfaces.patch39
-rw-r--r--freed-ora/current/f24/ipv4-Dont-do-expensive-useless-work-during-inetdev-des.patch97
-rw-r--r--freed-ora/current/f24/kernel.spec63
-rw-r--r--freed-ora/current/f24/revert-stmmac-Fix-eth0-No-PHY-found-regression.patch87
-rw-r--r--freed-ora/current/f24/stmmac-fix-MDIO-settings.patch235
-rw-r--r--freed-ora/current/f24/usb_driver_claim_interface-add-sanity-checking.patch39
17 files changed, 3088 insertions, 74 deletions
diff --git a/freed-ora/current/f24/ALSA-usb-audio-Add-sanity-checks-for-endpoint-access.patch b/freed-ora/current/f24/ALSA-usb-audio-Add-sanity-checks-for-endpoint-access.patch
new file mode 100644
index 000000000..801434a26
--- /dev/null
+++ b/freed-ora/current/f24/ALSA-usb-audio-Add-sanity-checks-for-endpoint-access.patch
@@ -0,0 +1,80 @@
+From 873156565ca67779bbf5a3475ccd08ea3bb92522 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 15 Mar 2016 15:20:58 +0100
+Subject: [PATCH 2/2] ALSA: usb-audio: Add sanity checks for endpoint accesses
+
+Add some sanity check codes before actually accessing the endpoint via
+get_endpoint() in order to avoid the invalid access through a
+malformed USB descriptor. Mostly just checking bNumEndpoints, but in
+one place (snd_microii_spdif_default_get()), the validity of iface and
+altsetting index is checked as well.
+
+Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=971125
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/usb/clock.c | 2 ++
+ sound/usb/endpoint.c | 3 +++
+ sound/usb/mixer_quirks.c | 4 ++++
+ sound/usb/pcm.c | 2 ++
+ 4 files changed, 11 insertions(+)
+
+diff --git a/sound/usb/clock.c b/sound/usb/clock.c
+index 2ed260b10f6d..7ccbcaf6a147 100644
+--- a/sound/usb/clock.c
++++ b/sound/usb/clock.c
+@@ -285,6 +285,8 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
+ unsigned char data[3];
+ int err, crate;
+
++ if (get_iface_desc(alts)->bNumEndpoints < 1)
++ return -EINVAL;
+ ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+ /* if endpoint doesn't have sampling rate control, bail out */
+diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
+index e6f71894ecdc..c2131b851602 100644
+--- a/sound/usb/endpoint.c
++++ b/sound/usb/endpoint.c
+@@ -415,6 +415,9 @@ exit_clear:
+ *
+ * New endpoints will be added to chip->ep_list and must be freed by
+ * calling snd_usb_endpoint_free().
++ *
++ * For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that
++ * bNumEndpoints > 1 beforehand.
+ */
+ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
+index d3608c0a29f3..2d724e3c4cc0 100644
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -1518,7 +1518,11 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
+
+ /* use known values for that card: interface#1 altsetting#1 */
+ iface = usb_ifnum_to_if(chip->dev, 1);
++ if (!iface || iface->num_altsetting < 2)
++ return -EINVAL;
+ alts = &iface->altsetting[1];
++ if (get_iface_desc(alts)->bNumEndpoints < 1)
++ return -EINVAL;
+ ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+ err = snd_usb_ctl_msg(chip->dev,
+diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
+index cdac5179db3f..4da64896df6d 100644
+--- a/sound/usb/pcm.c
++++ b/sound/usb/pcm.c
+@@ -159,6 +159,8 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
+ unsigned char data[1];
+ int err;
+
++ if (get_iface_desc(alts)->bNumEndpoints < 1)
++ return -EINVAL;
+ ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+ data[0] = 1;
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/ALSA-usb-audio-Fix-NULL-dereference-in-create_fixed_.patch b/freed-ora/current/f24/ALSA-usb-audio-Fix-NULL-dereference-in-create_fixed_.patch
new file mode 100644
index 000000000..37cdb213a
--- /dev/null
+++ b/freed-ora/current/f24/ALSA-usb-audio-Fix-NULL-dereference-in-create_fixed_.patch
@@ -0,0 +1,40 @@
+From b0bb5691b38e2f439b071e226bad9f699c33b77d Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 15 Mar 2016 12:09:10 +0100
+Subject: [PATCH 1/2] ALSA: usb-audio: Fix NULL dereference in
+ create_fixed_stream_quirk()
+
+create_fixed_stream_quirk() may cause a NULL-pointer dereference by
+accessing the non-existing endpoint when a USB device with a malformed
+USB descriptor is used.
+
+This patch avoids it simply by adding a sanity check of bNumEndpoints
+before the accesses.
+
+Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=971125
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/usb/quirks.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index eef9b8e4b949..e128ca62eb44 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -177,6 +177,12 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
+ }
+ alts = &iface->altsetting[fp->altset_idx];
+ altsd = get_iface_desc(alts);
++ if (altsd->bNumEndpoints < 1) {
++ kfree(fp);
++ kfree(rate_table);
++ return -EINVAL;
++ }
++
+ fp->protocol = altsd->bInterfaceProtocol;
+
+ if (fp->datainterval == 0)
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/USB-input-powermate-fix-oops-with-malicious-USB-desc.patch b/freed-ora/current/f24/USB-input-powermate-fix-oops-with-malicious-USB-desc.patch
new file mode 100644
index 000000000..7de890e1b
--- /dev/null
+++ b/freed-ora/current/f24/USB-input-powermate-fix-oops-with-malicious-USB-desc.patch
@@ -0,0 +1,38 @@
+From 0383ff3ba89d3e6c604138e3ba46685621d71f98 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@fedoraproject.org>
+Date: Mon, 14 Mar 2016 10:02:51 -0400
+Subject: [PATCH] USB: input: powermate: fix oops with malicious USB
+ descriptors
+
+The powermate driver expects at least one valid USB endpoint in its
+probe function. If given malicious descriptors that specify 0 for
+the number of endpoints, it will crash. Validate the number of
+endpoints on the interface before using them.
+
+The full report for this issue can be found here:
+http://seclists.org/bugtraq/2016/Mar/85
+
+Reported-by: Ralf Spenneberg <ralf@spenneberg.net>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
+---
+ drivers/input/misc/powermate.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
+index 63b539d3daba..84909a12ff36 100644
+--- a/drivers/input/misc/powermate.c
++++ b/drivers/input/misc/powermate.c
+@@ -307,6 +307,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
+ int error = -ENOMEM;
+
+ interface = intf->cur_altsetting;
++ if (interface->desc.bNumEndpoints < 1)
++ return -EINVAL;
++
+ endpoint = &interface->endpoint[0].desc;
+ if (!usb_endpoint_is_int_in(endpoint))
+ return -EIO;
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/USB-iowarrior-fix-oops-with-malicious-USB-descriptor.patch b/freed-ora/current/f24/USB-iowarrior-fix-oops-with-malicious-USB-descriptor.patch
new file mode 100644
index 000000000..7df3af2b1
--- /dev/null
+++ b/freed-ora/current/f24/USB-iowarrior-fix-oops-with-malicious-USB-descriptor.patch
@@ -0,0 +1,40 @@
+From 3620ebad64a327113bed34edefd45c3605086fc6 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@fedoraproject.org>
+Date: Mon, 14 Mar 2016 10:38:31 -0400
+Subject: [PATCH] USB: iowarrior: fix oops with malicious USB descriptors
+
+The iowarrior driver expects at least one valid endpoint. If given
+malicious descriptors that specify 0 for the number of endpoints,
+it will crash in the probe function. Ensure there is at least
+one endpoint on the interface before using it.
+
+The full report of this issue can be found here:
+http://seclists.org/bugtraq/2016/Mar/87
+
+Reported-by: Ralf Spenneberg <ralf@spenneberg.net>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
+---
+ drivers/usb/misc/iowarrior.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
+index c6bfd13f6c92..1950e87b4219 100644
+--- a/drivers/usb/misc/iowarrior.c
++++ b/drivers/usb/misc/iowarrior.c
+@@ -787,6 +787,12 @@ static int iowarrior_probe(struct usb_interface *interface,
+ iface_desc = interface->cur_altsetting;
+ dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
+
++ if (iface_desc->desc.bNumEndpoints < 1) {
++ dev_err(&interface->dev, "Invalid number of endpoints\n");
++ retval = -EINVAL;
++ goto error;
++ }
++
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/bcm283x-add-aux-uart-support-extra-DT-bits-initial-r.patch b/freed-ora/current/f24/bcm283x-add-aux-uart-support-extra-DT-bits-initial-r.patch
new file mode 100644
index 000000000..beaa6bd0f
--- /dev/null
+++ b/freed-ora/current/f24/bcm283x-add-aux-uart-support-extra-DT-bits-initial-r.patch
@@ -0,0 +1,2155 @@
+From 59fb5b800868d984e836ab4a38d8ba1598dc675a Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Fri, 18 Mar 2016 19:18:51 +0000
+Subject: [PATCH] bcm283x: add aux uart support, extra DT bits, initial rpi3,
+ VC4 fixes and VC4 DT bindings
+
+---
+ .../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 | 25 +
+ 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/tty/serial/8250/8250_bcm2835aux.c | 146 +++++
+ drivers/tty/serial/8250/Kconfig | 24 +
+ drivers/tty/serial/8250/Makefile | 1 +
+ 26 files changed, 1365 insertions(+), 122 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
+
+diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+index 11d3056..6ffe087 100644
+--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+@@ -30,6 +30,10 @@ Raspberry Pi 2 Model B
+ Required root node properties:
+ compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+
++Raspberry Pi 3 Model B
++Required root node properties:
++compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
++
+ Raspberry Pi Compute Module
+ Required root node properties:
+ compatible = "raspberrypi,compute-module", "brcm,bcm2835";
+diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
+new file mode 100644
+index 0000000..b5cc629
+--- /dev/null
++++ b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt
+@@ -0,0 +1,18 @@
++* BCM2835 AUXILIAR UART
++
++Required properties:
++
++- compatible: "brcm,bcm2835-aux-uart"
++- reg: The base address of the UART register bank.
++- interrupts: A single interrupt specifier.
++- clocks: Clock driving the hardware; used to figure out the baud rate
++ divisor.
++
++Example:
++
++ uart1: serial@7e215040 {
++ compatible = "brcm,bcm2835-aux-uart";
++ reg = <0x7e215040 0x40>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_UART>;
++ };
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index a4a6d70..a8a0767 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -60,10 +60,12 @@ dtb-$(CONFIG_ARCH_AXXIA) += \
+ axm5516-amarillo.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2835-rpi-b.dtb \
++ bcm2835-rpi-a.dtb \
+ bcm2835-rpi-b-rev2.dtb \
+ bcm2835-rpi-b-plus.dtb \
+ bcm2835-rpi-a-plus.dtb \
+- bcm2836-rpi-2-b.dtb
++ bcm2836-rpi-2-b.dtb \
++ bcm2837-rpi-3-b.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-asus-rt-ac56u.dtb \
+ bcm4708-asus-rt-ac68u.dtb \
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+index 228614f..35ff4e7a 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+@@ -29,3 +29,7 @@
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+new file mode 100644
+index 0000000..306a84e
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+@@ -0,0 +1,28 @@
++/dts-v1/;
++#include "bcm2835.dtsi"
++#include "bcm2835-rpi.dtsi"
++
++/ {
++ compatible = "raspberrypi,model-a", "brcm,bcm2835";
++ model = "Raspberry Pi Model A";
++
++ leds {
++ act {
++ gpios = <&gpio 16 1>;
++ };
++ };
++};
++
++&gpio {
++ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>;
++
++ /* I2S interface */
++ i2s_alt2: i2s_alt2 {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
++};
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+index ef54050..57d313b 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+@@ -29,3 +29,7 @@
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+index 86f1f2f..cf2774e 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+@@ -22,3 +22,7 @@
+ brcm,function = <BCM2835_FSEL_ALT2>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+index 4859e9d..8b15f9c 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+@@ -16,3 +16,7 @@
+ &gpio {
+ pinctrl-0 = <&gpioout &alt0 &alt3>;
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++};
+diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+index 3afb9fe..40510df 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -1,3 +1,5 @@
++#include <dt-bindings/power/raspberrypi-power.h>
++
+ / {
+ memory {
+ reg = <0 0x10000000>;
+@@ -18,6 +20,12 @@
+ compatible = "raspberrypi,bcm2835-firmware";
+ mboxes = <&mailbox>;
+ };
++
++ power: power {
++ compatible = "raspberrypi,bcm2835-power";
++ firmware = <&firmware>;
++ #power-domain-cells = <1>;
++ };
+ };
+ };
+
+@@ -58,3 +66,20 @@
+ status = "okay";
+ bus-width = <4>;
+ };
++
++&usb {
++ power-domains = <&power RPI_POWER_DOMAIN_USB>;
++};
++
++&pwm {
++ status = "okay";
++};
++
++&v3d {
++ power-domains = <&power RPI_POWER_DOMAIN_V3D>;
++};
++
++&hdmi {
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
++};
+diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+index ff94666..c4743f4 100644
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -33,3 +33,7 @@
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+ };
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
+diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+new file mode 100644
+index 0000000..5e8eafd
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -0,0 +1,22 @@
++/dts-v1/;
++#include "bcm2837.dtsi"
++#include "bcm2835-rpi.dtsi"
++
++/ {
++ compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
++ model = "Raspberry Pi 3 Model B";
++
++ memory {
++ reg = <0 0x40000000>;
++ };
++};
++
++&gpio {
++ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
++
++ /* I2S interface */
++ i2s_alt0: i2s_alt0 {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
++};
+diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi
+new file mode 100644
+index 0000000..2f36722
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2837.dtsi
+@@ -0,0 +1,68 @@
++#include "bcm283x.dtsi"
++
++/ {
++ compatible = "brcm,bcm2836";
++
++ soc {
++ ranges = <0x7e000000 0x3f000000 0x1000000>,
++ <0x40000000 0x40000000 0x00001000>;
++ dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
++
++ local_intc: local_intc {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&local_intc>;
++ };
++ };
++
++ timer {
++ compatible = "arm,armv7-timer";
++ interrupt-parent = <&local_intc>;
++ interrupts = <0>, // PHYS_SECURE_PPI
++ <1>, // PHYS_NONSECURE_PPI
++ <3>, // VIRT_PPI
++ <2>; // HYP_PPI
++ always-on;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <0>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <1>;
++ };
++
++ cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <2>;
++ };
++
++ cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <3>;
++ };
++ };
++};
++
++/* Make the BCM2835-style global interrupt controller be a child of the
++ * CPU-local interrupt controller.
++ */
++&intc {
++ compatible = "brcm,bcm2836-armctrl-ic";
++ reg = <0x7e00b200 0x200>;
++ interrupt-parent = <&local_intc>;
++ interrupts = <8>;
++};
+diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
+index 971e741..31cc2f2 100644
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -1,5 +1,7 @@
+ #include <dt-bindings/pinctrl/bcm2835.h>
+ #include <dt-bindings/clock/bcm2835.h>
++#include <dt-bindings/clock/bcm2835-aux.h>
++#include <dt-bindings/gpio/gpio.h>
+ #include "skeleton.dtsi"
+
+ /* 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 */
++ };
++
++ pixelvalve@7e207000 {
++ compatible = "brcm,bcm2835-pixelvalve1";
++ reg = <0x7e207000 0x100>;
++ interrupts = <2 14>; /* pwa1 */
++ };
++
+ 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";
++ };
++
++ 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>;
++ };
++
++ 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);
++
++ 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.
+ */
+diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
+index 018145e..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 {
+ /* Which HVS channel we're using for our CRTC. */
+ int channel;
+
+- /* Pointer to the actual hardware display list memory for the
+- * crtc.
+- */
+- u32 __iomem *dlist;
+-
+- u32 dlist_size; /* in dwords */
+-
+ struct drm_pending_vblank_event *event;
+ };
+
++struct vc4_crtc_state {
++ struct drm_crtc_state base;
++ /* Dlist area for this CRTC configuration. */
++ struct drm_mm_node mm;
++};
++
+ static inline struct vc4_crtc *
+ to_vc4_crtc(struct drm_crtc *crtc)
+ {
+ return (struct vc4_crtc *)crtc;
+ }
+
++static inline struct vc4_crtc_state *
++to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
++{
++ return (struct vc4_crtc_state *)crtc_state;
++}
++
+ 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)
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+ struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_plane *plane;
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ unsigned long flags;
+ u32 dlist_count = 0;
++ int ret;
+
+ /* 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,
+
+ dlist_count++; /* Account for SCALER_CTL0_END. */
+
+- if (!vc4_crtc->dlist || dlist_count > vc4_crtc->dlist_size) {
+- vc4_crtc->dlist = ((u32 __iomem *)vc4->hvs->dlist +
+- HVS_BOOTLOADER_DLIST_END);
+- vc4_crtc->dlist_size = ((SCALER_DLIST_SIZE >> 2) -
+- HVS_BOOTLOADER_DLIST_END);
+-
+- if (dlist_count > vc4_crtc->dlist_size) {
+- DRM_DEBUG_KMS("dlist too large for CRTC (%d > %d).\n",
+- dlist_count, vc4_crtc->dlist_size);
+- return -EINVAL;
+- }
+- }
++ spin_lock_irqsave(&vc4->hvs->mm_lock, flags);
++ ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm,
++ dlist_count, 1, 0);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags);
++ if (ret)
++ return ret;
+
+ return 0;
+ }
+@@ -368,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);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
+ struct drm_plane *plane;
+ bool debug_dump_regs = false;
+- u32 __iomem *dlist_next = vc4_crtc->dlist;
++ u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
++ u32 __iomem *dlist_next = dlist_start;
+
+ if (debug_dump_regs) {
+ DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
+ vc4_hvs_dump_state(dev);
+ }
+
+- /* Copy all the active planes' dlist contents to the hardware dlist.
+- *
+- * XXX: If the new display list was large enough that it
+- * overlapped a currently-read display list, we need to do
+- * something like disable scanout before putting in the new
+- * list. For now, we're safe because we only have the two
+- * planes.
+- */
++ /* Copy all the active planes' dlist contents to the hardware dlist. */
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ dlist_next += vc4_plane_write_dlist(plane, dlist_next);
+ }
+
+- if (dlist_next == vc4_crtc->dlist) {
+- /* If no planes were enabled, use the SCALER_CTL0_END
+- * at the start of the display list memory (in the
+- * bootloader section). We'll rewrite that
+- * SCALER_CTL0_END, just in case, though.
+- */
+- writel(SCALER_CTL0_END, vc4->hvs->dlist);
+- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), 0);
+- } else {
+- writel(SCALER_CTL0_END, dlist_next);
+- dlist_next++;
+-
+- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
+- (u32 __iomem *)vc4_crtc->dlist -
+- (u32 __iomem *)vc4->hvs->dlist);
+-
+- /* Make the next display list start after ours. */
+- vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist);
+- vc4_crtc->dlist = dlist_next;
+- }
++ writel(SCALER_CTL0_END, dlist_next);
++ dlist_next++;
++
++ WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
++
++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
++ vc4_state->mm.start);
+
+ 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,
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags);
+ }
+
++static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
++{
++ struct vc4_crtc_state *vc4_state;
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return NULL;
++
++ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
++ return &vc4_state->base;
++}
++
++static void vc4_crtc_destroy_state(struct drm_crtc *crtc,
++ struct drm_crtc_state *state)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(crtc->dev);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++
++ if (vc4_state->mm.allocated) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&vc4->hvs->mm_lock, flags);
++ drm_mm_remove_node(&vc4_state->mm);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags);
++
++ }
++
++ __drm_atomic_helper_crtc_destroy_state(crtc, state);
++}
++
+ 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 = {
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+ .reset = drm_atomic_helper_crtc_reset,
+- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
++ .atomic_duplicate_state = vc4_crtc_duplicate_state,
++ .atomic_destroy_state = vc4_crtc_destroy_state,
+ };
+
+ 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
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -154,7 +154,17 @@ struct vc4_v3d {
+ struct vc4_hvs {
+ struct platform_device *pdev;
+ void __iomem *regs;
+- void __iomem *dlist;
++ u32 __iomem *dlist;
++
++ /* Memory manager for CRTCs to allocate space in the display
++ * 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);
+
+ 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;
+ }
+
++ /* 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;
++ }
++
+ 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;
+ }
++
++ hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
+ }
+
+ 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);
++
++ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE);
++
++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL,
++ VC4_HDMI_SW_RESET_HDMI |
++ VC4_HDMI_SW_RESET_FORMAT_DETECT);
++
++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0);
++
++ /* 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_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
+index 8098c5b..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)
+ }
+ #endif
+
++/* The filter kernel is composed of dwords each containing 3 9-bit
++ * signed integers packed next to each other.
++ */
++#define VC4_INT_TO_COEFF(coeff) (coeff & 0x1ff)
++#define VC4_PPF_FILTER_WORD(c0, c1, c2) \
++ ((((c0) & 0x1ff) << 0) | \
++ (((c1) & 0x1ff) << 9) | \
++ (((c2) & 0x1ff) << 18))
++
++/* The whole filter kernel is arranged as the coefficients 0-16 going
++ * up, then a pad, then 17-31 going down and reversed within the
++ * dwords. This means that a linear phase kernel (where it's
++ * symmetrical at the boundary between 15 and 16) has the last 5
++ * dwords matching the first 5, but reversed.
++ */
++#define VC4_LINEAR_PHASE_KERNEL(c0, c1, c2, c3, c4, c5, c6, c7, c8, \
++ c9, c10, c11, c12, c13, c14, c15) \
++ {VC4_PPF_FILTER_WORD(c0, c1, c2), \
++ VC4_PPF_FILTER_WORD(c3, c4, c5), \
++ VC4_PPF_FILTER_WORD(c6, c7, c8), \
++ VC4_PPF_FILTER_WORD(c9, c10, c11), \
++ VC4_PPF_FILTER_WORD(c12, c13, c14), \
++ VC4_PPF_FILTER_WORD(c15, c15, 0)}
++
++#define VC4_LINEAR_PHASE_KERNEL_DWORDS 6
++#define VC4_KERNEL_DWORDS (VC4_LINEAR_PHASE_KERNEL_DWORDS * 2 - 1)
++
++/* Recommended B=1/3, C=1/3 filter choice from Mitchell/Netravali.
++ * http://www.cs.utexas.edu/~fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf
++ */
++static const u32 mitchell_netravali_1_3_1_3_kernel[] =
++ VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18,
++ 50, 82, 119, 155, 187, 213, 227);
++
++static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
++ struct drm_mm_node *space,
++ const u32 *kernel)
++{
++ int ret, i;
++ u32 __iomem *dst_kernel;
++
++ ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS, 1,
++ 0);
++ if (ret) {
++ DRM_ERROR("Failed to allocate space for filter kernel: %d\n",
++ ret);
++ return ret;
++ }
++
++ dst_kernel = hvs->dlist + space->start;
++
++ for (i = 0; i < VC4_KERNEL_DWORDS; i++) {
++ if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS)
++ writel(kernel[i], &dst_kernel[i]);
++ else {
++ writel(kernel[VC4_KERNEL_DWORDS - i - 1],
++ &dst_kernel[i]);
++ }
++ }
++
++ return 0;
++}
++
+ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = drm->dev_private;
+ struct vc4_hvs *hvs = NULL;
++ int ret;
+
+ hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
+ if (!hvs)
+@@ -119,6 +183,33 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
+
+ hvs->dlist = hvs->regs + SCALER_DLIST_START;
+
++ 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
++ * for now we just allocate globally.
++ */
++ drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
++
++ /* Upload filter kernels. We only have the one for now, so we
++ * keep it around for the lifetime of the driver.
++ */
++ ret = vc4_hvs_upload_linear_kernel(hvs,
++ &hvs->mitchell_netravali_filter,
++ mitchell_netravali_1_3_1_3_kernel);
++ if (ret)
++ return ret;
++
+ vc4->hvs = hvs;
+ return 0;
+ }
+@@ -129,6 +220,12 @@ 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->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
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -24,19 +24,52 @@
+ #include "drm_fb_cma_helper.h"
+ #include "drm_plane_helper.h"
+
++enum vc4_scaling_mode {
++ VC4_SCALING_NONE,
++ VC4_SCALING_TPZ,
++ VC4_SCALING_PPF,
++};
++
+ 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;
+
+ /* 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 area being scanned from in the FB. */
++ u32 src_x, src_y;
++
++ 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 offsets[3];
++
++ /* 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)
+ return NULL;
+ }
+
++static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
++{
++ if (dst > src)
++ return VC4_SCALING_PPF;
++ else if (dst < src)
++ return VC4_SCALING_TPZ;
++ else
++ return VC4_SCALING_NONE;
++}
++
+ 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
+ if (!vc4_state)
+ return NULL;
+
++ memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
++
+ __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
+ static void vc4_plane_destroy_state(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);
+
++ if (vc4_state->lbm.allocated) {
++ unsigned long irqflags;
++
++ spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
++ drm_mm_remove_node(&vc4_state->lbm);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
++ }
++
+ 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)
+ vc4_state->dlist[vc4_state->dlist_count++] = val;
+ }
+
++/* Returns the scl0/scl1 field based on whether the dimensions need to
++ * be up/down/non-scaled.
++ *
++ * This is a replication of a table from the spec.
++ */
++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[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:
++ return SCALER_CTL0_SCL_H_TPZ_V_PPF;
++ case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:
++ return SCALER_CTL0_SCL_H_PPF_V_TPZ;
++ case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:
++ return SCALER_CTL0_SCL_H_TPZ_V_TPZ;
++ case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:
++ return SCALER_CTL0_SCL_H_PPF_V_NONE;
++ case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:
++ return SCALER_CTL0_SCL_H_NONE_V_PPF;
++ case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:
++ return SCALER_CTL0_SCL_H_NONE_V_TPZ;
++ case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:
++ return SCALER_CTL0_SCL_H_TPZ_V_NONE;
++ default:
++ case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:
++ /* The unity case is independently handled by
++ * SCALER_CTL0_UNITY.
++ */
++ return 0;
++ }
++}
++
++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;
++
++ 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) ||
++ (state->src_y & subpixel_src_mask) ||
++ (state->src_w & subpixel_src_mask) ||
++ (state->src_h & subpixel_src_mask)) {
++ 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);
++
++ /* No configuring scaling on the cursor plane, since it gets
++ non-vblank-synced updates, and scaling requires requires
++ LBM changes which have to be vblank-synced.
++ */
++ if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
++ return -EINVAL;
++
++ /* 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;
++}
++
++static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
++{
++ u32 scale, recip;
++
++ scale = (1 << 16) * src / dst;
++
++ /* The specs note that while the reciprocal would be defined
++ * as (1<<32)/scale, ~0 is close enough.
++ */
++ recip = ~0 / scale;
++
++ vc4_dlist_write(vc4_state,
++ VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
++ VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
++ vc4_dlist_write(vc4_state,
++ VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
++}
++
++static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
++{
++ u32 scale = (1 << 16) * src / dst;
++
++ vc4_dlist_write(vc4_state,
++ SCALER_PPF_AGC |
++ VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
++ VC4_SET_FIELD(0, SCALER_PPF_IPHASE));
++}
++
++static u32 vc4_lbm_size(struct drm_plane_state *state)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_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[0], (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.
++ */
++ lbm = pix_per_line * 16;
++ }
++
++ lbm = roundup(lbm, 32);
++
++ return lbm;
++}
++
++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[channel] == VC4_SCALING_PPF) {
++ vc4_write_ppf(vc4_state,
++ vc4_state->src_w[channel], vc4_state->crtc_w);
++ }
++
++ /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
++ if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
++ vc4_write_ppf(vc4_state,
++ 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[channel] == VC4_SCALING_TPZ) {
++ vc4_write_tpz(vc4_state,
++ vc4_state->src_w[channel], vc4_state->crtc_w);
++ }
++
++ /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
++ if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
++ vc4_write_tpz(vc4_state,
++ vc4_state->src_h[channel], 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.
+ */
+ 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);
+ 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 lbm_size;
++ unsigned long irqflags;
++ int ret, i;
++
++ 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.
++ */
++ lbm_size = vc4_lbm_size(state);
++ if (lbm_size) {
++ if (!vc4_state->lbm.allocated) {
++ spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
++ ret = drm_mm_insert_node(&vc4->hvs->lbm_mm,
++ &vc4_state->lbm,
++ lbm_size, 32, 0);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
++ } 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);
+ }
+
++ /* Control word */
+ vc4_dlist_write(vc4_state,
+ SCALER_CTL0_VALID |
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+ (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));
+
+ /* 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));
+-
+- /* 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,
++ VC4_SET_FIELD(vc4_state->crtc_w,
++ SCALER_POS1_SCL_WIDTH) |
++ VC4_SET_FIELD(vc4_state->crtc_h,
++ SCALER_POS1_SCL_HEIGHT));
++ }
+
+ /* 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 :
+ 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));
+
+ /* 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]);
++ }
+
+- /* 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[0] != VC4_SCALING_NONE ||
++ vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
++ vc4_dlist_write(vc4_state, vc4_state->lbm.start);
++ }
++
++ 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[0] == VC4_SCALING_PPF ||
++ vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
++ vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
++ vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
++ u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
++ SCALER_PPF_KERNEL_OFFSET);
++
++ /* HPPF plane 0 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* VPPF plane 0 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* HPPF plane 1 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* VPPF plane 1 */
++ vc4_dlist_write(vc4_state, kernel);
++ }
++ }
+
+ vc4_state->dlist[ctl0_offset] |=
+ VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
+@@ -303,13 +716,13 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
+ * scanout will start from this address as soon as the FIFO
+ * needs to refill with pixels.
+ */
+- writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
++ writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
+
+ /* Also update the CPU-side dlist copy, so that any later
+ * atomic updates that don't do a new modeset on our plane
+ * also use our updated address.
+ */
+- vc4_state->dlist[vc4_state->pw0_offset] = addr;
++ vc4_state->dlist[vc4_state->ptr0_offset] = addr;
+ }
+
+ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+@@ -325,8 +738,83 @@ static void vc4_plane_destroy(struct drm_plane *plane)
+ drm_plane_cleanup(plane);
+ }
+
++/* Implements immediate (non-vblank-synced) updates of the cursor
++ * position, or falls back to the atomic helper otherwise.
++ */
++static int
++vc4_update_plane(struct drm_plane *plane,
++ struct drm_crtc *crtc,
++ struct drm_framebuffer *fb,
++ int crtc_x, int crtc_y,
++ unsigned int crtc_w, unsigned int crtc_h,
++ uint32_t src_x, uint32_t src_y,
++ uint32_t src_w, uint32_t src_h)
++{
++ struct drm_plane_state *plane_state;
++ struct vc4_plane_state *vc4_state;
++
++ if (plane != crtc->cursor)
++ goto out;
++
++ plane_state = plane->state;
++ vc4_state = to_vc4_plane_state(plane_state);
++
++ if (!plane_state)
++ goto out;
++
++ /* If we're changing the cursor contents, do that in the
++ * normal vblank-synced atomic path.
++ */
++ if (fb != plane_state->fb)
++ goto out;
++
++ /* No configuring new scaling in the fast path. */
++ if (crtc_w != plane_state->crtc_w ||
++ crtc_h != plane_state->crtc_h ||
++ src_w != plane_state->src_w ||
++ src_h != plane_state->src_h) {
++ goto out;
++ }
++
++ /* Set the cursor's position on the screen. This is the
++ * expected change from the drm_mode_cursor_universal()
++ * helper.
++ */
++ plane_state->crtc_x = crtc_x;
++ plane_state->crtc_y = crtc_y;
++
++ /* Allow changing the start position within the cursor BO, if
++ * that matters.
++ */
++ plane_state->src_x = src_x;
++ plane_state->src_y = src_y;
++
++ /* Update the display list based on the new crtc_x/y. */
++ vc4_plane_atomic_check(plane, plane_state);
++
++ /* Note that we can't just call vc4_plane_write_dlist()
++ * because that would smash the context data that the HVS is
++ * currently using.
++ */
++ writel(vc4_state->dlist[vc4_state->pos0_offset],
++ &vc4_state->hw_dlist[vc4_state->pos0_offset]);
++ writel(vc4_state->dlist[vc4_state->pos2_offset],
++ &vc4_state->hw_dlist[vc4_state->pos2_offset]);
++ writel(vc4_state->dlist[vc4_state->ptr0_offset],
++ &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
++
++ return 0;
++
++out:
++ return drm_atomic_helper_update_plane(plane, crtc, fb,
++ crtc_x, crtc_y,
++ crtc_w, crtc_h,
++ src_x, src_y,
++ src_w, src_h);
++}
++
+ static const struct drm_plane_funcs vc4_plane_funcs = {
+- .update_plane = drm_atomic_helper_update_plane,
++ .update_plane = vc4_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = vc4_plane_destroy,
+ .set_property = NULL,
+@@ -341,6 +829,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
+ 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);
+
+ 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)
+
+-#define PV_VSYNCD 0x08
++#define PV_VSYNCD_EVEN 0x08
+
+ #define PV_HORZA 0x0c
+ # define PV_HORZA_HBP_MASK VC4_MASK(31, 16)
+@@ -350,6 +350,17 @@
+ # define SCALER_DISPCTRLX_HEIGHT_SHIFT 0
+
+ #define SCALER_DISPBKGND0 0x00000044
++# define SCALER_DISPBKGND_AUTOHS BIT(31)
++# define SCALER_DISPBKGND_INTERLACE BIT(30)
++# define SCALER_DISPBKGND_GAMMA BIT(29)
++# define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25)
++# define SCALER_DISPBKGND_TESTMODE_SHIFT 25
++/* Enables filling the scaler line with the RGB value in the low 24
++ * bits before compositing. Costs cycles, so should be skipped if
++ * opaque display planes will cover everything.
++ */
++# define SCALER_DISPBKGND_FILL BIT(24)
++
+ #define SCALER_DISPSTAT0 0x00000048
+ #define SCALER_DISPBASE0 0x0000004c
+ # define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30)
+@@ -362,6 +373,9 @@
+ # define SCALER_DISPSTATX_EMPTY BIT(28)
+ #define SCALER_DISPCTRL1 0x00000050
+ #define SCALER_DISPBKGND1 0x00000054
++#define SCALER_DISPBKGNDX(x) (SCALER_DISPBKGND0 + \
++ (x) * (SCALER_DISPBKGND1 - \
++ SCALER_DISPBKGND0))
+ #define SCALER_DISPSTAT1 0x00000058
+ #define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \
+ (x) * (SCALER_DISPSTAT1 - \
+@@ -456,6 +470,8 @@
+ #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
+
+ #define VC4_HD_M_CTL 0x00c
++# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
++# define VC4_HD_M_RAM_STANDBY (3 << 4)
+ # define VC4_HD_M_SW_RST BIT(2)
+ # define VC4_HD_M_ENABLE BIT(0)
+
+@@ -503,7 +519,12 @@ enum hvs_pixel_format {
+ 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
+@@ -536,6 +557,21 @@ enum hvs_pixel_format {
+ #define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13)
+ #define SCALER_CTL0_ORDER_SHIFT 13
+
++#define SCALER_CTL0_SCL1_MASK VC4_MASK(10, 8)
++#define SCALER_CTL0_SCL1_SHIFT 8
++
++#define SCALER_CTL0_SCL0_MASK VC4_MASK(7, 5)
++#define SCALER_CTL0_SCL0_SHIFT 5
++
++#define SCALER_CTL0_SCL_H_PPF_V_PPF 0
++#define SCALER_CTL0_SCL_H_TPZ_V_PPF 1
++#define SCALER_CTL0_SCL_H_PPF_V_TPZ 2
++#define SCALER_CTL0_SCL_H_TPZ_V_TPZ 3
++#define SCALER_CTL0_SCL_H_PPF_V_NONE 4
++#define SCALER_CTL0_SCL_H_NONE_V_PPF 5
++#define SCALER_CTL0_SCL_H_NONE_V_TPZ 6
++#define SCALER_CTL0_SCL_H_TPZ_V_NONE 7
++
+ /* Set to indicate no scaling. */
+ #define SCALER_CTL0_UNITY BIT(4)
+
+@@ -551,6 +587,12 @@ enum hvs_pixel_format {
+ #define SCALER_POS0_START_X_MASK VC4_MASK(11, 0)
+ #define SCALER_POS0_START_X_SHIFT 0
+
++#define SCALER_POS1_SCL_HEIGHT_MASK VC4_MASK(27, 16)
++#define SCALER_POS1_SCL_HEIGHT_SHIFT 16
++
++#define SCALER_POS1_SCL_WIDTH_MASK VC4_MASK(11, 0)
++#define SCALER_POS1_SCL_WIDTH_SHIFT 0
++
+ #define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30)
+ #define SCALER_POS2_ALPHA_MODE_SHIFT 30
+ #define SCALER_POS2_ALPHA_MODE_PIPELINE 0
+@@ -564,6 +606,80 @@ enum hvs_pixel_format {
+ #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
++#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
+
+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/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
+new file mode 100644
+index 0000000..ecf89f1
+--- /dev/null
++++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
+@@ -0,0 +1,146 @@
++/*
++ * Serial port driver for BCM2835AUX UART
++ *
++ * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
++ *
++ * Based on 8250_lpc18xx.c:
++ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++
++#include "8250.h"
++
++struct bcm2835aux_data {
++ struct uart_8250_port uart;
++ struct clk *clk;
++ int line;
++};
++
++static int bcm2835aux_serial_probe(struct platform_device *pdev)
++{
++ struct bcm2835aux_data *data;
++ struct resource *res;
++ int ret;
++
++ /* allocate the custom structure */
++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ /* initialize data */
++ spin_lock_init(&data->uart.port.lock);
++ data->uart.capabilities = UART_CAP_FIFO;
++ data->uart.port.dev = &pdev->dev;
++ data->uart.port.regshift = 2;
++ data->uart.port.type = PORT_16550;
++ data->uart.port.iotype = UPIO_MEM;
++ data->uart.port.fifosize = 8;
++ data->uart.port.flags = UPF_SHARE_IRQ |
++ UPF_FIXED_PORT |
++ UPF_FIXED_TYPE |
++ UPF_SKIP_TEST;
++
++ /* get the clock - this also enables the HW */
++ data->clk = devm_clk_get(&pdev->dev, NULL);
++ ret = PTR_ERR_OR_ZERO(data->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
++ return ret;
++ }
++
++ /* get the interrupt */
++ data->uart.port.irq = platform_get_irq(pdev, 0);
++ if (data->uart.port.irq < 0) {
++ dev_err(&pdev->dev, "irq not found - %i",
++ data->uart.port.irq);
++ return data->uart.port.irq;
++ }
++
++ /* map the main registers */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "memory resource not found");
++ return -EINVAL;
++ }
++ data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res);
++ ret = PTR_ERR_OR_ZERO(data->uart.port.membase);
++ if (ret)
++ return ret;
++
++ /* Check for a fixed line number */
++ ret = of_alias_get_id(pdev->dev.of_node, "serial");
++ if (ret >= 0)
++ data->uart.port.line = ret;
++
++ /* enable the clock as a last step */
++ ret = clk_prepare_enable(data->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
++ ret);
++ return ret;
++ }
++
++ /* the HW-clock divider for bcm2835aux is 8,
++ * but 8250 expects a divider of 16,
++ * so we have to multiply the actual clock by 2
++ * to get identical baudrates.
++ */
++ data->uart.port.uartclk = clk_get_rate(data->clk) * 2;
++
++ /* register the port */
++ ret = serial8250_register_8250_port(&data->uart);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "unable to register 8250 port - %d\n",
++ ret);
++ goto dis_clk;
++ }
++ data->line = ret;
++
++ platform_set_drvdata(pdev, data);
++
++ return 0;
++
++dis_clk:
++ clk_disable_unprepare(data->clk);
++ return ret;
++}
++
++static int bcm2835aux_serial_remove(struct platform_device *pdev)
++{
++ struct bcm2835aux_data *data = platform_get_drvdata(pdev);
++
++ serial8250_unregister_port(data->uart.port.line);
++ clk_disable_unprepare(data->clk);
++
++ return 0;
++}
++
++static const struct of_device_id bcm2835aux_serial_match[] = {
++ { .compatible = "brcm,bcm2835-aux-uart" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
++
++static struct platform_driver bcm2835aux_serial_driver = {
++ .driver = {
++ .name = "bcm2835-aux-uart",
++ .of_match_table = bcm2835aux_serial_match,
++ },
++ .probe = bcm2835aux_serial_probe,
++ .remove = bcm2835aux_serial_remove,
++};
++module_platform_driver(bcm2835aux_serial_driver);
++
++MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
++MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
+index b03cb517..67ad6b0 100644
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -272,6 +272,30 @@ config SERIAL_8250_ACORN
+ system, say Y to this option. The driver can handle 1, 2, or 3 port
+ cards. If unsure, say N.
+
++config SERIAL_8250_BCM2835AUX
++ tristate "BCM2835 auxiliar mini UART support"
++ depends on ARCH_BCM2835 || COMPILE_TEST
++ depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ
++ help
++ Support for the BCM2835 auxiliar mini UART.
++
++ Features and limitations of the UART are
++ Registers are similar to 16650 registers,
++ set bits in the control registers that are unsupported
++ are ignored and read back as 0
++ 7/8 bit operation with 1 start and 1 stop bit
++ 8 symbols deep fifo for rx and tx
++ SW controlled RTS and SW readable CTS
++ Clock rate derived from system clock
++ Uses 8 times oversampling (compared to 16 times for 16650)
++ Missing break detection (but break generation)
++ Missing framing error detection
++ Missing parity bit
++ Missing receive time-out interrupt
++ Missing DCD, DSR, DTR and RI signals
++
++ If unsure, say N.
++
+ config SERIAL_8250_FSL
+ bool
+ depends on SERIAL_8250_CONSOLE
+diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
+index b9b9bca..5c1869f 100644
+--- a/drivers/tty/serial/8250/Makefile
++++ b/drivers/tty/serial/8250/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
+ obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
+ obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
+ obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
++obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
+ obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+ obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
+ obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/cdc-acm-more-sanity-checking.patch b/freed-ora/current/f24/cdc-acm-more-sanity-checking.patch
new file mode 100644
index 000000000..99ad43416
--- /dev/null
+++ b/freed-ora/current/f24/cdc-acm-more-sanity-checking.patch
@@ -0,0 +1,33 @@
+From e6a87f147002fa16adcbafebbc458ff90a463474 Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Tue, 15 Mar 2016 10:14:04 +0100
+Subject: [PATCH] cdc-acm: more sanity checking
+
+An attack has become available which pretends to be a quirky
+device circumventing normal sanity checks and crashes the kernel
+by an insufficient number of interfaces. This patch adds a check
+to the code path for quirky devices.
+
+Signed-off-by: Oliver Neukum <ONeukum@suse.com>
+CC: stable@vger.kernel.org
+---
+ drivers/usb/class/cdc-acm.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
+index 26ca4f910cb0..a7732f80a912 100644
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -1113,6 +1113,9 @@ static int acm_probe(struct usb_interface *intf,
+ if (quirks == NO_UNION_NORMAL) {
+ data_interface = usb_ifnum_to_if(usb_dev, 1);
+ control_interface = usb_ifnum_to_if(usb_dev, 0);
++ /* we would crash */
++ if (!data_interface || !control_interface)
++ return -ENODEV;
+ goto skip_normal_probe;
+ }
+
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/config-armv7 b/freed-ora/current/f24/config-armv7
index 0cce9bc04..1a040d692 100644
--- a/freed-ora/current/f24/config-armv7
+++ b/freed-ora/current/f24/config-armv7
@@ -8,7 +8,6 @@ CONFIG_ARCH_OMAP3=y
CONFIG_ARCH_OMAP4=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_TEGRA=y
-CONFIG_ARCH_U8500=y
CONFIG_ARCH_ZYNQ=y
# These are supported in the LPAE kernel
@@ -259,6 +258,7 @@ CONFIG_INPUT_TPS65218_PWRBUTTON=m
CONFIG_VIDEO_AM437X_VPFE=m
CONFIG_UIO_PRUSS=m
CONFIG_WKUP_M3_RPROC=m
+CONFIG_WKUP_M3_IPC=m
# Builtin needed for BBone White
CONFIG_MFD_TPS65217=y
@@ -538,46 +538,6 @@ CONFIG_AK8975=m
CONFIG_CM36651=m
CONFIG_KEYBOARD_SAMSUNG=m
-# ST Ericsson
-CONFIG_MACH_HREFV60=y
-CONFIG_MACH_SNOWBALL=y
-
-CONFIG_ABX500_CORE=y
-# CONFIG_ARM_U8500_CPUIDLE is not set
-CONFIG_UX500_DEBUG_UART=2
-CONFIG_AB8500_CORE=y
-CONFIG_STE_DMA40=y
-CONFIG_HSEM_U8500=m
-CONFIG_PINCTRL_ABX500=y
-CONFIG_PINCTRL_AB8500=y
-CONFIG_I2C_NOMADIK=m
-CONFIG_KEYBOARD_NOMADIK=m
-CONFIG_DB8500_CPUFREQ_COOLING=m
-CONFIG_DB8500_THERMAL=y
-CONFIG_UX500_WATCHDOG=m
-CONFIG_AHCI_ST=m
-CONFIG_INPUT_AB8500_PONKEY=m
-CONFIG_REGULATOR_AB8500=y
-CONFIG_AB8500_USB=m
-CONFIG_USB_MUSB_UX500=m
-# CONFIG_USB_UX500_DMA is not set
-CONFIG_RTC_DRV_AB8500=m
-CONFIG_PWM_AB8500=m
-CONFIG_SND_SOC_UX500=m
-CONFIG_SND_SOC_UX500_PLAT_DMA=m
-CONFIG_SND_SOC_UX500_MACH_MOP500=m
-CONFIG_CLKSRC_DBX500_PRCMU=y
-CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK=y
-CONFIG_CRYPTO_DEV_UX500=m
-CONFIG_CRYPTO_DEV_UX500_CRYP=m
-CONFIG_CRYPTO_DEV_UX500_HASH=m
-CONFIG_SENSORS_LIS3_I2C=m
-CONFIG_AB8500_BM=y
-CONFIG_AB8500_GPADC=y
-CONFIG_SENSORS_AB8500=m
-CONFIG_STE_MODEM_RPROC=m
-CONFIG_STIH415_RESET=y
-
# Allwinner
CONFIG_MACH_SUN4I=y
CONFIG_MACH_SUN5I=y
diff --git a/freed-ora/current/f24/config-armv7-generic b/freed-ora/current/f24/config-armv7-generic
index 563811d20..e5d10e198 100644
--- a/freed-ora/current/f24/config-armv7-generic
+++ b/freed-ora/current/f24/config-armv7-generic
@@ -50,6 +50,7 @@ CONFIG_CPU_SW_DOMAIN_PAN=y
# CONFIG_ARM_VIRT_EXT is not set
# Platforms enabled/disabled globally on ARMv7
+CONFIG_ARCH_BCM=y
CONFIG_ARCH_BCM2835=y
CONFIG_ARCH_EXYNOS=y
CONFIG_ARCH_HIGHBANK=y
@@ -57,7 +58,13 @@ CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_TEGRA=y
CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y
CONFIG_ARCH_VIRT=y
-# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BCM_CYGNUS is not set
+# CONFIG_ARCH_BCM_NSP is not set
+# CONFIG_ARCH_BCM_5301X is not set
+# CONFIG_ARCH_BCM_281XX is not set
+# CONFIG_ARCH_BCM_21664 is not set
+# CONFIG_ARCH_BCM_63XX is not set
+# CONFIG_ARCH_BRCMSTB is not set
# CONFIG_ARCH_BERLIN is not set
# CONFIG_ARCH_HI3xxx is not set
# CONFIG_ARCH_HISI is not set
@@ -233,6 +240,7 @@ CONFIG_NVMEM_SUNXI_SID=m
# BCM 283x
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_8250_BCM2835AUX=y
CONFIG_DMA_BCM2835=m
CONFIG_MMC_SDHCI_BCM2835=m
CONFIG_BCM2835_MBOX=m
@@ -244,7 +252,8 @@ CONFIG_SPI_BCM2835AUX=m
CONFIG_BCM2835_WDT=m
CONFIG_SND_BCM2835_SOC_I2S=m
CONFIG_DRM_VC4=m
-CONFIG_RASPBERRYPI_FIRMWARE=m
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RASPBERRYPI_POWER=y
# Exynos
CONFIG_ARCH_EXYNOS3=y
diff --git a/freed-ora/current/f24/cypress_m8-add-sanity-checking.patch b/freed-ora/current/f24/cypress_m8-add-sanity-checking.patch
new file mode 100644
index 000000000..fa8513f94
--- /dev/null
+++ b/freed-ora/current/f24/cypress_m8-add-sanity-checking.patch
@@ -0,0 +1,50 @@
+From f7a3aa353011e38e119adebd845b38551587a26a Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Thu, 17 Mar 2016 16:25:33 +0100
+Subject: [PATCH] cypress_m8: add sanity checking
+
+An attack using missing endpoints exists.
+CVE-2016-3137
+
+Signed-off-by: Oliver Neukum <ONeukum@suse.com>
+CC: stable@vger.kernel.org
+
+v1 - add sanity check
+v2 - add error logging
+v3 - correct error message
+---
+ drivers/usb/serial/cypress_m8.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
+index 01bf53392819..5e25443fe4ef 100644
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -447,6 +447,11 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
+ struct usb_serial *serial = port->serial;
+ struct cypress_private *priv;
+
++ if (!port->interrupt_out_urb || !port->interrupt_in_urb) {
++ dev_err(&port->dev, "A required endpoint is missing\n");
++ return -ENODEV;
++ }
++
+ priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+@@ -606,12 +611,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
+ cypress_set_termios(tty, port, &priv->tmp_termios);
+
+ /* setup the port and start reading from the device */
+- if (!port->interrupt_in_urb) {
+- dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
+- __func__);
+- return -1;
+- }
+-
+ usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
+ usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
+ port->interrupt_in_urb->transfer_buffer,
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/digi_acceleport-do-sanity-checking-for-the-number-of.patch b/freed-ora/current/f24/digi_acceleport-do-sanity-checking-for-the-number-of.patch
new file mode 100644
index 000000000..2bbae94b7
--- /dev/null
+++ b/freed-ora/current/f24/digi_acceleport-do-sanity-checking-for-the-number-of.patch
@@ -0,0 +1,34 @@
+From e9c2a3972496927631a1a98fef43e9538e9fd5d5 Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Mon, 14 Mar 2016 15:53:38 +0100
+Subject: [PATCH] digi_acceleport: do sanity checking for the number of ports
+
+The driver can be crashed with devices that expose crafted
+descriptors with too few endpoints.
+See:
+http://seclists.org/bugtraq/2016/Mar/61
+
+Signed-off-by: Oliver Neukum <ONeukum@suse.com>
+---
+ drivers/usb/serial/digi_acceleport.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
+index 12b0e67473ba..c4d4d4547d40 100644
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -1260,6 +1260,11 @@ static int digi_startup(struct usb_serial *serial)
+
+ spin_lock_init(&serial_priv->ds_serial_lock);
+ serial_priv->ds_oob_port_num = serial->type->num_ports;
++ if (!(serial_priv->ds_oob_port_num == 2 && serial->type == &digi_acceleport_2_device)
++ && !(serial_priv->ds_oob_port_num == 4 && serial->type == &digi_acceleport_4_device)) {
++ kfree(serial_priv);
++ return -EINVAL;
++ }
+ serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];
+
+ ret = digi_port_init(serial_priv->ds_oob_port,
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/Geekbox-device-tree-support.patch b/freed-ora/current/f24/geekbox-v4-device-tree-support.patch
index 51caf8aaf..77c1e5c28 100644
--- a/freed-ora/current/f24/Geekbox-device-tree-support.patch
+++ b/freed-ora/current/f24/geekbox-v4-device-tree-support.patch
@@ -1,19 +1,21 @@
-From a516bbf04744817e49e173b2a217a2a6366b5f9c Mon Sep 17 00:00:00 2001
+From 4d321bf15d2d5e5b1b674f2a26a1c5202090a800 Mon Sep 17 00:00:00 2001
From: Peter Robinson <pbrobinson@gmail.com>
-Date: Wed, 2 Mar 2016 18:12:09 +0000
-Subject: [PATCH] Geekbox device tree support
+Date: Thu, 17 Mar 2016 15:19:04 +0000
+Subject: [PATCH] geekbox v4 patchset
---
Documentation/devicetree/bindings/arm/rockchip.txt | 9 +
arch/arm64/boot/dts/rockchip/Makefile | 2 +
- .../dts/rockchip/rk3368-geekbox-landingship.dts | 56 ++++
- arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts | 321 +++++++++++++++++++++
- 4 files changed, 388 insertions(+)
+ arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi | 2 +-
+ .../dts/rockchip/rk3368-geekbox-landingship.dts | 57 ++++
+ arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts | 319 +++++++++++++++++++++
+ arch/arm64/boot/dts/rockchip/rk3368-r88.dts | 2 +-
+ 6 files changed, 389 insertions(+), 2 deletions(-)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-geekbox-landingship.dts
create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
-index 078c14f..c6d95f2 100644
+index 078c14f..ae84f4e 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -87,6 +87,15 @@ Rockchip platforms device tree bindings
@@ -24,9 +26,9 @@ index 078c14f..c6d95f2 100644
+ Required root node properties:
+ - compatible = "geekbuying,geekbox", "rockchip,rk3368";
+
-+- GeekBuying Landingship:
++- GeekBuying Landingship with GeekBox module:
+ Required root node properties:
-+ - compatible = "geekbuying,landingship",
++ - compatible = "geekbuying,geekbox-landingship",
+ "geekbuying,geekbox", "rockchip,rk3368";
+
- Rockchip RK3368 evb:
@@ -43,12 +45,25 @@ index e3f0b5f..201bcd9 100644
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
always := $(dtb-y)
+diff --git a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
+index 8c219cc..e4ceb53 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
+@@ -48,7 +48,7 @@
+ stdout-path = "serial2:115200n8";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x40000000>;
+ };
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox-landingship.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox-landingship.dts
new file mode 100644
-index 0000000..e4a1175
+index 0000000..a28ace9
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox-landingship.dts
-@@ -0,0 +1,56 @@
+@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016 Andreas Färber
+ *
@@ -95,11 +110,12 @@ index 0000000..e4a1175
+
+/ {
+ model = "GeekBox on Landingship";
-+ compatible = "geekbuying,landingship", "geekbuying,geekbox", "rockchip,rk3368";
++ compatible = "geekbuying,geekbox-landingship",
++ "geekbuying,geekbox", "rockchip,rk3368";
+};
+
+&i2c1 {
-+ status = "okay";
++ status = "disabled";
+};
+
+&i2c2 {
@@ -107,10 +123,10 @@ index 0000000..e4a1175
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts
new file mode 100644
-index 0000000..7e51876
+index 0000000..46cdddf
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts
-@@ -0,0 +1,321 @@
+@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2016 Andreas Färber
+ *
@@ -155,6 +171,7 @@ index 0000000..7e51876
+
+/dts-v1/;
+#include "rk3368.dtsi"
++#include <dt-bindings/input/input.h>
+
+/ {
+ model = "GeekBox";
@@ -164,7 +181,7 @@ index 0000000..7e51876
+ stdout-path = "serial2:115200n8";
+ };
+
-+ memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
@@ -187,15 +204,12 @@ index 0000000..7e51876
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_key>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
+
-+ button@0 {
-+ reg = <0>;
-+ gpio-key,wakeup = <1>;
++ power {
+ gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+ label = "GPIO Power";
-+ linux,code = <116>;
++ linux,code = <KEY_POWER>;
++ wakeup-source;
+ };
+ };
+
@@ -390,13 +404,13 @@ index 0000000..7e51876
+&pinctrl {
+ ir {
+ ir_int: ir-int {
-+ rockchip,pins = <3 30 RK_FUNC_GPIO &pcfg_pull_up>;
++ rockchip,pins = <3 30 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ keys {
+ pwr_key: pwr-key {
-+ rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_up>;
++ rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
@@ -414,7 +428,7 @@ index 0000000..7e51876
+&tsadc {
+ status = "okay";
+ rockchip,hw-tshut-mode = <0>; /* CRU */
-+ rockchip,hw-tshut-polarity = <0>; /* low */
++ rockchip,hw-tshut-polarity = <1>; /* high */
+};
+
+&uart2 {
@@ -432,6 +446,19 @@ index 0000000..7e51876
+&wdt {
+ status = "okay";
+};
+diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
+index 104cbee..9548129 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
+@@ -51,7 +51,7 @@
+ stdout-path = "serial2:115200n8";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x40000000>;
+ };
--
2.5.0
diff --git a/freed-ora/current/f24/ims-pcu-sanity-check-against-missing-interfaces.patch b/freed-ora/current/f24/ims-pcu-sanity-check-against-missing-interfaces.patch
new file mode 100644
index 000000000..827a2b7ee
--- /dev/null
+++ b/freed-ora/current/f24/ims-pcu-sanity-check-against-missing-interfaces.patch
@@ -0,0 +1,39 @@
+From a4200b7eb26271108586d3a7cf34a2f16d460e48 Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Thu, 17 Mar 2016 15:10:47 +0100
+Subject: [PATCH] ims-pcu: sanity check against missing interfaces
+
+A malicious device missing interface can make the driver oops.
+Add sanity checking.
+
+Signed-off-by: Oliver Neukum <ONeukum@suse.com>
+CC: stable@vger.kernel.org
+---
+ drivers/input/misc/ims-pcu.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
+index ac1fa5f44580..9c0ea36913b4 100644
+--- a/drivers/input/misc/ims-pcu.c
++++ b/drivers/input/misc/ims-pcu.c
+@@ -1663,6 +1663,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
+
+ pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
+ union_desc->bMasterInterface0);
++ if (!pcu->ctrl_intf)
++ return -EINVAL;
+
+ alt = pcu->ctrl_intf->cur_altsetting;
+ pcu->ep_ctrl = &alt->endpoint[0].desc;
+@@ -1670,6 +1672,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
+
+ pcu->data_intf = usb_ifnum_to_if(pcu->udev,
+ union_desc->bSlaveInterface0);
++ if (!pcu->data_intf)
++ return -EINVAL;
+
+ alt = pcu->data_intf->cur_altsetting;
+ if (alt->desc.bNumEndpoints != 2) {
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/ipv4-Dont-do-expensive-useless-work-during-inetdev-des.patch b/freed-ora/current/f24/ipv4-Dont-do-expensive-useless-work-during-inetdev-des.patch
new file mode 100644
index 000000000..48e4762e3
--- /dev/null
+++ b/freed-ora/current/f24/ipv4-Dont-do-expensive-useless-work-during-inetdev-des.patch
@@ -0,0 +1,97 @@
+From fbd40ea0180a2d328c5adc61414dc8bab9335ce2 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Sun, 13 Mar 2016 23:28:00 -0400
+Subject: ipv4: Don't do expensive useless work during inetdev destroy.
+
+When an inetdev is destroyed, every address assigned to the interface
+is removed. And in this scenerio we do two pointless things which can
+be very expensive if the number of assigned interfaces is large:
+
+1) Address promotion. We are deleting all addresses, so there is no
+ point in doing this.
+
+2) A full nf conntrack table purge for every address. We only need to
+ do this once, as is already caught by the existing
+ masq_dev_notifier so masq_inet_event() can skip this.
+
+Reported-by: Solar Designer <solar@openwall.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Tested-by: Cyrill Gorcunov <gorcunov@openvz.org>
+---
+ net/ipv4/devinet.c | 4 ++++
+ net/ipv4/fib_frontend.c | 4 ++++
+ net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 12 ++++++++++--
+ 3 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index 65e76a4..e333bc8 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -334,6 +334,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+
+ ASSERT_RTNL();
+
++ if (in_dev->dead)
++ goto no_promotions;
++
+ /* 1. Deleting primary ifaddr forces deletion all secondaries
+ * unless alias promotion is set
+ **/
+@@ -380,6 +383,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+ fib_del_ifaddr(ifa, ifa1);
+ }
+
++no_promotions:
+ /* 2. Unlink it */
+
+ *ifap = ifa1->ifa_next;
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 4734475..21add55 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -922,6 +922,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
+ subnet = 1;
+ }
+
++ if (in_dev->dead)
++ goto no_promotions;
++
+ /* Deletion is more complicated than add.
+ * We should take care of not to delete too much :-)
+ *
+@@ -997,6 +1000,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
+ }
+ }
+
++no_promotions:
+ if (!(ok & BRD_OK))
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
+ if (subnet && ifa->ifa_prefixlen < 31) {
+diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
+index c6eb421..ea91058 100644
+--- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
++++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
+@@ -108,10 +108,18 @@ static int masq_inet_event(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+ {
+- struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
++ struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev;
+ struct netdev_notifier_info info;
+
+- netdev_notifier_info_init(&info, dev);
++ /* The masq_dev_notifier will catch the case of the device going
++ * down. So if the inetdev is dead and being destroyed we have
++ * no work to do. Otherwise this is an individual address removal
++ * and we have to perform the flush.
++ */
++ if (idev->dead)
++ return NOTIFY_DONE;
++
++ netdev_notifier_info_init(&info, idev->dev);
+ return masq_device_event(this, event, &info);
+ }
+
+--
+cgit v0.12
+
diff --git a/freed-ora/current/f24/kernel.spec b/freed-ora/current/f24/kernel.spec
index f50307aab..5a88d1210 100644
--- a/freed-ora/current/f24/kernel.spec
+++ b/freed-ora/current/f24/kernel.spec
@@ -42,7 +42,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be appended after the rcX and
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
#
-%global baserelease 300
+%global baserelease 301
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@@ -545,9 +545,13 @@ Patch07: freedo.patch
# Standalone patches
-Patch451: lib-cpumask-Make-CPUMASK_OFFSTACK-usable-without-deb.patch
+# http://www.spinics.net/lists/netdev/msg369442.html
+Patch452: revert-stmmac-Fix-eth0-No-PHY-found-regression.patch
+Patch453: stmmac-fix-MDIO-settings.patch
-Patch454: arm64-avoid-needing-console-to-enable-serial-console.patch
+Patch454: bcm283x-add-aux-uart-support-extra-DT-bits-initial-r.patch
+
+Patch455: arm64-avoid-needing-console-to-enable-serial-console.patch
Patch456: arm64-acpi-drop-expert-patch.patch
@@ -556,8 +560,8 @@ Patch457: ARM-tegra-usb-no-reset.patch
Patch458: ARM-mvebu-change-order-of-ethernet-DT-nodes-on-Armada-38x.patch
-# http://www.spinics.net/lists/arm-kernel/msg480703.html
-Patch459: Geekbox-device-tree-support.patch
+# http://www.spinics.net/lists/arm-kernel/msg490981.html
+Patch459: geekbox-v4-device-tree-support.patch
# http://www.spinics.net/lists/arm-kernel/msg483898.html
Patch460: Initial-AllWinner-A64-and-PINE64-support.patch
@@ -567,6 +571,8 @@ Patch461: Fix-tegra-to-use-stdout-path-for-serial-console.patch
Patch463: arm-i.MX6-Utilite-device-dtb.patch
+Patch465: lib-cpumask-Make-CPUMASK_OFFSTACK-usable-without-deb.patch
+
Patch466: input-kill-stupid-messages.patch
Patch467: die-floppy-die.patch
@@ -670,6 +676,33 @@ Patch664: netfilter-x_tables-check-for-size-overflow.patch
#CVE-2016-3134 rhbz 1317383 1317384
Patch665: netfilter-x_tables-deal-with-bogus-nextoffset-values.patch
+#CVE-2016-3135 rhbz 1318172 1318270
+Patch666: ipv4-Dont-do-expensive-useless-work-during-inetdev-des.patch
+
+#CVE-2016-2184 rhbz 1317012 1317470
+Patch670: ALSA-usb-audio-Fix-NULL-dereference-in-create_fixed_.patch
+Patch671: ALSA-usb-audio-Add-sanity-checks-for-endpoint-access.patch
+
+#CVE-2016-3137 rhbz 1317010 1316996
+Patch672: cypress_m8-add-sanity-checking.patch
+
+#CVE-2016-2186 rhbz 1317015 1317464
+Patch673: USB-input-powermate-fix-oops-with-malicious-USB-desc.patch
+
+#CVE-2016-2188 rhbz 1317018 1317467
+Patch674: USB-iowarrior-fix-oops-with-malicious-USB-descriptor.patch
+
+#CVE-2016-2185 rhbz 1317014 1317471
+Patch675: usb_driver_claim_interface-add-sanity-checking.patch
+
+#CVE-2016-3138 rhbz 1317010 1316204
+Patch676: cdc-acm-more-sanity-checking.patch
+
+#CVE-2016-3140 rhbz 1317010 1316995
+Patch677: digi_acceleport-do-sanity-checking-for-the-number-of.patch
+
+Patch678: ims-pcu-sanity-check-against-missing-interfaces.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -2289,10 +2322,28 @@ fi
#
#
%changelog
+* Sat Mar 19 2016 Peter Robinson <pbrobinson@fedoraproject.org> 4.5.0-301
+- Upstream fix for stmmac driver regressions (AllWinner Gb NICs)
+- Update various ARM device support patches
+- General ARM updates
+
+* Fri Mar 18 2016 Josh Boyer <jwboyer@fedoraproject.org>
+- ims-pcu: sanity checking on missing interfaces
+- CVE-2016-3140 digi_acceleport: oops on invalid USB descriptors (rhbz 1317010 1316995)
+- CVE-2016-3138 cdc_acm: oops on invalid USB descriptors (rhbz 1317010 1316204)
+- CVE-2016-2185 ati_remote2: oops on invalid USB descriptors (rhbz 1317014 1317471)
+- CVE-2016-2188 iowarrior: oops on invalid USB descriptors (rhbz 1317018 1317467)
+- CVE-2016-2186 powermate: oops on invalid USB descriptors (rhbz 1317015 1317464)
+- CVE-2016-3137 cypress_m8: oops on invalid USB descriptors (rhbz 1317010 1316996)
+- CVE-2016-2184 alsa: panic on invalid USB descriptors (rhbz 1317012 1317470)
+
+* Wed Mar 16 2016 Josh Boyer <jwboyer@fedoraproject.org>
+- CVE-2016-3135 ipv4: DoS when destroying a network interface (rhbz 1318172 1318270)
+
* Mon Mar 14 2016 Alexandre Oliva <lxoliva@fsfla.org> -libre
- GNU Linux-libre 4.5-gnu.
-* Mon Mar 14 2016 Justin M. Forbes <jforbes@fedoraproject.org> - 4.5.0-1
+* Mon Mar 14 2016 Justin M. Forbes <jforbes@fedoraproject.org> - 4.5.0-300
- Linux v4.5
- Disable debugging options.
diff --git a/freed-ora/current/f24/revert-stmmac-Fix-eth0-No-PHY-found-regression.patch b/freed-ora/current/f24/revert-stmmac-Fix-eth0-No-PHY-found-regression.patch
new file mode 100644
index 000000000..68b9cd3ab
--- /dev/null
+++ b/freed-ora/current/f24/revert-stmmac-Fix-eth0-No-PHY-found-regression.patch
@@ -0,0 +1,87 @@
+From 44f947bb8ef5f4add9f2d84e1ff53afd8f2f5537 Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Wed, 16 Mar 2016 15:21:44 +0000
+Subject: [PATCH 1/2] Revert "stmmac: Fix 'eth0: No PHY found' regression"
+
+This reverts commit 88f8b1bb41c6208f81b6a480244533ded7b59493.
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 11 ++++++++++-
+ drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 9 +--------
+ include/linux/stmmac.h | 1 -
+ 3 files changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+index efb54f3..0faf163 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+@@ -199,12 +199,21 @@ int stmmac_mdio_register(struct net_device *ndev)
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
+ int addr, found;
+- struct device_node *mdio_node = priv->plat->mdio_node;
++ struct device_node *mdio_node = NULL;
++ struct device_node *child_node = NULL;
+
+ if (!mdio_bus_data)
+ return 0;
+
+ if (IS_ENABLED(CONFIG_OF)) {
++ for_each_child_of_node(priv->device->of_node, child_node) {
++ if (of_device_is_compatible(child_node,
++ "snps,dwmac-mdio")) {
++ mdio_node = child_node;
++ break;
++ }
++ }
++
+ if (mdio_node) {
+ netdev_dbg(ndev, "FOUND MDIO subnode\n");
+ } else {
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+index 4514ba7..6a52fa1 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -110,7 +110,6 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+ struct device_node *np = pdev->dev.of_node;
+ struct plat_stmmacenet_data *plat;
+ struct stmmac_dma_cfg *dma_cfg;
+- struct device_node *child_node = NULL;
+
+ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
+ if (!plat)
+@@ -141,19 +140,13 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+ plat->phy_node = of_node_get(np);
+ }
+
+- for_each_child_of_node(np, child_node)
+- if (of_device_is_compatible(child_node, "snps,dwmac-mdio")) {
+- plat->mdio_node = child_node;
+- break;
+- }
+-
+ /* "snps,phy-addr" is not a standard property. Mark it as deprecated
+ * and warn of its use. Remove this when phy node support is added.
+ */
+ if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
+ dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
+
+- if ((plat->phy_node && !of_phy_is_fixed_link(np)) || !plat->mdio_node)
++ if ((plat->phy_node && !of_phy_is_fixed_link(np)) || plat->phy_bus_name)
+ plat->mdio_bus_data = NULL;
+ else
+ plat->mdio_bus_data =
+diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
+index 881a79d..eead8ab 100644
+--- a/include/linux/stmmac.h
++++ b/include/linux/stmmac.h
+@@ -100,7 +100,6 @@ struct plat_stmmacenet_data {
+ int interface;
+ struct stmmac_mdio_bus_data *mdio_bus_data;
+ struct device_node *phy_node;
+- struct device_node *mdio_node;
+ struct stmmac_dma_cfg *dma_cfg;
+ int clk_csr;
+ int has_gmac;
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/stmmac-fix-MDIO-settings.patch b/freed-ora/current/f24/stmmac-fix-MDIO-settings.patch
new file mode 100644
index 000000000..41fa928a4
--- /dev/null
+++ b/freed-ora/current/f24/stmmac-fix-MDIO-settings.patch
@@ -0,0 +1,235 @@
+From d55a02f460ffd64a5ba7f331489af87edeebf8da Mon Sep 17 00:00:00 2001
+From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
+Date: Wed, 16 Mar 2016 10:38:49 +0100
+Subject: [PATCH 2/2] stmmac: fix MDIO settings
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Initially the phy_bus_name was added to manipulate the
+driver name but it was recently just used to manage the
+fixed-link and then to take some decision at run-time.
+So the patch uses the is_pseudo_fixed_link and removes
+the phy_bus_name variable not necessary anymore.
+
+The driver can manage the mdio registration by using phy-handle,
+dwmac-mdio and own parameter e.g. snps,phy-addr.
+This patch takes care about all these possible configurations
+and fixes the mdio registration in case of there is a real
+transceiver or a switch (that needs to be managed by using
+fixed-link).
+
+Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+Reviewed-by: Andreas Färber <afaerber@suse.de>
+Tested-by: Frank Schäfer <fschaefer.oss@googlemail.com>
+Cc: Gabriel Fernandez <gabriel.fernandez@linaro.org>
+Cc: Dinh Nguyen <dinh.linux@gmail.com>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Phil Reid <preid@electromag.com.au>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 11 +--
+ drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 19 +----
+ .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 84 +++++++++++++++++-----
+ include/linux/stmmac.h | 2 +-
+ 4 files changed, 71 insertions(+), 45 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index c21015b..389d7d0 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -271,7 +271,6 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
+ */
+ bool stmmac_eee_init(struct stmmac_priv *priv)
+ {
+- char *phy_bus_name = priv->plat->phy_bus_name;
+ unsigned long flags;
+ bool ret = false;
+
+@@ -283,7 +282,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
+ goto out;
+
+ /* Never init EEE in case of a switch is attached */
+- if (phy_bus_name && (!strcmp(phy_bus_name, "fixed")))
++ if (priv->phydev->is_pseudo_fixed_link)
+ goto out;
+
+ /* MAC core supports the EEE feature. */
+@@ -820,12 +819,8 @@ static int stmmac_init_phy(struct net_device *dev)
+ phydev = of_phy_connect(dev, priv->plat->phy_node,
+ &stmmac_adjust_link, 0, interface);
+ } else {
+- if (priv->plat->phy_bus_name)
+- snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
+- priv->plat->phy_bus_name, priv->plat->bus_id);
+- else
+- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
+- priv->plat->bus_id);
++ snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
++ priv->plat->bus_id);
+
+ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+ priv->plat->phy_addr);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+index 0faf163..3f5512f 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+@@ -198,29 +198,12 @@ int stmmac_mdio_register(struct net_device *ndev)
+ struct mii_bus *new_bus;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
++ struct device_node *mdio_node = priv->plat->mdio_node;
+ int addr, found;
+- struct device_node *mdio_node = NULL;
+- struct device_node *child_node = NULL;
+
+ if (!mdio_bus_data)
+ return 0;
+
+- if (IS_ENABLED(CONFIG_OF)) {
+- for_each_child_of_node(priv->device->of_node, child_node) {
+- if (of_device_is_compatible(child_node,
+- "snps,dwmac-mdio")) {
+- mdio_node = child_node;
+- break;
+- }
+- }
+-
+- if (mdio_node) {
+- netdev_dbg(ndev, "FOUND MDIO subnode\n");
+- } else {
+- netdev_warn(ndev, "No MDIO subnode found\n");
+- }
+- }
+-
+ new_bus = mdiobus_alloc();
+ if (new_bus == NULL)
+ return -ENOMEM;
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+index 6a52fa1..190fb6d 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -96,6 +96,69 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries)
+ }
+
+ /**
++ * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
++ * @plat: driver data platform structure
++ * @np: device tree node
++ * @dev: device pointer
++ * Description:
++ * The mdio bus will be allocated in case of a phy transceiver is on board;
++ * it will be NULL if the fixed-link is configured.
++ * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
++ * in any case (for DSA, mdio must be registered even if fixed-link).
++ * The table below sums the supported configurations:
++ * -------------------------------
++ * snps,phy-addr | Y
++ * -------------------------------
++ * phy-handle | Y
++ * -------------------------------
++ * fixed-link | N
++ * -------------------------------
++ * snps,dwmac-mdio |
++ * even if | Y
++ * fixed-link |
++ * -------------------------------
++ *
++ * It returns 0 in case of success otherwise -ENODEV.
++ */
++static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
++ struct device_node *np, struct device *dev)
++{
++ bool mdio = true;
++
++ /* If phy-handle property is passed from DT, use it as the PHY */
++ plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
++ if (plat->phy_node)
++ dev_dbg(dev, "Found phy-handle subnode\n");
++
++ /* If phy-handle is not specified, check if we have a fixed-phy */
++ if (!plat->phy_node && of_phy_is_fixed_link(np)) {
++ if ((of_phy_register_fixed_link(np) < 0))
++ return -ENODEV;
++
++ dev_dbg(dev, "Found fixed-link subnode\n");
++ plat->phy_node = of_node_get(np);
++ mdio = false;
++ }
++
++ /* If snps,dwmac-mdio is passed from DT, always register the MDIO */
++ for_each_child_of_node(np, plat->mdio_node) {
++ if (of_device_is_compatible(plat->mdio_node, "snps,dwmac-mdio"))
++ break;
++ }
++
++ if (plat->mdio_node) {
++ dev_dbg(dev, "Found MDIO subnode\n");
++ mdio = true;
++ }
++
++ if (mdio)
++ plat->mdio_bus_data =
++ devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
++ GFP_KERNEL);
++ return 0;
++}
++
++/**
+ * stmmac_probe_config_dt - parse device-tree driver parameters
+ * @pdev: platform_device structure
+ * @plat: driver data platform structure
+@@ -129,30 +192,15 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+ /* Default to phy auto-detection */
+ plat->phy_addr = -1;
+
+- /* If we find a phy-handle property, use it as the PHY */
+- plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
+-
+- /* If phy-handle is not specified, check if we have a fixed-phy */
+- if (!plat->phy_node && of_phy_is_fixed_link(np)) {
+- if ((of_phy_register_fixed_link(np) < 0))
+- return ERR_PTR(-ENODEV);
+-
+- plat->phy_node = of_node_get(np);
+- }
+-
+ /* "snps,phy-addr" is not a standard property. Mark it as deprecated
+ * and warn of its use. Remove this when phy node support is added.
+ */
+ if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
+ dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
+
+- if ((plat->phy_node && !of_phy_is_fixed_link(np)) || plat->phy_bus_name)
+- plat->mdio_bus_data = NULL;
+- else
+- plat->mdio_bus_data =
+- devm_kzalloc(&pdev->dev,
+- sizeof(struct stmmac_mdio_bus_data),
+- GFP_KERNEL);
++ /* To Configure PHY by using all device-tree supported properties */
++ if (stmmac_dt_phy(plat, np, &pdev->dev))
++ return ERR_PTR(-ENODEV);
+
+ of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
+
+diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
+index eead8ab..8b1ff2b 100644
+--- a/include/linux/stmmac.h
++++ b/include/linux/stmmac.h
+@@ -94,12 +94,12 @@ struct stmmac_dma_cfg {
+ };
+
+ struct plat_stmmacenet_data {
+- char *phy_bus_name;
+ int bus_id;
+ int phy_addr;
+ int interface;
+ struct stmmac_mdio_bus_data *mdio_bus_data;
+ struct device_node *phy_node;
++ struct device_node *mdio_node;
+ struct stmmac_dma_cfg *dma_cfg;
+ int clk_csr;
+ int has_gmac;
+--
+2.5.0
+
diff --git a/freed-ora/current/f24/usb_driver_claim_interface-add-sanity-checking.patch b/freed-ora/current/f24/usb_driver_claim_interface-add-sanity-checking.patch
new file mode 100644
index 000000000..079ff03fd
--- /dev/null
+++ b/freed-ora/current/f24/usb_driver_claim_interface-add-sanity-checking.patch
@@ -0,0 +1,39 @@
+From de0784bdf6314b70c69416d8c576eb83237d5b1e Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Wed, 16 Mar 2016 12:26:17 -0400
+Subject: [PATCH] usb_driver_claim_interface: add sanity checking
+
+Attacks that trick drivers into passing a NULL pointer
+to usb_driver_claim_interface() using forged descriptors are
+known. This thwarts them by sanity checking.
+
+Signed-off-by: Oliver Neukum <ONeukum@suse.com>
+CC: stable@vger.kernel.org
+---
+ drivers/usb/core/driver.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
+index 6b5063e7943f..e2d242b68d4b 100644
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -500,11 +500,15 @@ static int usb_unbind_interface(struct device *dev)
+ int usb_driver_claim_interface(struct usb_driver *driver,
+ struct usb_interface *iface, void *priv)
+ {
+- struct device *dev = &iface->dev;
++ struct device *dev;
+ struct usb_device *udev;
+ int retval = 0;
+ int lpm_disable_error;
+
++ if (!iface)
++ return -ENODEV;
++
++ dev = &iface->dev;
+ if (dev->driver)
+ return -EBUSY;
+
+--
+2.5.0
+
OpenPOWER on IntegriCloud