aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/arm-boards21
-rw-r--r--Documentation/devicetree/bindings/display/virtual-encoder.txt74
-rw-r--r--arch/arm/boot/dts/Makefile4
l---------arch/arm/boot/dts/fvp-base-aemv8a-aemv8a.dts1
l---------arch/arm/boot/dts/fvp-base.dtsi1
l---------arch/arm/boot/dts/juno-base.dtsi1
l---------arch/arm/boot/dts/juno-clocks.dtsi1
l---------arch/arm/boot/dts/juno-cs-r1r2.dtsi1
l---------arch/arm/boot/dts/juno-motherboard.dtsi1
l---------arch/arm/boot/dts/juno-r1.dts1
l---------arch/arm/boot/dts/juno-r2.dts1
l---------arch/arm/boot/dts/juno-sched-energy.dtsi1
l---------arch/arm/boot/dts/juno.dts1
l---------arch/arm/boot/dts/juno_r2-sched-energy.dtsi1
-rw-r--r--arch/arm/boot/dts/vexpress-v2m-rs1.dtsi5
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts30
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts30
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca5s.dts30
-rw-r--r--arch/arm/mach-vexpress/Kconfig2
-rw-r--r--arch/arm64/boot/dts/arm/Makefile1
-rw-r--r--arch/arm64/boot/dts/arm/foundation-v8.dtsi71
-rw-r--r--arch/arm64/boot/dts/arm/fvp-base-aemv8a-aemv8a.dts228
-rw-r--r--arch/arm64/boot/dts/arm/fvp-base.dtsi304
-rw-r--r--arch/arm64/boot/dts/arm/juno-base.dtsi44
-rw-r--r--arch/arm64/boot/dts/arm/juno-r1.dts2
-rw-r--r--arch/arm64/boot/dts/arm/juno-r2.dts2
-rw-r--r--arch/arm64/boot/dts/arm/juno.dts2
-rw-r--r--drivers/firmware/Kconfig4
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/arm_scpi.c56
-rw-r--r--drivers/firmware/arm_scpi_test.c568
-rw-r--r--drivers/gpu/drm/Kconfig8
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/arm/Makefile2
-rw-r--r--drivers/gpu/drm/arm/hdlcd_crtc.c42
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c93
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.h6
-rw-r--r--drivers/gpu/drm/arm/hdlcd_fb_helper.c855
-rw-r--r--drivers/gpu/drm/arm/hdlcd_fb_helper.h54
-rw-r--r--drivers/gpu/drm/drm_virtual_encoder.c299
-rw-r--r--drivers/gpu/drm/i2c/Kconfig3
-rw-r--r--drivers/gpu/drm/i2c/Makefile2
-rw-r--r--drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c264
-rw-r--r--drivers/net/ethernet/marvell/sky2.c26
-rw-r--r--include/drm/drm_crtc.h2
-rw-r--r--linaro/configs/android.conf35
-rw-r--r--linaro/configs/big-LITTLE-MP.conf0
-rw-r--r--linaro/configs/vexpress.conf20
-rw-r--r--linaro/configs/vexpress64.conf42
49 files changed, 3161 insertions, 85 deletions
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards
index b6e810c2781a..d28b61c93cf8 100644
--- a/Documentation/devicetree/bindings/arm/arm-boards
+++ b/Documentation/devicetree/bindings/arm/arm-boards
@@ -235,3 +235,24 @@ Example:
};
};
+
+ARM Fixed Virtual Platforms (FVP)
+---------------------------------
+FVPs are simulated platforms produced by ARM to aid software development without
+the requirement for actual hardware. They come in several families, each of
+which (usually) contain variants for different configurations of simulated
+hardware. These are documented in the Fixed Virtual Platforms FVP Reference
+Guide (reference number ARM DUI0837H).
+
+Required properties (in root node):
+- compatible value:
+ compatible = "arm,<family>,<variant>", "arm,<family>";
+ where <family> is one of:
+ - "fvp-base" for the Base FVP
+ - "fvp-ve" for the VE FVP
+ and <variant> is the part of the model's executable filename with the family
+ name omitted, converted to lower case, and with non-alphanumeric characters
+ replaced with '-'. E.g. the Base FVP that has two AEMv8 CPU clusters has an
+ executable file called FVP_Base_AEMv8A-AEMv8A, so the compatible value for
+ this would be:
+ compatible = "arm,fvp-base,aemv8a-aemv8a", "arm,fvp-base";
diff --git a/Documentation/devicetree/bindings/display/virtual-encoder.txt b/Documentation/devicetree/bindings/display/virtual-encoder.txt
new file mode 100644
index 000000000000..3a9b8221c3ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/virtual-encoder.txt
@@ -0,0 +1,74 @@
+DRM Virtual Encoder
+
+The DRM Virtual Encoder is a component-based basic encoder that fetches
+the display timings information from the device tree and "discovers" a
+DRM output with the given data. It is helpful in a simulated environment
+where there is no actual hardware to be probed and the configuration of
+the display happens outside the kernel world.
+
+Required properties:
+ - compatible: should be "drm,virtual-encoder"
+
+Required sub-nodes:
+ - display-timings: node describing the virtual output timings information,
+ as specified in panel/display-timing.txt file.
+ - port: the input port connection as modelled using the OF graph bindings
+ specified in Documentation/devicetree/bindings/graph.txt
+
+
+Example:
+
+/ {
+ ...
+
+ vencoder {
+ compatible = "drm,virtual-encoder";
+ display-timings {
+ native-mode = <&timing1>;
+ timing0: timing@0 {
+ /* 640x480 framebuffer */
+ clock-frequency = <23750>;
+ hactive = <640>;
+ vactive = <480>;
+ hfront-porch = <48>;
+ hback-porch = <16>;
+ hsync-len = <96>;
+ vfront-porch = <33>;
+ vback-porch = <9>;
+ vsync-len = <3>;
+ };
+ timing1: timing@1 {
+ /* 1280x720 framebuffer */
+ clock-frequency = <74440000>;
+ hactive = <1280>;
+ vactive = <720>;
+ hfront-porch = <56>;
+ hback-porch = <192>;
+ hsync-len = <136>;
+ vfront-porch = <1>;
+ vback-porch = <22>;
+ vsync-len = <3>;
+ };
+ };
+
+ port {
+ vencoder_in: endpoint {
+ remote-endpoint = <&driver_out>;
+ };
+ };
+ };
+
+ drm_driver: driver@f00bad {
+ ...
+
+ port {
+ driver_out: endpoint {
+ remote-endpoint = <&vencoder_in>;
+ };
+ };
+
+ ...
+ };
+
+ ...
+};
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9c5e1d944d1c..533e670c9b55 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -962,6 +962,10 @@ dtb-$(CONFIG_ARCH_VERSATILE) += \
versatile-ab.dtb \
versatile-pb.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += \
+ juno.dtb \
+ juno-r1.dtb \
+ juno-r2.dtb \
+ fvp-base-aemv8a-aemv8a.dtb \
vexpress-v2p-ca5s.dtb \
vexpress-v2p-ca9.dtb \
vexpress-v2p-ca15-tc1.dtb \
diff --git a/arch/arm/boot/dts/fvp-base-aemv8a-aemv8a.dts b/arch/arm/boot/dts/fvp-base-aemv8a-aemv8a.dts
new file mode 120000
index 000000000000..4f545027a7b4
--- /dev/null
+++ b/arch/arm/boot/dts/fvp-base-aemv8a-aemv8a.dts
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/fvp-base-aemv8a-aemv8a.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/fvp-base.dtsi b/arch/arm/boot/dts/fvp-base.dtsi
new file mode 120000
index 000000000000..9cb4e3c1cbf1
--- /dev/null
+++ b/arch/arm/boot/dts/fvp-base.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/fvp-base.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-base.dtsi b/arch/arm/boot/dts/juno-base.dtsi
new file mode 120000
index 000000000000..5bf5772d7718
--- /dev/null
+++ b/arch/arm/boot/dts/juno-base.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-base.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-clocks.dtsi b/arch/arm/boot/dts/juno-clocks.dtsi
new file mode 120000
index 000000000000..d26c206771d4
--- /dev/null
+++ b/arch/arm/boot/dts/juno-clocks.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-clocks.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-cs-r1r2.dtsi b/arch/arm/boot/dts/juno-cs-r1r2.dtsi
new file mode 120000
index 000000000000..08c059e69464
--- /dev/null
+++ b/arch/arm/boot/dts/juno-cs-r1r2.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-cs-r1r2.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-motherboard.dtsi b/arch/arm/boot/dts/juno-motherboard.dtsi
new file mode 120000
index 000000000000..a4e1f71b8533
--- /dev/null
+++ b/arch/arm/boot/dts/juno-motherboard.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-motherboard.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-r1.dts b/arch/arm/boot/dts/juno-r1.dts
new file mode 120000
index 000000000000..f0bf74937285
--- /dev/null
+++ b/arch/arm/boot/dts/juno-r1.dts
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-r1.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-r2.dts b/arch/arm/boot/dts/juno-r2.dts
new file mode 120000
index 000000000000..aba7e1fac440
--- /dev/null
+++ b/arch/arm/boot/dts/juno-r2.dts
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-r2.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno-sched-energy.dtsi b/arch/arm/boot/dts/juno-sched-energy.dtsi
new file mode 120000
index 000000000000..3508c8b8438f
--- /dev/null
+++ b/arch/arm/boot/dts/juno-sched-energy.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno-sched-energy.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno.dts b/arch/arm/boot/dts/juno.dts
new file mode 120000
index 000000000000..186e53545ef2
--- /dev/null
+++ b/arch/arm/boot/dts/juno.dts
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/juno_r2-sched-energy.dtsi b/arch/arm/boot/dts/juno_r2-sched-energy.dtsi
new file mode 120000
index 000000000000..0d000be54a83
--- /dev/null
+++ b/arch/arm/boot/dts/juno_r2-sched-energy.dtsi
@@ -0,0 +1 @@
+../../../arm64/boot/dts/arm/juno_r2-sched-energy.dtsi \ No newline at end of file
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index 35714ff6f467..4582c33b152f 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -222,6 +222,9 @@
dvi-transmitter@39 {
compatible = "sil,sii9022-tpi", "sil,sii9022";
reg = <0x39>;
+
+ v2m_dvi_port: port {
+ };
};
dvi-transmitter@60 {
@@ -245,7 +248,7 @@
reg-shift = <2>;
};
- clcd@1f0000 {
+ v2m_clcd: clcd@1f0000 {
compatible = "arm,pl111", "arm,primecell";
reg = <0x1f0000 0x1000>;
interrupt-names = "combined";
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
index 0c8de0ca73ee..cedef43b3944 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -57,6 +57,22 @@
interrupts = <0 85 4>;
clocks = <&hdlcd_clk>;
clock-names = "pxlclk";
+
+ port {
+ hdlcd0_output: endpoint@0 {
+ remote-endpoint = <&sii9022_0_input>;
+ };
+ };
+ };
+
+ hdmi0: connector@0 {
+ compatible = "hdmi-connector";
+ type = "a";
+ port {
+ hdmi0_connector_output: endpoint {
+ remote-endpoint = <&sii9022_0_output>;
+ };
+ };
};
memory-controller@2b0a0000 {
@@ -294,3 +310,17 @@
<0 3 &gic 0 39 4>;
};
};
+
+&v2m_clcd {
+ status = "disabled";
+};
+
+&v2m_dvi_port {
+ sii9022_0_input: endpoint@0 {
+ remote-endpoint = <&hdlcd0_output>;
+ };
+
+ sii9022_0_output: endpoint@1 {
+ remote-endpoint = <&hdmi0_connector_output>;
+ };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index 65ecf206388c..aec0df2b6d40 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -116,6 +116,22 @@
interrupts = <0 85 4>;
clocks = <&hdlcd_clk>;
clock-names = "pxlclk";
+
+ port {
+ hdlcd0_output: endpoint@0 {
+ remote-endpoint = <&sii9022_0_input>;
+ };
+ };
+ };
+
+ hdmi0: connector@0 {
+ compatible = "hdmi-connector";
+ type = "a";
+ port {
+ hdmi0_connector_output: endpoint {
+ remote-endpoint = <&sii9022_0_output>;
+ };
+ };
};
memory-controller@2b0a0000 {
@@ -657,3 +673,17 @@
<0 3 &gic 0 39 4>;
};
};
+
+&v2m_clcd {
+ status = "disabled";
+};
+
+&v2m_dvi_port {
+ sii9022_0_input: endpoint@0 {
+ remote-endpoint = <&hdlcd0_output>;
+ };
+
+ sii9022_0_output: endpoint@1 {
+ remote-endpoint = <&hdmi0_connector_output>;
+ };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
index 6e69b8e6c1a7..8bc8f71c7d28 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -59,6 +59,22 @@
interrupts = <0 85 4>;
clocks = <&hdlcd_clk>;
clock-names = "pxlclk";
+
+ port {
+ hdlcd0_output: endpoint@0 {
+ remote-endpoint = <&sii9022_0_input>;
+ };
+ };
+ };
+
+ hdmi0: connector@0 {
+ compatible = "hdmi-connector";
+ type = "a";
+ port {
+ hdmi0_connector_output: endpoint {
+ remote-endpoint = <&sii9022_0_output>;
+ };
+ };
};
memory-controller@2a150000 {
@@ -264,3 +280,17 @@
<0 3 &gic 0 39 4>;
};
};
+
+&v2m_clcd {
+ status = "disabled";
+};
+
+&v2m_dvi_port {
+ sii9022_0_input: endpoint@0 {
+ remote-endpoint = <&hdlcd0_output>;
+ };
+
+ sii9022_0_output: endpoint@1 {
+ remote-endpoint = <&hdmi0_connector_output>;
+ };
+};
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 7c728ebc0b33..834084feccbb 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -4,6 +4,7 @@ menuconfig ARCH_VEXPRESS
select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
select ARM_GIC
+ select ARM_GIC_V3
select ARM_GLOBAL_TIMER
select ARM_TIMER_SP804
select COMMON_CLK_VERSATILE
@@ -22,6 +23,7 @@ menuconfig ARCH_VEXPRESS
select VEXPRESS_CONFIG
select VEXPRESS_SYSCFG
select MFD_VEXPRESS_SYSREG
+ select PM_GENERIC_DOMAINS
help
This option enables support for systems using Cortex processor based
ARM core and logic (FPGA) tiles on the Versatile Express motherboard,
diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile
index 75cc2aa10101..7531001f6321 100644
--- a/arch/arm64/boot/dts/arm/Makefile
+++ b/arch/arm64/boot/dts/arm/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb foundation-v8-gicv3.dtb
+dtb-$(CONFIG_ARCH_VEXPRESS) += fvp-base-aemv8a-aemv8a.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb juno-r1.dtb juno-r2.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2f-1xv7-ca53x2.dtb
diff --git a/arch/arm64/boot/dts/arm/foundation-v8.dtsi b/arch/arm64/boot/dts/arm/foundation-v8.dtsi
index 7cfa8e414e7f..7f536637d4ce 100644
--- a/arch/arm64/boot/dts/arm/foundation-v8.dtsi
+++ b/arch/arm64/boot/dts/arm/foundation-v8.dtsi
@@ -24,40 +24,87 @@
serial3 = &v2m_serial3;
};
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
cpus {
#address-cells = <2>;
#size-cells = <0>;
- cpu@0 {
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+
+ idle-states {
+ entry-method = "arm,psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2000>;
+ };
+
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x1010000>;
+ local-timer-stop;
+ entry-latency-us = <400>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2500>;
+ };
+ };
+
+ CPU0:cpu@0 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x0>;
- enable-method = "spin-table";
- cpu-release-addr = <0x0 0x8000fff8>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
next-level-cache = <&L2_0>;
};
- cpu@1 {
+
+ CPU1:cpu@1 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x1>;
- enable-method = "spin-table";
- cpu-release-addr = <0x0 0x8000fff8>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
next-level-cache = <&L2_0>;
};
- cpu@2 {
+
+ CPU2:cpu@2 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x2>;
- enable-method = "spin-table";
- cpu-release-addr = <0x0 0x8000fff8>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
next-level-cache = <&L2_0>;
};
- cpu@3 {
+
+ CPU3:cpu@3 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x3>;
- enable-method = "spin-table";
- cpu-release-addr = <0x0 0x8000fff8>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
next-level-cache = <&L2_0>;
};
diff --git a/arch/arm64/boot/dts/arm/fvp-base-aemv8a-aemv8a.dts b/arch/arm64/boot/dts/arm/fvp-base-aemv8a-aemv8a.dts
new file mode 100644
index 000000000000..c88dc9a62585
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/fvp-base-aemv8a-aemv8a.dts
@@ -0,0 +1,228 @@
+/*
+ * ARM Ltd. Fixed Virtual Platform (FVP) Base model with dual cluster
+ * Architecture Envelope Model (AEM) v8-A CPUs
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ model = "FVP_Base_AEMv8A-AEMv8A";
+ compatible = "arm,fvp-base,aemv8a-aemv8a", "arm,fvp-base";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &bp_serial0;
+ serial1 = &bp_serial1;
+ serial2 = &bp_serial2;
+ serial3 = &bp_serial3;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0_0>;
+ };
+ core1 {
+ cpu = <&CPU0_1>;
+ };
+ core2 {
+ cpu = <&CPU0_2>;
+ };
+ core3 {
+ cpu = <&CPU0_3>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&CPU1_0>;
+ };
+ core1 {
+ cpu = <&CPU1_1>;
+ };
+ core2 {
+ cpu = <&CPU1_2>;
+ };
+ core3 {
+ cpu = <&CPU1_3>;
+ };
+ };
+ };
+
+ idle-states {
+ entry-method = "arm,psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2000>;
+ };
+
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x1010000>;
+ local-timer-stop;
+ entry-latency-us = <400>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2500>;
+ };
+ };
+
+ CPU0_0: cpu@0 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER0_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU0_1: cpu@1 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x1>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER0_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU0_2: cpu@2 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x2>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER0_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU0_3: cpu@3 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x3>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER0_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU1_0: cpu@100 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER1_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU1_1: cpu@101 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x101>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER1_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU1_2: cpu@102 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x102>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER1_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CPU1_3: cpu@103 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x103>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&CLUSTER1_L2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ };
+
+ CLUSTER0_L2: l2-cache0 {
+ compatible = "cache";
+ };
+
+ CLUSTER1_L2: l2-cache1 {
+ compatible = "cache";
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&CPU0_0>,
+ <&CPU0_1>,
+ <&CPU0_2>,
+ <&CPU0_3>,
+ <&CPU1_0>,
+ <&CPU1_1>,
+ <&CPU1_2>,
+ <&CPU1_3>;
+ };
+
+ gic: interrupt-controller@2f000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ reg = <0x0 0x2f000000 0x0 0x10000>,
+ <0x0 0x2f100000 0x0 0x100000>,
+ <0x0 0x2c000000 0x0 0x2000>,
+ <0x0 0x2c010000 0x0 0x2000>,
+ <0x0 0x2c02f000 0x0 0x2000>;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ its: its@2f020000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x2f020000 0x0 0x20000>;
+ };
+ };
+
+ #include "fvp-base.dtsi"
+};
+
+&hdlcd {
+ status = "disabled";
+};
+
diff --git a/arch/arm64/boot/dts/arm/fvp-base.dtsi b/arch/arm64/boot/dts/arm/fvp-base.dtsi
new file mode 100644
index 000000000000..bf919fa76ff3
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/fvp-base.dtsi
@@ -0,0 +1,304 @@
+ bp_clock35mhz: clock35mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <35000000>;
+ clock-output-names = "bp:clock35mhz";
+ };
+
+ bp_clock24mhz: clock24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "bp:clock24mhz";
+ };
+
+ flash@8000000 {
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0x0 0x08000000 0x0 0x04000000>,
+ <0x0 0x0C000000 0x0 0x04000000>;
+ bank-width = <4>;
+ };
+
+ bp_video_ram: vram@18000000 {
+ compatible = "arm,vexpress-vram";
+ reg = <0x0 0x18000000 0x0 0x00800000>;
+ };
+
+ ethernet@1a000000 {
+ compatible = "smsc,lan91c111";
+ reg = <0x0 0x1a000000 0x0 0x10000>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ bp_sysreg: sysreg@1c010000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x0 0x1c010000 0x0 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ mcc {
+ compatible = "arm,vexpress,config-bus";
+ arm,vexpress,config-bridge = <&bp_sysreg>;
+
+ bp_oscclk1: oscclk1 {
+ compatible = "arm,vexpress-osc";
+ arm,vexpress-sysreg,func = <1 1>;
+ freq-range = <23750000 63500000>;
+ #clock-cells = <0>;
+ clock-output-names = "bp:oscclk1";
+ };
+
+ muxfpga {
+ compatible = "arm,vexpress-muxfpga";
+ arm,vexpress-sysreg,func = <7 0>;
+ };
+ };
+
+ sysctl_refclk: sysctl-refclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000>;
+ clock-output-names = "sysctl:refclk";
+ };
+
+ sysctl_timclk: sysctl-timclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "sysctl:timclk";
+ };
+
+ bp_sysctl: sysctl@1c020000 {
+ compatible = "arm,sp810", "arm,primecell";
+ reg = <0x0 0x1c020000 0x0 0x1000>;
+ clocks = <&sysctl_refclk>, <&sysctl_timclk>, <&bp_clock35mhz>;
+ clock-names = "refclk", "timclk", "apb_pclk";
+ #clock-cells = <1>;
+ clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+ assigned-clocks = <&bp_sysctl 0>, <&bp_sysctl 1>, <&bp_sysctl 3>, <&bp_sysctl 3>;
+ assigned-clock-parents = <&sysctl_timclk>, <&sysctl_timclk>, <&sysctl_timclk>, <&sysctl_timclk>;
+ };
+
+ aaci@1c040000 {
+ compatible = "arm,pl041", "arm,primecell";
+ reg = <0x0 0x1c040000 0x0 0x1000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ bp_fixed_3v3: bp-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ mmci@1c050000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x0 0x1c050000 0x0 0x1000>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ cd-gpios = <&bp_sysreg 0 0>;
+ wp-gpios = <&bp_sysreg 1 0>;
+ max-frequency = <12000000>;
+ vmmc-supply = <&bp_fixed_3v3>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "mclk", "apb_pclk";
+ };
+
+ kmi@1c060000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x0 0x1c060000 0x0 0x1000>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ kmi@1c070000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x0 0x1c070000 0x0 0x1000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ bp_serial0: uart@1c090000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x1c090000 0x0 0x1000>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ bp_serial1: uart@1c0a0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x1c0a0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ bp_serial2: uart@1c0b0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x1c0b0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ bp_serial3: uart@1c0c0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x1c0c0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ wdt@1c0f0000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0x1c0f0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "wdogclk", "apb_pclk";
+ };
+
+ bp_timer01: timer@1c110000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x0 0x1c110000 0x0 0x1000>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_sysctl 0>, <&bp_sysctl 1>, <&bp_clock35mhz>;
+ clock-names = "timclken1", "timclken2", "apb_pclk";
+ };
+
+ bp_timer23: timer@1c120000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x0 0x1c120000 0x0 0x1000>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_sysctl 2>, <&bp_sysctl 3>, <&bp_clock35mhz>;
+ clock-names = "timclken1", "timclken2", "apb_pclk";
+ };
+
+ virtio_block@1c0130000 {
+ compatible = "virtio,mmio";
+ reg = <0x0 0x1c130000 0x0 0x200>;
+ interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ rtc@1c170000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x0 0x1c170000 0x0 0x1000>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ clcd: clcd@1c1f0000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x0 0x1c1f0000 0x0 0x1000>;
+ interrupt-names = "combined";
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_oscclk1>, <&bp_clock24mhz>;
+ clock-names = "clcdclk", "apb_pclk";
+ arm,pl11x,framebuffer = <0x18000000 0x00180000>;
+ memory-region = <&bp_video_ram>;
+ max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */
+
+ port {
+ bp_clcd_pads: endpoint {
+ remote-endpoint = <&bp_clcd_panel>;
+ arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+ };
+ };
+
+ panel {
+ compatible = "panel-dpi";
+
+ port {
+ bp_clcd_panel: endpoint {
+ remote-endpoint = <&bp_clcd_pads>;
+ };
+ };
+
+ panel-timing {
+ clock-frequency = <63500127>;
+ hactive = <1024>;
+ hback-porch = <152>;
+ hfront-porch = <48>;
+ hsync-len = <104>;
+ vactive = <768>;
+ vback-porch = <23>;
+ vfront-porch = <3>;
+ vsync-len = <4>;
+ };
+ };
+ };
+
+ timer@2a810000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x0 0x2a810000 0x0 0x1000>;
+ clock-frequency = <50000000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ frame@2a830000 {
+ frame-number = <1>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x0 0x2a830000 0x0 0x1000>;
+ };
+ };
+
+ fake_hdlcd_clk: fake-hdlcd-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <63500000>;
+ clock-output-names = "pxlclk";
+ };
+
+
+ hdlcd: hdlcd@7ff60000 {
+ compatible = "arm,hdlcd";
+ reg = <0 0x7ff60000 0 0x1000>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&fake_hdlcd_clk>;
+ clock-names = "pxlclk";
+
+ port {
+ hdlcd_out: endpoint {
+ remote-endpoint = <&bp_hdlcd_display>;
+ };
+ };
+ };
+
+ vencoder {
+ compatible = "drm,virtual-encoder";
+
+ port {
+ bp_hdlcd_display: endpoint {
+ remote-endpoint = <&hdlcd_out>;
+ };
+ };
+
+ display-timings {
+ panel-timing {
+ clock-frequency = <63500127>;
+ hactive = <1024>;
+ hback-porch = <152>;
+ hfront-porch = <48>;
+ hsync-len = <104>;
+ vactive = <768>;
+ vback-porch = <23>;
+ vfront-porch = <3>;
+ vsync-len = <4>;
+ };
+ };
+
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000 0 0x80000000>,
+ <0x00000008 0x80000000 0 0x80000000>;
+ };
diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi
index 2bf79578e612..c55e1edf2986 100644
--- a/arch/arm64/boot/dts/arm/juno-base.dtsi
+++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
@@ -1,4 +1,5 @@
#include "juno-clocks.dtsi"
+#include <dt-bindings/display/tda998x.h>
/ {
/*
@@ -620,7 +621,7 @@
dma-coherent;
};
- dma@7ff00000 {
+ dma0: dma@7ff00000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0x7ff00000 0 0x1000>;
#dma-cells = <1>;
@@ -647,7 +648,7 @@
clocks = <&soc_faxiclk>;
clock-names = "apb_pclk";
};
-
+/*
hdlcd@7ff50000 {
compatible = "arm,hdlcd";
reg = <0 0x7ff50000 0 0x1000>;
@@ -662,7 +663,7 @@
};
};
};
-
+*/
hdlcd@7ff60000 {
compatible = "arm,hdlcd";
reg = <0 0x7ff60000 0 0x1000>;
@@ -696,16 +697,18 @@
i2c-sda-hold-time-ns = <500>;
clocks = <&soc_smc50mhz>;
- hdmi-transmitter@70 {
+ hdmi_transmitter0: hdmi-transmitter@70 {
compatible = "nxp,tda998x";
reg = <0x70>;
+ #sound-dai-cells = <0>;
+ audio-ports = <TDA998x_I2S 0x03>;
port {
tda998x_0_input: tda998x-0-endpoint {
remote-endpoint = <&hdlcd0_output>;
};
};
};
-
+/*
hdmi-transmitter@71 {
compatible = "nxp,tda998x";
reg = <0x71>;
@@ -715,7 +718,7 @@
};
};
};
- };
+*/ };
ohci@7ffb0000 {
compatible = "generic-ohci";
@@ -749,6 +752,35 @@
<0x00000008 0x80000000 0x1 0x80000000>;
};
+ soc_i2s: i2s@7ff90000 {
+ compatible = "snps,designware-i2s";
+ reg = <0x0 0x7ff90000 0x0 0x1000>;
+ clocks = <&scmi_clk 5>, <&soc_refclk100mhz>;
+ clock-names = "i2sclk", "apb_pclk";
+ #sound-dai-cells = <0>;
+ dmas = <&dma0 5>;
+ dma-names = "tx";
+ };
+
+ hdmi_audio: hdmi_audio@0 {
+ compatible = "linux,hdmi-audio";
+ #sound-dai-cells = <0>;
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,format = "i2s";
+
+ simple-audio-card,cpu {
+ sound-dai = <&soc_i2s>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi_transmitter0>;
+ };
+ };
+
smb@8000000 {
compatible = "simple-bus";
#address-cells = <2>;
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts
index ce21273b8dea..8b2501e73cbe 100644
--- a/arch/arm64/boot/dts/arm/juno-r1.dts
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -14,7 +14,7 @@
/ {
model = "ARM Juno development board (r1)";
- compatible = "arm,juno-r1", "arm,juno", "arm,vexpress";
+ compatible = "arm,juno-r1", "arm,juno";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts
index 6cd2d6cab727..dab2e49befef 100644
--- a/arch/arm64/boot/dts/arm/juno-r2.dts
+++ b/arch/arm64/boot/dts/arm/juno-r2.dts
@@ -14,7 +14,7 @@
/ {
model = "ARM Juno development board (r2)";
- compatible = "arm,juno-r2", "arm,juno", "arm,vexpress";
+ compatible = "arm,juno-r2", "arm,juno";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index 420060889e61..1d05029687ff 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -13,7 +13,7 @@
/ {
model = "ARM Juno development board (r0)";
- compatible = "arm,juno", "arm,vexpress";
+ compatible = "arm,juno";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index a4462bc661c8..6d29f991ca33 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -82,6 +82,10 @@ config ARM_SCPI_POWER_DOMAIN
This enables support for the SCPI power domains which can be
enabled or disabled via the SCP firmware
+config ARM_SCPI_PROTOCOL_TEST
+ tristate "Test code for SCPI Message Protocol"
+ default ARM_SCPI_PROTOCOL
+
config EDD
tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on X86
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 91d3ff62c653..102b722e2404 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ARM_PSCI_FW) += psci.o
obj-$(CONFIG_ARM_PSCI_CHECKER) += psci_checker.o
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
+obj-$(CONFIG_ARM_SCPI_PROTOCOL_TEST) += arm_scpi_test.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 8043e51de897..2235271d82f4 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -88,8 +88,6 @@
#define FW_REV_MINOR(x) (((x) & FW_REV_MINOR_MASK) >> FW_REV_MINOR_BITS)
#define FW_REV_PATCH(x) ((x) & FW_REV_PATCH_MASK)
-#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
-
enum scpi_error_codes {
SCPI_SUCCESS = 0, /* Success */
SCPI_ERR_PARAM = 1, /* Invalid parameter(s) */
@@ -481,6 +479,18 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
mem->command = cpu_to_le32(t->cmd);
}
+static void scpi_tx_done(struct mbox_client *c, void *msg, int result)
+{
+ struct scpi_xfer *t = msg;
+
+ if (!t->rx_buf)
+ complete(&t->done);
+ /*
+ * Messages with rx_buf are expecting a reply and will be on the
+ * rx_pending list, so leave them alone.
+ */
+}
+
static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch)
{
struct scpi_xfer *t;
@@ -542,17 +552,24 @@ static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len,
reinit_completion(&msg->done);
ret = mbox_send_message(scpi_chan->chan, msg);
- if (ret < 0 || !rx_buf)
- goto out;
+ if (ret >= 0) {
+ /*
+ * Wait for message to be processed. If we end up having to wait
+ * for a very long time then there is a serious bug, probably in
+ * the firmware.
+ *
+ * IMPORTANT: We must not try and continue after the timeout
+ * because this driver and the mailbox framework still has data
+ * structures referring to the failed request and further
+ * serious bugs will result.
+ */
+ if (!wait_for_completion_timeout(&msg->done, msecs_to_jiffies(10000)))
+ BUG();
- if (!wait_for_completion_timeout(&msg->done, MAX_RX_TIMEOUT))
- ret = -ETIMEDOUT;
- else
/* first status word */
- ret = msg->status;
-out:
- if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */
- scpi_process_cmd(scpi_chan, msg->cmd);
+ if (rx_buf)
+ ret = le32_to_cpu(msg->status);
+ }
put_scpi_xfer(msg, scpi_chan);
/* SCPI error codes > 0, translate them to Linux scale*/
@@ -643,6 +660,8 @@ static int opp_cmp_func(const void *opp1, const void *opp2)
return t1->freq - t2->freq;
}
+static bool juno_cpufreq_limit_hack = 0;
+
static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
{
struct scpi_dvfs_info *info;
@@ -681,6 +700,14 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
sort(info->opps, info->count, sizeof(*opp), opp_cmp_func, NULL);
+ /*
+ * Juno silicon doesn't seem to be able to run the big cluster
+ * (domain == 0) at max frequency in AArch32 mode (it produces
+ * random and weird crashes) so drop the highest OPP in that case...
+ */
+ if (juno_cpufreq_limit_hack && domain == 0)
+ --info->count;
+
scpi_info->dvfs[domain] = info;
return info;
}
@@ -956,6 +983,10 @@ static int scpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ if (IS_ENABLED(CONFIG_ARM) && of_find_compatible_node(NULL,NULL,"arm,juno")) {
+ juno_cpufreq_limit_hack = true;
+ }
+
scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
if (!scpi_info)
return -ENOMEM;
@@ -998,8 +1029,7 @@ static int scpi_probe(struct platform_device *pdev)
cl->dev = dev;
cl->rx_callback = scpi_handle_remote_msg;
cl->tx_prepare = scpi_tx_prepare;
- cl->tx_block = true;
- cl->tx_tout = 20;
+ cl->tx_done = scpi_tx_done;
cl->knows_txdone = false; /* controller can't ack */
INIT_LIST_HEAD(&pchan->rx_pending);
diff --git a/drivers/firmware/arm_scpi_test.c b/drivers/firmware/arm_scpi_test.c
new file mode 100644
index 000000000000..c21b35e6f4b8
--- /dev/null
+++ b/drivers/firmware/arm_scpi_test.c
@@ -0,0 +1,568 @@
+/*
+ * Test code for System Control and Power Interface (SCPI)
+ *
+ * Copyright (C) 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/scpi_protocol.h>
+
+
+static int stress_time;
+module_param(stress_time, int, 0644);
+MODULE_PARM_DESC(stress_time, "Number of seconds to run each stress test for, overides each test's default.");
+
+static int run;
+static struct kernel_param_ops run_ops;
+module_param_cb(run, &run_ops, &run, 0644);
+MODULE_PARM_DESC(run, "The number of the test case to run, or -1 for all, 0 to stop tests.");
+
+
+static struct scpi_ops *scpi;
+
+static struct task_struct *main_thread;
+
+static DEFINE_MUTEX(main_thread_lock);
+
+
+#define MAX_TEST_THREADS 4
+
+static struct test_thread {
+ struct task_struct *task;
+ int thread_num;
+} test_threads[MAX_TEST_THREADS];
+
+static DEFINE_MUTEX(thread_lock);
+
+
+#define MAX_POWER_DOMAINS 8
+
+static u16 num_sensors;
+static u8 num_pd;
+static u8 num_opps[MAX_POWER_DOMAINS];
+static struct mutex pd_lock[MAX_POWER_DOMAINS];
+static u8 num_devices_with_power_states;
+
+
+#define FLAG_SERIAL_DVFS (1<<0)
+#define FLAG_SERIAL_PD (1<<1)
+
+static int test_flags;
+
+
+static int sensor_pmic = -1;
+
+
+static u32 random_seed;
+
+static u32 random(u32 range)
+{
+ random_seed = random_seed*69069+1;
+
+ return ((u64)random_seed * (u64)range) >> 32;
+}
+
+
+static atomic_t passes;
+static atomic_t failures;
+
+static bool fail_on(bool fail)
+{
+ if (fail)
+ atomic_inc(&failures);
+ else
+ atomic_inc(&passes);
+ return fail;
+}
+
+static void show_results(const char *title)
+{
+ int fail = atomic_xchg(&failures, 0);
+ int pass = atomic_xchg(&passes, 0);
+
+ if (fail)
+ pr_err("Results for '%s' is %d/%d (pass/fail)\n", title, pass, fail);
+ else
+ pr_info("Results for '%s' is %d/%d (pass/fail)\n", title, pass, fail);
+}
+
+
+static bool check_name(const char *name)
+{
+ char c;
+
+ if (!isalpha(*name++))
+ return false;
+
+ while ((c = *name++))
+ if (!isalnum(c) && c != '_')
+ return false;
+
+ return true;
+}
+
+static u64 get_sensor(u16 id)
+{
+ u64 val;
+ int ret;
+
+ ret = scpi->sensor_get_value(id, &val);
+ if (fail_on(ret < 0))
+ pr_err("FAILED sensor_get_value %d (%d)\n", id, ret);
+
+ return val;
+}
+
+static void init_sensors(void)
+{
+ u16 id;
+ int ret;
+
+ ret = scpi->sensor_get_capability(&num_sensors);
+ if (fail_on(ret))
+ pr_err("FAILED sensor_get_capability (%d)\n", ret);
+
+ pr_info("num_sensors: %d\n", num_sensors);
+
+ for (id = 0; id < num_sensors; id++) {
+
+ struct scpi_sensor_info info;
+ char name[sizeof(info.name) + 1];
+
+ ret = scpi->sensor_get_info(id, &info);
+ if (fail_on(ret)) {
+ pr_err("FAILED sensor_get_info (%d)\n", ret);
+ continue;
+ }
+
+ /* Get sensor name, guarding against missing NUL terminator */
+ memcpy(name, info.name, sizeof(info.name));
+ name[sizeof(info.name)] = 0;
+
+ pr_info("sensor[%d] id=%d class=%d trigger=%d name=%s\n", id,
+ info.sensor_id, info.class, info.trigger_type, name);
+
+ if (fail_on(id != info.sensor_id))
+ pr_err("FAILED bad sensor id\n");
+ if (fail_on(info.class > 4))
+ pr_err("FAILED bad sensor class\n");
+ if (fail_on(info.trigger_type > 3))
+ pr_err("FAILED bad sensor trigger type\n");
+ if (fail_on(strlen(name) >= sizeof(info.name) || !check_name(name)))
+ pr_err("FAILED bad name\n");
+
+ pr_info("sensor[%d] value is %llu\n", id, get_sensor(id));
+ if (strstr(name, "PMIC"))
+ sensor_pmic = id;
+ }
+}
+
+static int get_dvfs(u8 pd)
+{
+ int ret = scpi->dvfs_get_idx(pd);
+
+ if (fail_on(ret < 0))
+ pr_err("FAILED get_dvfs %d (%d)\n", pd, ret);
+ else if (fail_on(ret >= num_opps[pd]))
+ pr_err("FAILED get_dvfs %d returned out of range index (%d)\n", pd, ret);
+
+ return ret;
+}
+
+static int set_dvfs(u8 pd, u8 opp)
+{
+ int ret;
+
+ if (test_flags & FLAG_SERIAL_DVFS)
+ mutex_lock(&pd_lock[0]);
+ else if (test_flags & FLAG_SERIAL_PD)
+ mutex_lock(&pd_lock[pd]);
+
+ ret = scpi->dvfs_set_idx(pd, opp);
+
+ if (test_flags & FLAG_SERIAL_DVFS)
+ mutex_unlock(&pd_lock[0]);
+ else if (test_flags & FLAG_SERIAL_PD)
+ mutex_unlock(&pd_lock[pd]);
+
+ if (fail_on(ret < 0))
+ pr_err("FAILED set_dvfs %d %d (%d)\n", pd, opp, ret);
+
+ return ret;
+}
+
+static void init_dvfs(void)
+{
+ u8 pd;
+
+ for (pd = 0; pd < MAX_POWER_DOMAINS; ++pd) {
+ struct scpi_dvfs_info *info;
+ int opp;
+
+ info = scpi->dvfs_get_info(pd);
+ if (IS_ERR(info)) {
+ pr_info("dvfs_get_info %d failed with %d assume because no more power domains\n",
+ pd, (int)PTR_ERR(info));
+ break;
+ }
+
+ num_opps[pd] = info->count;
+ mutex_init(&pd_lock[pd]);
+ pr_info("pd[%d] count=%u latency=%u\n",
+ pd, info->count, info->latency);
+
+ opp = get_dvfs(pd);
+ pr_info("pd[%d] current opp=%d\n", pd, opp);
+
+ for (opp = 0; opp < info->count; ++opp) {
+ pr_info("pd[%d].opp[%d] freq=%u m_volt=%u\n", pd, opp,
+ info->opps[opp].freq, info->opps[opp].m_volt);
+ /*
+ * Try setting each opp. Note, failure is not necessarily
+ * an error because cpufreq may be setting values too.
+ */
+ set_dvfs(pd, opp);
+ if (get_dvfs(pd) == opp)
+ pr_info("pd[%d] set to opp %d OK\n", pd, opp);
+ else
+ pr_warn("pd[%d] failed to set opp to %d\n", pd, opp);
+ }
+ }
+
+ if (!pd) {
+ /* Assume device should have at least one DVFS power domain */
+ pr_err("FAILED no power domains\n");
+ fail_on(true);
+ }
+ num_pd = pd;
+}
+
+static int device_get_power_state(u16 dev_id)
+{
+ int ret;
+
+ ret = scpi->device_get_power_state(dev_id);
+ if (fail_on(ret < 0))
+ pr_err("FAILED device_get_power_state %d (%d)\n", dev_id, ret);
+
+ return ret;
+}
+
+static int device_set_power_state(u16 dev_id, u8 pstate)
+{
+ int ret;
+
+ ret = scpi->device_set_power_state(dev_id, pstate);
+ if (fail_on(ret < 0))
+ pr_err("FAILED device_get_power_state %d (%d)\n", dev_id, ret);
+
+ return ret;
+}
+
+static void init_device_power_states(void)
+{
+ u16 dev_id;
+
+ for (dev_id = 0; dev_id < 0xffff; ++dev_id) {
+ int state = scpi->device_get_power_state(dev_id);
+
+ if (state < 0) {
+ pr_info("device_get_power_state %d failed with %d assume because no more devices\n",
+ dev_id, state);
+ break;
+ }
+
+ pr_info("device[%d] current state=%d\n", dev_id, state);
+
+ device_set_power_state(dev_id, state);
+ if (device_get_power_state(dev_id) == state)
+ pr_info("device[%d] set state to %d OK\n", dev_id, state);
+ else
+ pr_warn("device[%d] failed set state to %d\n", dev_id, state);
+ }
+
+ if (!dev_id) {
+ /* Assume device should have at least one device power state */
+ pr_err("FAILED no devices with power states\n");
+ fail_on(true);
+ }
+ num_devices_with_power_states = dev_id;
+}
+
+static int stress_pmic(void *data)
+{
+ int sensor, pd, opp;
+
+ while (!kthread_should_stop()) {
+ sensor = sensor_pmic;
+ pd = random(num_pd);
+ opp = random(num_opps[pd]);
+
+ switch (random(3)) {
+ case 0:
+ if (sensor >= 0) {
+ get_sensor(sensor);
+ break;
+ }
+ /* If no sensor, do DFVS... */
+ case 1:
+ set_dvfs(pd, opp);
+ break;
+ default:
+ msleep(random(20));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int stress_all(void *data)
+{
+ int sensor, pd, opp;
+
+ while (!kthread_should_stop()) {
+ sensor = random(num_sensors);
+ pd = random(num_pd);
+ opp = random(num_opps[pd]);
+
+ switch (random(4)) {
+ case 0:
+ set_dvfs(pd, opp);
+ break;
+ case 1:
+ opp = get_dvfs(pd);
+ break;
+ case 2:
+ get_sensor(sensor);
+ break;
+ default:
+ msleep(random(20));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+struct test {
+ const char *title;
+ int (*thread_fn)(void *);
+ int flags;
+ int num_threads;
+ int duration;
+};
+
+static void stop_test_threads(void)
+{
+ int t, ret;
+
+ for (t = 0; t < MAX_TEST_THREADS; ++t) {
+ struct test_thread *thread = &test_threads[t];
+
+ mutex_lock(&thread_lock);
+ if (thread->task) {
+ ret = kthread_stop(thread->task);
+ thread->task = NULL;
+ if (ret)
+ pr_warn("Test thread %d exited with status %d\n", t, ret);
+ }
+ mutex_unlock(&thread_lock);
+ }
+}
+
+static void run_test(struct test *test)
+{
+ int num_threads = min(test->num_threads, MAX_TEST_THREADS);
+ int duration = stress_time;
+ int t;
+
+ if (test->duration <= 0)
+ duration = 0;
+ else if (duration <= 0)
+ duration = test->duration;
+
+ pr_info("Running test '%s' for %d seconds\n", test->title, duration);
+
+ test_flags = test->flags;
+
+ for (t = 0; t < num_threads; ++t) {
+ struct test_thread *thread = &test_threads[t];
+ struct task_struct *task;
+
+ mutex_lock(&thread_lock);
+ thread->thread_num = t;
+ task = kthread_run(test->thread_fn, thread, "scpi-test-%d", t);
+ if (IS_ERR(task))
+ pr_warn("Failed to create test thread %d\n", t);
+ else
+ thread->task = task;
+ mutex_unlock(&thread_lock);
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(duration * 1000));
+
+ stop_test_threads();
+
+ show_results(test->title);
+}
+
+static struct test tests[] = {
+ {"Stress All, concurrent DVFS",
+ stress_all, 0, MAX_TEST_THREADS, 60},
+ {"Stress All, concurrent DVFS on different PDs",
+ stress_all, FLAG_SERIAL_PD, MAX_TEST_THREADS, 60},
+ {"Stress All, no concurrent DVFS",
+ stress_all, FLAG_SERIAL_DVFS, MAX_TEST_THREADS, 60},
+ {"Stress PMIC, concurrent DVFS",
+ stress_pmic, 0, MAX_TEST_THREADS, 60},
+ {"Stress PMIC, concurrent DVFS on different PDs",
+ stress_pmic, FLAG_SERIAL_PD, MAX_TEST_THREADS, 60},
+ {"Stress PMIC, no concurrent DVFS",
+ stress_pmic, FLAG_SERIAL_DVFS, MAX_TEST_THREADS, 60},
+ {}
+};
+
+static int main_thread_fn(void *data)
+{
+ struct test *test = tests;
+ int i = 1;
+
+ for (; test->title && !kthread_should_stop(); ++test, ++i)
+ if (run < 0 || run == i)
+ run_test(test);
+
+ run = 0;
+ return 0;
+}
+
+static DEFINE_MUTEX(setup_lock);
+
+static int setup(void)
+{
+ int ret = 0;
+
+ mutex_lock(&setup_lock);
+
+ if (!scpi) {
+ int tries = 12;
+
+ pr_info("Initial setup\n");
+ while ((scpi = get_scpi_ops()) == 0 && --tries) {
+ pr_info("Waiting for get_scpi_ops\n");
+ msleep(5000);
+ }
+
+ if (scpi) {
+ init_sensors();
+ init_dvfs();
+ init_device_power_states();
+ show_results("Initial setup");
+ } else {
+ pr_err("Given up on get_scpi_ops\n");
+ ret = -ENODEV;
+ }
+ }
+
+ mutex_unlock(&setup_lock);
+
+ return ret;
+}
+
+static int start_tests(void)
+{
+ struct task_struct *task;
+ int ret;
+
+ ret = setup();
+ if (ret) {
+ run = 0;
+ return ret;
+ }
+
+ pr_info("Creating main thread\n");
+ mutex_lock(&main_thread_lock);
+ if (main_thread) {
+ ret = -EBUSY;
+ } else {
+ task = kthread_run(main_thread_fn, 0, "scpi-test-main");
+ if (IS_ERR(task))
+ ret = PTR_ERR(task);
+ else
+ main_thread = task;
+ }
+ mutex_unlock(&main_thread_lock);
+
+ if (ret) {
+ pr_err("Failed to create main thread (%d)\n", ret);
+ run = 0;
+ }
+
+ return ret;
+}
+
+static void stop_tests(void)
+{
+ pr_info("Stopping tests\n");
+ mutex_lock(&main_thread_lock);
+ if (main_thread)
+ kthread_stop(main_thread);
+ main_thread = NULL;
+ mutex_unlock(&main_thread_lock);
+}
+
+static int param_set_running(const char *val, const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_int(val, kp);
+ if (!ret) {
+ if (run)
+ ret = start_tests();
+ else
+ stop_tests();
+ }
+
+ return ret;
+}
+
+static struct kernel_param_ops run_ops = {
+ .set = param_set_running,
+ .get = param_get_int,
+};
+
+
+static int scpi_test_init(void)
+{
+ return 0;
+}
+
+static void scpi_test_exit(void)
+{
+ stop_tests();
+}
+
+module_init(scpi_test_init);
+module_exit(scpi_test_exit);
+
+
+MODULE_AUTHOR("Jon Medhurst (Tixy) <tixy@linaro.org>");
+MODULE_DESCRIPTION("ARM SCPI driver tests");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 78d7fc0ebb57..7d7e0fd19edf 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -203,6 +203,14 @@ config DRM_VGEM
as used by Mesa's software renderer for enhanced performance.
If M is selected the module will be called vgem.
+config DRM_VIRT_ENCODER
+ tristate "Virtual OF-based encoder"
+ depends on DRM && OF
+ help
+ Choose this option to get a virtual encoder and its associated
+ connector that will use the device tree to read the display
+ timings information. If M is selected the module will be called
+ drm_vencoder.
source "drivers/gpu/drm/exynos/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 59f0f9b696eb..4eb316e8fa2b 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -44,6 +44,9 @@ obj-$(CONFIG_DRM_DEBUG_MM_SELFTEST) += selftests/
CFLAGS_drm_trace_points.o := -I$(src)
+drm_vencoder-y := drm_virtual_encoder.o
+obj-$(CONFIG_DRM_VIRT_ENCODER) += drm_vencoder.o
+
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
obj-$(CONFIG_DRM_ARM) += arm/
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
index bb8b158ff90d..0ade075b3568 100644
--- a/drivers/gpu/drm/arm/Makefile
+++ b/drivers/gpu/drm/arm/Makefile
@@ -1,4 +1,4 @@
-hdlcd-y := hdlcd_drv.o hdlcd_crtc.o
+hdlcd-y := hdlcd_drv.o hdlcd_crtc.o hdlcd_fb_helper.o
obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index 1a3359c0f6cd..9cbb8ca2459e 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -15,7 +15,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_fb_cma_helper.h>
+#include "hdlcd_fb_helper.h"
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_plane_helper.h>
@@ -83,6 +83,8 @@ static int hdlcd_set_pxl_fmt(struct drm_crtc *crtc)
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
const struct drm_framebuffer *fb = crtc->primary->state->fb;
uint32_t pixel_format;
+ bool swap_red_blue = false;
+ u32 hbi;
struct simplefb_format *format = NULL;
int i;
@@ -110,16 +112,36 @@ static int hdlcd_set_pxl_fmt(struct drm_crtc *crtc)
* pixel is outside the visible frame area or when there is a
* buffer underrun.
*/
- hdlcd_write(hdlcd, HDLCD_REG_RED_SELECT, format->red.offset |
+ if (of_property_read_u32(of_root, "arm,hbi", &hbi) == 0) {
+ /*
+ * This is a hack to swap read and blue when building for some
+ * Versatile Express CoreTiles because they seem to be wired up
+ * differently.
+ */
+ if (hbi == 0x249) /* TC2 */
+ swap_red_blue = true;
+ }
+ if(!swap_red_blue) {
+ hdlcd_write(hdlcd, HDLCD_REG_RED_SELECT, format->red.offset |
#ifdef CONFIG_DRM_HDLCD_SHOW_UNDERRUN
- 0x00ff0000 | /* show underruns in red */
+ 0x00ff0000 | /* show underruns in red */
#endif
- ((format->red.length & 0xf) << 8));
- hdlcd_write(hdlcd, HDLCD_REG_GREEN_SELECT, format->green.offset |
- ((format->green.length & 0xf) << 8));
- hdlcd_write(hdlcd, HDLCD_REG_BLUE_SELECT, format->blue.offset |
- ((format->blue.length & 0xf) << 8));
-
+ ((format->red.length & 0xf) << 8));
+ hdlcd_write(hdlcd, HDLCD_REG_GREEN_SELECT, format->green.offset |
+ ((format->green.length & 0xf) << 8));
+ hdlcd_write(hdlcd, HDLCD_REG_BLUE_SELECT, format->blue.offset |
+ ((format->blue.length & 0xf) << 8));
+ } else {
+ hdlcd_write(hdlcd, HDLCD_REG_BLUE_SELECT, format->red.offset |
+#ifdef CONFIG_DRM_HDLCD_SHOW_UNDERRUN
+ 0x00ff0000 | /* show underruns in red */
+#endif
+ ((format->red.length & 0xf) << 8));
+ hdlcd_write(hdlcd, HDLCD_REG_GREEN_SELECT, format->green.offset |
+ ((format->green.length & 0xf) << 8));
+ hdlcd_write(hdlcd, HDLCD_REG_RED_SELECT, format->blue.offset |
+ ((format->blue.length & 0xf) << 8));
+ }
return 0;
}
@@ -271,7 +293,7 @@ static void hdlcd_plane_atomic_update(struct drm_plane *plane,
src_x = plane->state->src.x1 >> 16;
src_y = plane->state->src.y1 >> 16;
dest_h = drm_rect_height(&plane->state->dst);
- gem = drm_fb_cma_get_gem_obj(fb, 0);
+ gem = hdlcd_fb_get_gem_obj(fb, 0);
scanout_start = gem->paddr + fb->offsets[0] +
src_y * fb->pitches[0] +
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index 0f49c4b12772..ea19a4781ba9 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -23,7 +23,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_fb_cma_helper.h>
+#include "hdlcd_fb_helper.h"
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
@@ -67,6 +67,12 @@ static int hdlcd_load(struct drm_device *drm, unsigned long flags)
(version & HDLCD_VERSION_MAJOR_MASK) >> 8,
version & HDLCD_VERSION_MINOR_MASK);
+ /* Make sure hardware is in a safe reset state */
+ hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
+ hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, 0);
+ hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR,~0);
+ hdlcd_write(hdlcd, HDLCD_REG_INT_RAWSTAT, 0);
+
/* Get the optional framebuffer memory resource */
ret = of_reserved_mem_device_init(drm->dev);
if (ret && ret != -ENODEV)
@@ -88,6 +94,9 @@ static int hdlcd_load(struct drm_device *drm, unsigned long flags)
goto irq_fail;
}
+ spin_lock_init(&hdlcd->frame_completion_lock);
+ init_completion(&hdlcd->frame_completion);
+
return 0;
irq_fail:
@@ -102,11 +111,11 @@ static void hdlcd_fb_output_poll_changed(struct drm_device *drm)
{
struct hdlcd_drm_private *hdlcd = drm->dev_private;
- drm_fbdev_cma_hotplug_event(hdlcd->fbdev);
+ hdlcd_drm_fbdev_hotplug_event(hdlcd->fbdev);
}
static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = {
- .fb_create = drm_fb_cma_create,
+ .fb_create = hdlcd_fb_create,
.output_poll_changed = hdlcd_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
@@ -126,7 +135,7 @@ static void hdlcd_lastclose(struct drm_device *drm)
{
struct hdlcd_drm_private *hdlcd = drm->dev_private;
- drm_fbdev_cma_restore_mode(hdlcd->fbdev);
+ hdlcd_drm_fbdev_restore_mode(hdlcd->fbdev);
}
static irqreturn_t hdlcd_irq(int irq, void *arg)
@@ -134,6 +143,7 @@ static irqreturn_t hdlcd_irq(int irq, void *arg)
struct drm_device *drm = arg;
struct hdlcd_drm_private *hdlcd = drm->dev_private;
unsigned long irq_status;
+ unsigned long flags;
irq_status = hdlcd_read(hdlcd, HDLCD_REG_INT_STATUS);
@@ -154,6 +164,16 @@ static irqreturn_t hdlcd_irq(int irq, void *arg)
if (irq_status & HDLCD_INTERRUPT_VSYNC)
drm_crtc_handle_vblank(&hdlcd->crtc);
+ spin_lock_irqsave(&hdlcd->frame_completion_lock, flags);
+ if (hdlcd_read(hdlcd, HDLCD_REG_INT_STATUS) & HDLCD_INTERRUPT_DMA_END) {
+ /* Clear DMA_END interrupt here, under frame_completion_lock */
+ hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, HDLCD_INTERRUPT_DMA_END);
+ irq_status &= ~HDLCD_INTERRUPT_DMA_END;
+ /* Wake up everyone waiting for frame completion */
+ complete_all(&hdlcd->frame_completion);
+ }
+ spin_unlock_irqrestore(&hdlcd->frame_completion_lock, flags);
+
/* acknowledge interrupt(s) */
hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, irq_status);
@@ -170,15 +190,18 @@ static void hdlcd_irq_preinstall(struct drm_device *drm)
static int hdlcd_irq_postinstall(struct drm_device *drm)
{
-#ifdef CONFIG_DEBUG_FS
struct hdlcd_drm_private *hdlcd = drm->dev_private;
unsigned long irq_mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
+#ifdef CONFIG_DEBUG_FS
/* enable debug interrupts */
irq_mask |= HDLCD_DEBUG_INT_MASK;
+#endif
+ /* enable DMA completion interrupts */
+ irq_mask |= HDLCD_INTERRUPT_DMA_END;
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask);
-#endif
+
return 0;
}
@@ -193,12 +216,34 @@ static void hdlcd_irq_uninstall(struct drm_device *drm)
irq_mask &= ~HDLCD_DEBUG_INT_MASK;
#endif
- /* disable vsync interrupts */
- irq_mask &= ~HDLCD_INTERRUPT_VSYNC;
+ /* disable vsync and dma interrupts */
+ irq_mask &= ~(HDLCD_INTERRUPT_VSYNC | HDLCD_INTERRUPT_DMA_END);
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask);
}
+void hdlcd_wait_for_frame_completion(struct drm_device *drm)
+{
+ struct hdlcd_drm_private *hdlcd = drm->dev_private;
+
+ if (drm_crtc_vblank_get(&hdlcd->crtc))
+ return; /* vblank interrupts not available so don't try and wait */
+
+ /*
+ * Clear pending interrupts and completions so we won't get signalled
+ * for any earlier frames,
+ */
+ spin_lock_irq(&hdlcd->frame_completion_lock);
+ hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, HDLCD_INTERRUPT_DMA_END);
+ reinit_completion(&hdlcd->frame_completion);
+ spin_unlock_irq(&hdlcd->frame_completion_lock);
+
+ /* Wait for end of current frame */
+ wait_for_completion_interruptible_timeout(&hdlcd->frame_completion, HZ / 10);
+
+ drm_crtc_vblank_put(&hdlcd->crtc);
+}
+
#ifdef CONFIG_DEBUG_FS
static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
{
@@ -229,7 +274,7 @@ static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
static struct drm_info_list hdlcd_debugfs_list[] = {
{ "interrupt_count", hdlcd_show_underrun_count, 0 },
{ "clocks", hdlcd_show_pxlclock, 0 },
- { "fb", drm_fb_cma_debugfs_show, 0 },
+ { "fb", hdlcd_fb_debugfs_show, 0 },
};
static int hdlcd_debugfs_init(struct drm_minor *minor)
@@ -280,6 +325,8 @@ static int hdlcd_drm_bind(struct device *dev)
struct drm_device *drm;
struct hdlcd_drm_private *hdlcd;
int ret;
+ struct device_node *node;
+ int preferred_bpp;
hdlcd = devm_kzalloc(dev, sizeof(*hdlcd), GFP_KERNEL);
if (!hdlcd)
@@ -318,7 +365,15 @@ static int hdlcd_drm_bind(struct device *dev)
drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm);
- hdlcd->fbdev = drm_fbdev_cma_init(drm, 32,
+ /* Try to pick the colour depth that Android user-side is hard-coded for */
+ preferred_bpp = 16;
+ node = of_find_compatible_node(NULL,NULL,"arm,mali-midgard");
+ if (node) {
+ of_node_put(node);
+ preferred_bpp = 32; /* If Mali present, assume 32bpp */
+ }
+
+ hdlcd->fbdev = hdlcd_drm_fbdev_init(drm, preferred_bpp,
drm->mode_config.num_connector);
if (IS_ERR(hdlcd->fbdev)) {
@@ -335,7 +390,7 @@ static int hdlcd_drm_bind(struct device *dev)
err_register:
if (hdlcd->fbdev) {
- drm_fbdev_cma_fini(hdlcd->fbdev);
+ hdlcd_drm_fbdev_fini(hdlcd->fbdev);
hdlcd->fbdev = NULL;
}
err_fbdev:
@@ -363,7 +418,7 @@ static void hdlcd_drm_unbind(struct device *dev)
drm_dev_unregister(drm);
if (hdlcd->fbdev) {
- drm_fbdev_cma_fini(hdlcd->fbdev);
+ hdlcd_drm_fbdev_fini(hdlcd->fbdev);
hdlcd->fbdev = NULL;
}
drm_kms_helper_poll_fini(drm);
@@ -465,7 +520,19 @@ static struct platform_driver hdlcd_platform_driver = {
},
};
-module_platform_driver(hdlcd_platform_driver);
+static int __init hdlcd_init(void)
+{
+ return platform_driver_register(&hdlcd_platform_driver);
+}
+
+static void __exit hdlcd_exit(void)
+{
+ platform_driver_unregister(&hdlcd_platform_driver);
+}
+
+/* need late_initcall() so we load after i2c driver */
+late_initcall(hdlcd_init);
+module_exit(hdlcd_exit);
MODULE_AUTHOR("Liviu Dudau");
MODULE_DESCRIPTION("ARM HDLCD DRM driver");
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
index e3950a071152..e76d99cfeada 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.h
+++ b/drivers/gpu/drm/arm/hdlcd_drv.h
@@ -8,10 +8,12 @@
struct hdlcd_drm_private {
void __iomem *mmio;
struct clk *clk;
- struct drm_fbdev_cma *fbdev;
+ struct hdlcd_drm_fbdev *fbdev;
struct drm_crtc crtc;
struct drm_plane *plane;
struct drm_atomic_state *state;
+ spinlock_t frame_completion_lock;
+ struct completion frame_completion;
#ifdef CONFIG_DEBUG_FS
atomic_t buffer_underrun_count;
atomic_t bus_error_count;
@@ -36,4 +38,6 @@ static inline u32 hdlcd_read(struct hdlcd_drm_private *hdlcd, unsigned int reg)
int hdlcd_setup_crtc(struct drm_device *dev);
void hdlcd_set_scanout(struct hdlcd_drm_private *hdlcd);
+void hdlcd_wait_for_frame_completion(struct drm_device *drm);
+
#endif /* __HDLCD_DRV_H__ */
diff --git a/drivers/gpu/drm/arm/hdlcd_fb_helper.c b/drivers/gpu/drm/arm/hdlcd_fb_helper.c
new file mode 100644
index 000000000000..1963dbc9fd3d
--- /dev/null
+++ b/drivers/gpu/drm/arm/hdlcd_fb_helper.c
@@ -0,0 +1,855 @@
+/*
+ * drm kms/fb cma (contiguous memory allocator) helper functions
+ *
+ * Copyright (C) 2012 Analog Device Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Based on udl_fbdev.c
+ * Copyright (C) 2012 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include "hdlcd_fb_helper.h"
+#include <linux/dma-buf.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/reservation.h>
+
+#include "hdlcd_drv.h"
+#include "hdlcd_regs.h"
+
+#define DEFAULT_FBDEFIO_DELAY_MS 50
+
+#define MAX_FRAMES 2
+
+static int hdlcd_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
+
+/******************************************************************************
+ * Code copied from drivers/gpu/drm/drm_fb_helper.c as of Linux 4.11-rc4
+ ******************************************************************************/
+
+/**
+ * Copy of drm_fb_helper_check_var modified to allow MAX_FRAMES * height
+ */
+static int hdlcd_fb_helper_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_framebuffer *fb = fb_helper->fb;
+ int depth;
+
+ if (var->pixclock != 0 || in_dbg_master())
+ return -EINVAL;
+
+ /*
+ * Changes struct fb_var_screeninfo are currently not pushed back
+ * to KMS, hence fail if different settings are requested.
+ */
+ if (var->bits_per_pixel != fb->format->cpp[0] * 8 ||
+ var->xres > fb->width || var->yres > fb->height ||
+ var->xres_virtual > fb->width || var->yres_virtual > fb->height * MAX_FRAMES) {
+ DRM_DEBUG("fb requested width/height/bpp can't fit in current fb "
+ "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
+ var->xres, var->yres, var->bits_per_pixel,
+ var->xres_virtual, var->yres_virtual,
+ fb->width, fb->height, fb->format->cpp[0] * 8);
+ return -EINVAL;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ depth = (var->green.length == 6) ? 16 : 15;
+ break;
+ case 32:
+ depth = (var->transp.length > 0) ? 32 : 24;
+ break;
+ default:
+ depth = var->bits_per_pixel;
+ break;
+ }
+
+ switch (depth) {
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 15:
+ var->red.offset = 10;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 1;
+ var->transp.offset = 15;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 24:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Code copied from drivers/gpu/drm/drm_fb_cma_helper.c as of Linux 4.4
+ ******************************************************************************/
+
+struct hdlcd_fb {
+ struct drm_framebuffer fb;
+ struct drm_gem_cma_object *obj[4];
+};
+
+struct hdlcd_drm_fbdev {
+ struct drm_fb_helper fb_helper;
+ struct hdlcd_fb *fb;
+ const struct drm_framebuffer_funcs *fb_funcs;
+};
+
+/**
+ * DOC: framebuffer cma helper functions
+ *
+ * Provides helper functions for creating a cma (contiguous memory allocator)
+ * backed framebuffer.
+ *
+ * hdlcd_fb_create() is used in the &drm_mode_config_funcs.fb_create
+ * callback function to create a cma backed framebuffer.
+ *
+ * An fbdev framebuffer backed by cma is also available by calling
+ * hdlcd_drm_fbdev_init(). hdlcd_drm_fbdev_fini() tears it down.
+ * If the &drm_framebuffer_funcs.dirty callback is set, fb_deferred_io will be
+ * set up automatically. &drm_framebuffer_funcs.dirty is called by
+ * drm_fb_helper_deferred_io() in process context (&struct delayed_work).
+ *
+ * Example fbdev deferred io code::
+ *
+ * static int driver_fb_dirty(struct drm_framebuffer *fb,
+ * struct drm_file *file_priv,
+ * unsigned flags, unsigned color,
+ * struct drm_clip_rect *clips,
+ * unsigned num_clips)
+ * {
+ * struct drm_gem_cma_object *cma = hdlcd_fb_get_gem_obj(fb, 0);
+ * ... push changes ...
+ * return 0;
+ * }
+ *
+ * static struct drm_framebuffer_funcs driver_fb_funcs = {
+ * .destroy = hdlcd_fb_destroy,
+ * .create_handle = hdlcd_fb_create_handle,
+ * .dirty = driver_fb_dirty,
+ * };
+ *
+ * Initialize::
+ *
+ * fbdev = hdlcd_drm_fbdev_init_with_funcs(dev, 16,
+ * dev->mode_config.num_crtc,
+ * dev->mode_config.num_connector,
+ * &driver_fb_funcs);
+ *
+ */
+
+static inline struct hdlcd_drm_fbdev *to_hdlcd_fbdev(struct drm_fb_helper *helper)
+{
+ return container_of(helper, struct hdlcd_drm_fbdev, fb_helper);
+}
+
+static inline struct hdlcd_fb *to_hdlcd_fb(struct drm_framebuffer *fb)
+{
+ return container_of(fb, struct hdlcd_fb, fb);
+}
+
+void hdlcd_fb_destroy(struct drm_framebuffer *fb)
+{
+ struct hdlcd_fb *hdlcd_fb = to_hdlcd_fb(fb);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (hdlcd_fb->obj[i])
+ drm_gem_object_put_unlocked(&hdlcd_fb->obj[i]->base);
+ }
+
+ drm_framebuffer_cleanup(fb);
+ kfree(hdlcd_fb);
+}
+EXPORT_SYMBOL(hdlcd_fb_destroy);
+
+int hdlcd_fb_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file_priv, unsigned int *handle)
+{
+ struct hdlcd_fb *hdlcd_fb = to_hdlcd_fb(fb);
+
+ return drm_gem_handle_create(file_priv,
+ &hdlcd_fb->obj[0]->base, handle);
+}
+EXPORT_SYMBOL(hdlcd_fb_create_handle);
+
+static struct drm_framebuffer_funcs hdlcd_fb_funcs = {
+ .destroy = hdlcd_fb_destroy,
+ .create_handle = hdlcd_fb_create_handle,
+};
+
+static struct hdlcd_fb *hdlcd_fb_alloc(struct drm_device *dev,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_cma_object **obj,
+ unsigned int num_planes, const struct drm_framebuffer_funcs *funcs)
+{
+ struct hdlcd_fb *hdlcd_fb;
+ int ret;
+ int i;
+
+ hdlcd_fb = kzalloc(sizeof(*hdlcd_fb), GFP_KERNEL);
+ if (!hdlcd_fb)
+ return ERR_PTR(-ENOMEM);
+
+ drm_helper_mode_fill_fb_struct(dev, &hdlcd_fb->fb, mode_cmd);
+
+ for (i = 0; i < num_planes; i++)
+ hdlcd_fb->obj[i] = obj[i];
+
+ ret = drm_framebuffer_init(dev, &hdlcd_fb->fb, funcs);
+ if (ret) {
+ dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret);
+ kfree(hdlcd_fb);
+ return ERR_PTR(ret);
+ }
+
+ return hdlcd_fb;
+}
+
+/**
+ * hdlcd_fb_create_with_funcs() - helper function for the
+ * &drm_mode_config_funcs.fb_create
+ * callback
+ * @dev: DRM device
+ * @file_priv: drm file for the ioctl call
+ * @mode_cmd: metadata from the userspace fb creation request
+ * @funcs: vtable to be used for the new framebuffer object
+ *
+ * This can be used to set &drm_framebuffer_funcs for drivers that need the
+ * &drm_framebuffer_funcs.dirty callback. Use hdlcd_fb_create() if you don't
+ * need to change &drm_framebuffer_funcs.
+ */
+struct drm_framebuffer *hdlcd_fb_create_with_funcs(struct drm_device *dev,
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_framebuffer_funcs *funcs)
+{
+ const struct drm_format_info *info;
+ struct hdlcd_fb *hdlcd_fb;
+ struct drm_gem_cma_object *objs[4];
+ struct drm_gem_object *obj;
+ int ret;
+ int i;
+
+ info = drm_get_format_info(dev, mode_cmd);
+ if (!info)
+ return ERR_PTR(-EINVAL);
+
+ for (i = 0; i < info->num_planes; i++) {
+ unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
+ unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
+ unsigned int min_size;
+
+ obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
+ if (!obj) {
+ dev_err(dev->dev, "Failed to lookup GEM object\n");
+ ret = -ENXIO;
+ goto err_gem_object_put;
+ }
+
+ min_size = (height - 1) * mode_cmd->pitches[i]
+ + width * info->cpp[i]
+ + mode_cmd->offsets[i];
+
+ if (obj->size < min_size) {
+ drm_gem_object_put_unlocked(obj);
+ ret = -EINVAL;
+ goto err_gem_object_put;
+ }
+ objs[i] = to_drm_gem_cma_obj(obj);
+ }
+
+ hdlcd_fb = hdlcd_fb_alloc(dev, mode_cmd, objs, i, funcs);
+ if (IS_ERR(hdlcd_fb)) {
+ ret = PTR_ERR(hdlcd_fb);
+ goto err_gem_object_put;
+ }
+
+ return &hdlcd_fb->fb;
+
+err_gem_object_put:
+ for (i--; i >= 0; i--)
+ drm_gem_object_put_unlocked(&objs[i]->base);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(hdlcd_fb_create_with_funcs);
+
+/**
+ * hdlcd_fb_create() - &drm_mode_config_funcs.fb_create callback function
+ * @dev: DRM device
+ * @file_priv: drm file for the ioctl call
+ * @mode_cmd: metadata from the userspace fb creation request
+ *
+ * If your hardware has special alignment or pitch requirements these should be
+ * checked before calling this function. Use hdlcd_fb_create_with_funcs() if
+ * you need to set &drm_framebuffer_funcs.dirty.
+ */
+struct drm_framebuffer *hdlcd_fb_create(struct drm_device *dev,
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ return hdlcd_fb_create_with_funcs(dev, file_priv, mode_cmd,
+ &hdlcd_fb_funcs);
+}
+EXPORT_SYMBOL_GPL(hdlcd_fb_create);
+
+/**
+ * hdlcd_fb_get_gem_obj() - Get CMA GEM object for framebuffer
+ * @fb: The framebuffer
+ * @plane: Which plane
+ *
+ * Return the CMA GEM object for given framebuffer.
+ *
+ * This function will usually be called from the CRTC callback functions.
+ */
+struct drm_gem_cma_object *hdlcd_fb_get_gem_obj(struct drm_framebuffer *fb,
+ unsigned int plane)
+{
+ struct hdlcd_fb *hdlcd_fb = to_hdlcd_fb(fb);
+
+ if (plane >= 4)
+ return NULL;
+
+ return hdlcd_fb->obj[plane];
+}
+EXPORT_SYMBOL_GPL(hdlcd_fb_get_gem_obj);
+
+/**
+ * hdlcd_fb_prepare_fb() - Prepare CMA framebuffer
+ * @plane: Which plane
+ * @state: Plane state attach fence to
+ *
+ * This should be set as the &struct drm_plane_helper_funcs.prepare_fb hook.
+ *
+ * This function checks if the plane FB has an dma-buf attached, extracts
+ * the exclusive fence and attaches it to plane state for the atomic helper
+ * to wait on.
+ *
+ * There is no need for cleanup_fb for CMA based framebuffer drivers.
+ */
+int hdlcd_fb_prepare_fb(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct dma_buf *dma_buf;
+ struct dma_fence *fence;
+
+ if ((plane->state->fb == state->fb) || !state->fb)
+ return 0;
+
+ dma_buf = hdlcd_fb_get_gem_obj(state->fb, 0)->base.dma_buf;
+ if (dma_buf) {
+ fence = reservation_object_get_excl_rcu(dma_buf->resv);
+ drm_atomic_set_fence_for_plane(state, fence);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hdlcd_fb_prepare_fb);
+
+#ifdef CONFIG_DEBUG_FS
+static void hdlcd_fb_describe(struct drm_framebuffer *fb, struct seq_file *m)
+{
+ struct hdlcd_fb *hdlcd_fb = to_hdlcd_fb(fb);
+ int i;
+
+ seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height,
+ (char *)&fb->format->format);
+
+ for (i = 0; i < fb->format->num_planes; i++) {
+ seq_printf(m, " %d: offset=%d pitch=%d, obj: ",
+ i, fb->offsets[i], fb->pitches[i]);
+ drm_gem_cma_describe(hdlcd_fb->obj[i], m);
+ }
+}
+
+/**
+ * hdlcd_fb_debugfs_show() - Helper to list CMA framebuffer objects
+ * in debugfs.
+ * @m: output file
+ * @arg: private data for the callback
+ */
+int hdlcd_fb_debugfs_show(struct seq_file *m, void *arg)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_framebuffer *fb;
+
+ mutex_lock(&dev->mode_config.fb_lock);
+ drm_for_each_fb(fb, dev)
+ hdlcd_fb_describe(fb, m);
+ mutex_unlock(&dev->mode_config.fb_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hdlcd_fb_debugfs_show);
+#endif
+
+static int hdlcd_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ return dma_mmap_writecombine(info->device, vma, info->screen_base,
+ info->fix.smem_start, info->fix.smem_len);
+}
+
+static int hdlcd_fb_helper_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct drm_fb_helper *helper = info->par;
+ struct drm_framebuffer *fb = helper->fb;
+ struct hdlcd_drm_private *hdlcd = helper->dev->dev_private;
+ struct drm_gem_cma_object *gem;
+ dma_addr_t scanout_start;
+ int ret;
+
+ ret = hdlcd_fb_helper_check_var(var, info);
+ if (ret)
+ return ret;
+
+ gem = hdlcd_fb_get_gem_obj(fb, 0);
+
+ scanout_start = gem->paddr + fb->offsets[0] +
+ (var->yoffset * fb->pitches[0]) + (var->xoffset * fb->format->cpp[0]);
+
+ hdlcd_write(hdlcd, HDLCD_REG_FB_BASE, scanout_start);
+
+ hdlcd_wait_for_frame_completion(helper->dev);
+
+ return 0;
+}
+
+static struct fb_ops hdlcd_drm_fbdev_ops = {
+ .owner = THIS_MODULE,
+ DRM_FB_HELPER_DEFAULT_OPS,
+ .fb_fillrect = drm_fb_helper_sys_fillrect,
+ .fb_copyarea = drm_fb_helper_sys_copyarea,
+ .fb_imageblit = drm_fb_helper_sys_imageblit,
+ .fb_mmap = hdlcd_fb_mmap,
+ .fb_ioctl = hdlcd_fb_ioctl,
+ .fb_compat_ioctl= hdlcd_fb_ioctl,
+};
+
+static int hdlcd_drm_fbdev_deferred_io_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ fb_deferred_io_mmap(info, vma);
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ return 0;
+}
+
+static int hdlcd_drm_fbdev_defio_init(struct fb_info *fbi,
+ struct drm_gem_cma_object *cma_obj)
+{
+ struct fb_deferred_io *fbdefio;
+ struct fb_ops *fbops;
+
+ /*
+ * Per device structures are needed because:
+ * fbops: fb_deferred_io_cleanup() clears fbops.fb_mmap
+ * fbdefio: individual delays
+ */
+ fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL);
+ fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+ if (!fbdefio || !fbops) {
+ kfree(fbdefio);
+ kfree(fbops);
+ return -ENOMEM;
+ }
+
+ /* can't be offset from vaddr since dirty() uses cma_obj */
+ fbi->screen_buffer = cma_obj->vaddr;
+ /* fb_deferred_io_fault() needs a physical address */
+ fbi->fix.smem_start = page_to_phys(virt_to_page(fbi->screen_buffer));
+
+ *fbops = *fbi->fbops;
+ fbi->fbops = fbops;
+
+ fbdefio->delay = msecs_to_jiffies(DEFAULT_FBDEFIO_DELAY_MS);
+ fbdefio->deferred_io = drm_fb_helper_deferred_io;
+ fbi->fbdefio = fbdefio;
+ fb_deferred_io_init(fbi);
+ fbi->fbops->fb_mmap = hdlcd_drm_fbdev_deferred_io_mmap;
+
+ return 0;
+}
+
+static void hdlcd_drm_fbdev_defio_fini(struct fb_info *fbi)
+{
+ if (!fbi->fbdefio)
+ return;
+
+ fb_deferred_io_cleanup(fbi);
+ kfree(fbi->fbdefio);
+ kfree(fbi->fbops);
+}
+
+static int
+hdlcd_drm_fbdev_create(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct hdlcd_drm_fbdev *hdlcd_fbdev = to_hdlcd_fbdev(helper);
+ struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+ struct drm_device *dev = helper->dev;
+ struct drm_gem_cma_object *obj;
+ struct drm_framebuffer *fb;
+ unsigned int bytes_per_pixel;
+ unsigned long offset;
+ struct fb_info *fbi;
+ size_t size;
+ int ret;
+
+ DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
+ sizes->surface_width, sizes->surface_height,
+ sizes->surface_bpp);
+
+ bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ size = mode_cmd.pitches[0] * mode_cmd.height * MAX_FRAMES;
+ obj = drm_gem_cma_create(dev, size);
+ if (IS_ERR(obj))
+ return -ENOMEM;
+
+ fbi = drm_fb_helper_alloc_fbi(helper);
+ if (IS_ERR(fbi)) {
+ ret = PTR_ERR(fbi);
+ goto err_gem_free_object;
+ }
+
+ hdlcd_fbdev->fb = hdlcd_fb_alloc(dev, &mode_cmd, &obj, 1,
+ hdlcd_fbdev->fb_funcs);
+ if (IS_ERR(hdlcd_fbdev->fb)) {
+ dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
+ ret = PTR_ERR(hdlcd_fbdev->fb);
+ goto err_fb_info_destroy;
+ }
+
+ fb = &hdlcd_fbdev->fb->fb;
+ helper->fb = fb;
+
+ fbi->par = helper;
+ fbi->flags = FBINFO_FLAG_DEFAULT;
+ hdlcd_drm_fbdev_ops.fb_check_var = hdlcd_fb_helper_check_var;
+ hdlcd_drm_fbdev_ops.fb_pan_display = hdlcd_fb_helper_pan_display;
+ fbi->fbops = &hdlcd_drm_fbdev_ops;
+
+ drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
+ drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
+
+ offset = fbi->var.xoffset * bytes_per_pixel;
+ offset += fbi->var.yoffset * fb->pitches[0];
+
+ dev->mode_config.fb_base = (resource_size_t)obj->paddr;
+ fbi->screen_base = obj->vaddr + offset;
+ fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
+ fbi->screen_size = size;
+ fbi->fix.smem_len = size;
+ fbi->var.yres_virtual = fbi->var.yres * MAX_FRAMES;
+
+ if (hdlcd_fbdev->fb_funcs->dirty) {
+ ret = hdlcd_drm_fbdev_defio_init(fbi, obj);
+ if (ret)
+ goto err_cma_destroy;
+ }
+
+ return 0;
+
+err_cma_destroy:
+ drm_framebuffer_remove(&hdlcd_fbdev->fb->fb);
+err_fb_info_destroy:
+ drm_fb_helper_fini(helper);
+err_gem_free_object:
+ drm_gem_object_put_unlocked(&obj->base);
+ return ret;
+}
+
+static const struct drm_fb_helper_funcs hdlcd_fb_helper_funcs = {
+ .fb_probe = hdlcd_drm_fbdev_create,
+};
+
+/**
+ * hdlcd_drm_fbdev_init_with_funcs() - Allocate and initializes a hdlcd_drm_fbdev struct
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device
+ * @max_conn_count: Maximum number of connectors
+ * @funcs: fb helper functions, in particular a custom dirty() callback
+ *
+ * Returns a newly allocated hdlcd_drm_fbdev struct or a ERR_PTR.
+ */
+struct hdlcd_drm_fbdev *hdlcd_drm_fbdev_init_with_funcs(struct drm_device *dev,
+ unsigned int preferred_bpp, unsigned int max_conn_count,
+ const struct drm_framebuffer_funcs *funcs)
+{
+ struct hdlcd_drm_fbdev *hdlcd_fbdev;
+ struct drm_fb_helper *helper;
+ int ret;
+
+ hdlcd_fbdev = kzalloc(sizeof(*hdlcd_fbdev), GFP_KERNEL);
+ if (!hdlcd_fbdev) {
+ dev_err(dev->dev, "Failed to allocate drm fbdev.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ hdlcd_fbdev->fb_funcs = funcs;
+
+ helper = &hdlcd_fbdev->fb_helper;
+
+ drm_fb_helper_prepare(dev, helper, &hdlcd_fb_helper_funcs);
+
+ ret = drm_fb_helper_init(dev, helper, max_conn_count);
+ if (ret < 0) {
+ dev_err(dev->dev, "Failed to initialize drm fb helper.\n");
+ goto err_free;
+ }
+
+ ret = drm_fb_helper_single_add_all_connectors(helper);
+ if (ret < 0) {
+ dev_err(dev->dev, "Failed to add connectors.\n");
+ goto err_drm_fb_helper_fini;
+
+ }
+
+ ret = drm_fb_helper_initial_config(helper, preferred_bpp);
+ if (ret < 0) {
+ dev_err(dev->dev, "Failed to set initial hw configuration.\n");
+ goto err_drm_fb_helper_fini;
+ }
+
+ return hdlcd_fbdev;
+
+err_drm_fb_helper_fini:
+ drm_fb_helper_fini(helper);
+err_free:
+ kfree(hdlcd_fbdev);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(hdlcd_drm_fbdev_init_with_funcs);
+
+/**
+ * hdlcd_drm_fbdev_init() - Allocate and initializes a hdlcd_drm_fbdev struct
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device
+ * @max_conn_count: Maximum number of connectors
+ *
+ * Returns a newly allocated hdlcd_drm_fbdev struct or a ERR_PTR.
+ */
+struct hdlcd_drm_fbdev *hdlcd_drm_fbdev_init(struct drm_device *dev,
+ unsigned int preferred_bpp, unsigned int max_conn_count)
+{
+ return hdlcd_drm_fbdev_init_with_funcs(dev, preferred_bpp,
+ max_conn_count,
+ &hdlcd_fb_funcs);
+}
+EXPORT_SYMBOL_GPL(hdlcd_drm_fbdev_init);
+
+/**
+ * hdlcd_drm_fbdev_fini() - Free hdlcd_drm_fbdev struct
+ * @hdlcd_fbdev: The hdlcd_drm_fbdev struct
+ */
+void hdlcd_drm_fbdev_fini(struct hdlcd_drm_fbdev *hdlcd_fbdev)
+{
+ drm_fb_helper_unregister_fbi(&hdlcd_fbdev->fb_helper);
+ if (hdlcd_fbdev->fb_helper.fbdev)
+ hdlcd_drm_fbdev_defio_fini(hdlcd_fbdev->fb_helper.fbdev);
+
+ if (hdlcd_fbdev->fb)
+ drm_framebuffer_remove(&hdlcd_fbdev->fb->fb);
+
+ drm_fb_helper_fini(&hdlcd_fbdev->fb_helper);
+ kfree(hdlcd_fbdev);
+}
+EXPORT_SYMBOL_GPL(hdlcd_drm_fbdev_fini);
+
+/**
+ * hdlcd_drm_fbdev_restore_mode() - Restores initial framebuffer mode
+ * @hdlcd_fbdev: The hdlcd_drm_fbdev struct, may be NULL
+ *
+ * This function is usually called from the &drm_driver.lastclose callback.
+ */
+void hdlcd_drm_fbdev_restore_mode(struct hdlcd_drm_fbdev *hdlcd_fbdev)
+{
+ if (hdlcd_fbdev)
+ drm_fb_helper_restore_fbdev_mode_unlocked(&hdlcd_fbdev->fb_helper);
+}
+EXPORT_SYMBOL_GPL(hdlcd_drm_fbdev_restore_mode);
+
+/**
+ * hdlcd_drm_fbdev_hotplug_event() - Poll for hotpulug events
+ * @hdlcd_fbdev: The hdlcd_drm_fbdev struct, may be NULL
+ *
+ * This function is usually called from the &drm_mode_config.output_poll_changed
+ * callback.
+ */
+void hdlcd_drm_fbdev_hotplug_event(struct hdlcd_drm_fbdev *hdlcd_fbdev)
+{
+ if (hdlcd_fbdev)
+ drm_fb_helper_hotplug_event(&hdlcd_fbdev->fb_helper);
+}
+EXPORT_SYMBOL_GPL(hdlcd_drm_fbdev_hotplug_event);
+
+/**
+ * hdlcd_drm_fbdev_set_suspend - wrapper around drm_fb_helper_set_suspend
+ * @hdlcd_fbdev: The hdlcd_drm_fbdev struct, may be NULL
+ * @state: desired state, zero to resume, non-zero to suspend
+ *
+ * Calls drm_fb_helper_set_suspend, which is a wrapper around
+ * fb_set_suspend implemented by fbdev core.
+ */
+void hdlcd_drm_fbdev_set_suspend(struct hdlcd_drm_fbdev *hdlcd_fbdev, int state)
+{
+ if (hdlcd_fbdev)
+ drm_fb_helper_set_suspend(&hdlcd_fbdev->fb_helper, state);
+}
+EXPORT_SYMBOL(hdlcd_drm_fbdev_set_suspend);
+
+/**
+ * hdlcd_drm_fbdev_set_suspend_unlocked - wrapper around
+ * drm_fb_helper_set_suspend_unlocked
+ * @hdlcd_fbdev: The hdlcd_drm_fbdev struct, may be NULL
+ * @state: desired state, zero to resume, non-zero to suspend
+ *
+ * Calls drm_fb_helper_set_suspend, which is a wrapper around
+ * fb_set_suspend implemented by fbdev core.
+ */
+void hdlcd_drm_fbdev_set_suspend_unlocked(struct hdlcd_drm_fbdev *hdlcd_fbdev,
+ int state)
+{
+ if (hdlcd_fbdev)
+ drm_fb_helper_set_suspend_unlocked(&hdlcd_fbdev->fb_helper,
+ state);
+}
+EXPORT_SYMBOL(hdlcd_drm_fbdev_set_suspend_unlocked);
+
+/******************************************************************************
+ * IOCTL Interface
+ ******************************************************************************/
+
+/*
+ * Used for sharing buffers with Mali userspace
+ */
+struct fb_dmabuf_export {
+ uint32_t fd;
+ uint32_t flags;
+};
+
+#define FBIOGET_DMABUF _IOR('F', 0x21, struct fb_dmabuf_export)
+
+static int hdlcd_get_dmabuf_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct fb_dmabuf_export ebuf;
+ struct drm_fb_helper *helper = info->par;
+ struct hdlcd_drm_private *hdlcd = helper->dev->dev_private;
+ struct drm_gem_cma_object *obj = hdlcd->fbdev->fb->obj[0];
+ struct dma_buf *dma_buf;
+ uint32_t fd;
+
+ if (copy_from_user(&ebuf, argp, sizeof(ebuf)))
+ return -EFAULT;
+
+ /*
+ * We need a reference on the gem object. This will be released by
+ * drm_gem_dmabuf_release when the file descriptor is closed.
+ */
+ drm_gem_object_reference(&obj->base);
+
+ dma_buf = drm_gem_prime_export(helper->dev, &obj->base, ebuf.flags | O_RDWR);
+ if (!dma_buf) {
+ dev_info(info->dev, "Failed to export DMA buffer\n");
+ goto err_export;
+ }
+
+ fd = dma_buf_fd(dma_buf, O_CLOEXEC);
+ if (fd < 0) {
+ dev_info(info->dev, "Failed to get file descriptor for DMA buffer\n");
+ goto err_export_fd;
+ }
+ ebuf.fd = fd;
+
+ if (copy_to_user(argp, &ebuf, sizeof(ebuf)))
+ goto err_export_fd;
+
+ return 0;
+
+err_export_fd:
+ dma_buf_put(dma_buf);
+err_export:
+ drm_gem_object_unreference(&obj->base);
+ return -EFAULT;
+}
+
+static int hdlcd_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case FBIOGET_DMABUF:
+ return hdlcd_get_dmabuf_ioctl(info, cmd, arg);
+ case FBIO_WAITFORVSYNC:
+ return 0; /* Nothing to do as we wait when page flipping anyway */
+ default:
+ printk(KERN_INFO "HDLCD FB does not handle ioctl 0x%x\n", cmd);
+ }
+
+ return -EFAULT;
+}
diff --git a/drivers/gpu/drm/arm/hdlcd_fb_helper.h b/drivers/gpu/drm/arm/hdlcd_fb_helper.h
new file mode 100644
index 000000000000..aee0d9037561
--- /dev/null
+++ b/drivers/gpu/drm/arm/hdlcd_fb_helper.h
@@ -0,0 +1,54 @@
+#ifndef __DRM_FB_CMA_HELPER_H__
+#define __DRM_FB_CMA_HELPER_H__
+
+struct hdlcd_drm_fbdev;
+struct drm_gem_cma_object;
+
+struct drm_fb_helper_surface_size;
+struct drm_framebuffer_funcs;
+struct drm_fb_helper_funcs;
+struct drm_framebuffer;
+struct drm_fb_helper;
+struct drm_device;
+struct drm_file;
+struct drm_mode_fb_cmd2;
+struct drm_plane;
+struct drm_plane_state;
+
+struct hdlcd_drm_fbdev *hdlcd_drm_fbdev_init_with_funcs(struct drm_device *dev,
+ unsigned int preferred_bpp, unsigned int max_conn_count,
+ const struct drm_framebuffer_funcs *funcs);
+struct hdlcd_drm_fbdev *hdlcd_drm_fbdev_init(struct drm_device *dev,
+ unsigned int preferred_bpp, unsigned int max_conn_count);
+void hdlcd_drm_fbdev_fini(struct hdlcd_drm_fbdev *hdlcd_fbdev);
+
+void hdlcd_drm_fbdev_restore_mode(struct hdlcd_drm_fbdev *hdlcd_fbdev);
+void hdlcd_drm_fbdev_hotplug_event(struct hdlcd_drm_fbdev *hdlcd_fbdev);
+void hdlcd_drm_fbdev_set_suspend(struct hdlcd_drm_fbdev *hdlcd_fbdev, int state);
+void hdlcd_drm_fbdev_set_suspend_unlocked(struct hdlcd_drm_fbdev *hdlcd_fbdev,
+ int state);
+
+void hdlcd_fb_destroy(struct drm_framebuffer *fb);
+int hdlcd_fb_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file_priv, unsigned int *handle);
+
+struct drm_framebuffer *hdlcd_fb_create_with_funcs(struct drm_device *dev,
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_framebuffer_funcs *funcs);
+struct drm_framebuffer *hdlcd_fb_create(struct drm_device *dev,
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd);
+
+struct drm_gem_cma_object *hdlcd_fb_get_gem_obj(struct drm_framebuffer *fb,
+ unsigned int plane);
+
+int hdlcd_fb_prepare_fb(struct drm_plane *plane,
+ struct drm_plane_state *state);
+
+#ifdef CONFIG_DEBUG_FS
+struct seq_file;
+
+int hdlcd_fb_debugfs_show(struct seq_file *m, void *arg);
+#endif
+
+#endif
+
diff --git a/drivers/gpu/drm/drm_virtual_encoder.c b/drivers/gpu/drm/drm_virtual_encoder.c
new file mode 100644
index 000000000000..d5e24dfc27ea
--- /dev/null
+++ b/drivers/gpu/drm/drm_virtual_encoder.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2016 ARM Limited
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * Dummy encoder and connector that use the OF to "discover" the attached
+ * display timings. Can be used in situations where the encoder and connector's
+ * functionality are emulated and no setup steps are needed, or to describe
+ * attached panels for which no driver exists but can be used without
+ * additional hardware setup.
+ *
+ * The encoder also uses the component framework so that it can be a quick
+ * replacement for existing drivers when testing in an emulated environment.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+#include <linux/component.h>
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+struct drm_virt_priv {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+ struct display_timings *timings;
+};
+
+#define connector_to_drm_virt_priv(x) \
+ container_of(x, struct drm_virt_priv, connector)
+
+#define encoder_to_drm_virt_priv(x) \
+ container_of(x, struct drm_virt_priv, encoder)
+
+static void drm_virtcon_destroy(struct drm_connector *connector)
+{
+ struct drm_virt_priv *conn = connector_to_drm_virt_priv(connector);
+
+ drm_connector_cleanup(connector);
+ display_timings_release(conn->timings);
+}
+
+static enum drm_connector_status
+drm_virtcon_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static const struct drm_connector_funcs drm_virtcon_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = drm_virtcon_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_virtcon_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int drm_virtcon_get_modes(struct drm_connector *connector)
+{
+ struct drm_virt_priv *conn = connector_to_drm_virt_priv(connector);
+ struct display_timings *timings = conn->timings;
+ int i;
+
+ for (i = 0; i < timings->num_timings; i++) {
+ struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ struct videomode vm;
+
+ if (videomode_from_timings(timings, &vm, i))
+ break;
+
+ drm_display_mode_from_videomode(&vm, mode);
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (timings->native_mode == i)
+ mode->type = DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
+
+ return i;
+}
+
+static int drm_virtcon_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+struct drm_encoder *drm_virtcon_best_encoder(struct drm_connector *connector)
+{
+ struct drm_virt_priv *priv = connector_to_drm_virt_priv(connector);
+
+ return &priv->encoder;
+}
+
+struct drm_encoder *
+drm_virtcon_atomic_best_encoder(struct drm_connector *connector,
+ struct drm_connector_state *connector_state)
+{
+ struct drm_virt_priv *priv = connector_to_drm_virt_priv(connector);
+
+ return &priv->encoder;
+}
+
+static const struct drm_connector_helper_funcs drm_virtcon_helper_funcs = {
+ .get_modes = drm_virtcon_get_modes,
+ .mode_valid = drm_virtcon_mode_valid,
+ .best_encoder = drm_virtcon_best_encoder,
+ .atomic_best_encoder = drm_virtcon_atomic_best_encoder,
+};
+
+static void drm_vencoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs drm_vencoder_funcs = {
+ .destroy = drm_vencoder_destroy,
+};
+
+static void drm_vencoder_dpms(struct drm_encoder *encoder, int mode)
+{
+ /* nothing needed */
+}
+
+static bool drm_vencoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ /* nothing needed */
+ return true;
+}
+
+static void drm_vencoder_prepare(struct drm_encoder *encoder)
+{
+ drm_vencoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void drm_vencoder_commit(struct drm_encoder *encoder)
+{
+ drm_vencoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void drm_vencoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ /* nothing needed */
+}
+
+static const struct drm_encoder_helper_funcs drm_vencoder_helper_funcs = {
+ .dpms = drm_vencoder_dpms,
+ .mode_fixup = drm_vencoder_mode_fixup,
+ .prepare = drm_vencoder_prepare,
+ .commit = drm_vencoder_commit,
+ .mode_set = drm_vencoder_mode_set,
+};
+
+static int drm_vencoder_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_encoder *encoder;
+ struct drm_virt_priv *con;
+ struct drm_connector *connector;
+ struct drm_device *drm = data;
+ u32 crtcs = 0;
+ int ret;
+
+ con = devm_kzalloc(dev, sizeof(*con), GFP_KERNEL);
+ if (!con)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, con);
+ connector = &con->connector;
+ encoder = &con->encoder;
+
+ if (dev->of_node) {
+ struct drm_bridge *bridge;
+ crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ bridge = of_drm_find_bridge(dev->of_node);
+ if (bridge) {
+ ret = drm_bridge_attach(encoder, bridge, NULL);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge\n");
+ return ret;
+ }
+ encoder->bridge = bridge;
+ }
+ con->timings = of_get_display_timings(dev->of_node);
+ if (!con->timings) {
+ dev_err(dev, "failed to get display panel timings\n");
+ return ENXIO;
+ }
+ }
+
+ /* If no CRTCs were found, fall back to the old encoder's behaviour */
+ if (crtcs == 0) {
+ dev_warn(dev, "Falling back to first CRTC\n");
+ crtcs = 1 << 0;
+ }
+
+ encoder->possible_crtcs = crtcs ? crtcs : 1;
+ encoder->possible_clones = 0;
+
+ ret = drm_encoder_init(drm, encoder, &drm_vencoder_funcs,
+ DRM_MODE_ENCODER_VIRTUAL, "virtual-encoder");
+ if (ret)
+ goto encoder_init_err;
+
+ drm_encoder_helper_add(encoder, &drm_vencoder_helper_funcs);
+
+ /* bogus values, pretend we're a 24" screen for DPI calculations */
+ connector->display_info.width_mm = 519;
+ connector->display_info.height_mm = 324;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ connector->polled = 0;
+
+ ret = drm_connector_init(drm, connector, &drm_virtcon_funcs,
+ DRM_MODE_CONNECTOR_VIRTUAL);
+ if (ret)
+ goto connector_init_err;
+
+ drm_connector_helper_add(connector, &drm_virtcon_helper_funcs);
+
+ drm_connector_register(connector);
+
+ ret = drm_mode_connector_attach_encoder(connector, encoder);
+ if (ret)
+ goto attach_err;
+
+ return ret;
+
+attach_err:
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+connector_init_err:
+ drm_encoder_cleanup(encoder);
+encoder_init_err:
+ display_timings_release(con->timings);
+
+ return ret;
+};
+
+static void drm_vencoder_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_virt_priv *con = dev_get_drvdata(dev);
+
+ drm_connector_unregister(&con->connector);
+ drm_connector_cleanup(&con->connector);
+ drm_encoder_cleanup(&con->encoder);
+ display_timings_release(con->timings);
+}
+
+static const struct component_ops drm_vencoder_ops = {
+ .bind = drm_vencoder_bind,
+ .unbind = drm_vencoder_unbind,
+};
+
+static int drm_vencoder_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &drm_vencoder_ops);
+}
+
+static int drm_vencoder_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &drm_vencoder_ops);
+ return 0;
+}
+
+static const struct of_device_id drm_vencoder_of_match[] = {
+ { .compatible = "drm,virtual-encoder", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, drm_vencoder_of_match);
+
+static struct platform_driver drm_vencoder_driver = {
+ .probe = drm_vencoder_probe,
+ .remove = drm_vencoder_remove,
+ .driver = {
+ .name = "drm_vencoder",
+ .of_match_table = drm_vencoder_of_match,
+ },
+};
+
+module_platform_driver(drm_vencoder_driver);
+
+MODULE_AUTHOR("Liviu Dudau");
+MODULE_DESCRIPTION("Virtual DRM Encoder");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index a6c92beb410a..23e0e8784e49 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -11,6 +11,9 @@ config DRM_I2C_CH7006
This driver is currently only useful if you're also using
the nouveau driver.
+config DRM_I2C_DUMMY
+ tristate "Dummy stub driver"
+
config DRM_I2C_SIL164
tristate "Silicon Image sil164 TMDS transmitter"
default m if DRM_NOUVEAU
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 43aa33baebed..658751730d50 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -3,6 +3,8 @@ ccflags-y := -Iinclude/drm
ch7006-y := ch7006_drv.o ch7006_mode.o
obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
+obj-$(CONFIG_DRM_I2C_DUMMY) += dummy_drm_i2c_drv.o
+
sil164-y := sil164_drv.o
obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
diff --git a/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c b/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c
new file mode 100644
index 000000000000..2958f57940e8
--- /dev/null
+++ b/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c
@@ -0,0 +1,264 @@
+/*
+ * This file was originally based on tda998x_drv.c which has the following
+ * copyright and licence...
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <robdclark@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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/component.h>
+#include <linux/module.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+
+struct dummy_priv {
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+};
+
+#define conn_to_dummy_priv(x) \
+ container_of(x, struct dummy_priv, connector);
+
+/* DRM encoder functions */
+
+static void dummy_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool
+dummy_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static int dummy_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static void
+dummy_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static enum drm_connector_status
+dummy_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static const u8 edid_1024x768[] = {
+ /*
+ * These values are a copy of Documentation/EDID/1024x768.c
+ * produced by executing "make -C Documentation/EDID"
+ */
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
+ 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+ 0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
+ 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
+ 0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+ 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+ 0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+ 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
+ 0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55
+};
+
+static int dummy_read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
+{
+ memcpy(buf, edid_1024x768, min(sizeof(edid_1024x768),length));
+ return 0;
+}
+
+static int dummy_connector_get_modes(struct drm_connector *connector)
+{
+ struct edid *edid;
+ int n;
+
+ edid = drm_do_get_edid(connector, dummy_read_edid_block, NULL);
+ if (!edid)
+ return 0;
+
+ drm_mode_connector_update_edid_property(connector, edid);
+ n = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+
+ return n;
+}
+
+/* I2C driver functions */
+
+static void dummy_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void dummy_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static const struct drm_encoder_helper_funcs dummy_encoder_helper_funcs = {
+ .dpms = dummy_encoder_dpms,
+ .mode_fixup = dummy_encoder_mode_fixup,
+ .prepare = dummy_encoder_prepare,
+ .commit = dummy_encoder_commit,
+ .mode_set = dummy_encoder_mode_set,
+};
+
+static void dummy_encoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs dummy_encoder_funcs = {
+ .destroy = dummy_encoder_destroy,
+};
+
+static struct drm_encoder *
+dummy_connector_best_encoder(struct drm_connector *connector)
+{
+ struct dummy_priv *priv = conn_to_dummy_priv(connector);
+
+ return &priv->encoder;
+}
+
+static
+const struct drm_connector_helper_funcs dummy_connector_helper_funcs = {
+ .get_modes = dummy_connector_get_modes,
+ .mode_valid = dummy_connector_mode_valid,
+ .best_encoder = dummy_connector_best_encoder,
+};
+
+static void dummy_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs dummy_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dummy_connector_detect,
+ .destroy = dummy_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int dummy_bind(struct device *dev, struct device *master, void *data)
+{
+ struct drm_device *drm = data;
+ struct dummy_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+
+ priv->connector.interlace_allowed = 1;
+ priv->encoder.possible_crtcs = 1 << 0;
+
+ drm_encoder_helper_add(&priv->encoder, &dummy_encoder_helper_funcs);
+ ret = drm_encoder_init(drm, &priv->encoder, &dummy_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
+ if (ret)
+ goto err_encoder;
+
+ drm_connector_helper_add(&priv->connector,
+ &dummy_connector_helper_funcs);
+ ret = drm_connector_init(drm, &priv->connector,
+ &dummy_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ if (ret)
+ goto err_connector;
+
+ drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+
+ return 0;
+
+err_connector:
+ drm_encoder_cleanup(&priv->encoder);
+err_encoder:
+ return ret;
+}
+
+static void dummy_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct dummy_priv *priv = dev_get_drvdata(dev);
+
+ drm_connector_cleanup(&priv->connector);
+ drm_encoder_cleanup(&priv->encoder);
+}
+
+static const struct component_ops dummy_ops = {
+ .bind = dummy_bind,
+ .unbind = dummy_unbind,
+};
+
+static int
+dummy_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ return component_add(&client->dev, &dummy_ops);
+}
+
+static int dummy_remove(struct i2c_client *client)
+{
+ component_del(&client->dev, &dummy_ops);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dummy_of_ids[] = {
+ { .compatible = "sil,sii9022-tpi", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, dummy_of_ids);
+#endif
+
+static struct i2c_device_id dummy_ids[] = {
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, dummy_ids);
+
+static struct i2c_driver dummy_driver = {
+ .probe = dummy_probe,
+ .remove = dummy_remove,
+ .driver = {
+ .name = "dummy_drm_i2c",
+ .of_match_table = dummy_of_ids
+ },
+ .id_table = dummy_ids,
+};
+
+module_i2c_driver(dummy_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 1145cde2274a..bf397e3c5195 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -101,6 +101,10 @@ static int legacy_pme = 0;
module_param(legacy_pme, int, 0);
MODULE_PARM_DESC(legacy_pme, "Legacy power management");
+/* Ugh! Let the firmware tell us the hardware address */
+static int mac_address[ETH_ALEN] = { 0, };
+module_param_array(mac_address, int, NULL, 0);
+
static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */
@@ -3909,6 +3913,18 @@ static void sky2_get_stats(struct net_device *dev,
unsigned int start;
u64 _bytes, _packets;
+ /* Try and check if device if off. If it is, abort gathering stats as
+ * any attempt to read hardware registers will generate a bus fault.
+ * This test is hacky and racy as there's nothing stopping the device
+ * being powered off immediately after the test.
+ */
+ if (hw->pdev->pm_cap) {
+ u16 pmcsr;
+ int ret = pci_read_config_word(hw->pdev, hw->pdev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ if (ret || (pmcsr & PCI_PM_CTRL_STATE_MASK) > PCI_D2)
+ return; /* Can't read power state or it's state D3 (off) */
+ }
+
do {
start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp);
_bytes = sky2->rx_stats.bytes;
@@ -4819,13 +4835,21 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
/* try to get mac address in the following order:
* 1) from device tree data
* 2) from internal registers set by bootloader
+ * 3) from the command line parameter
*/
iap = of_get_mac_address(hw->pdev->dev.of_node);
if (iap)
memcpy(dev->dev_addr, iap, ETH_ALEN);
- else
+ else {
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8,
ETH_ALEN);
+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ dev->dev_addr[i] = mac_address[i];
+ }
+ }
/* if the address is invalid, use a random value */
if (!is_valid_ether_addr(dev->dev_addr)) {
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index a8176a836e25..57a11bba6e3b 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -895,6 +895,8 @@ int drm_crtc_force_disable_all(struct drm_device *dev);
int drm_mode_set_config_internal(struct drm_mode_set *set);
struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx);
+extern int drm_create_virtual_connector(struct drm_device *dev);
+
/**
* drm_crtc_find - look up a CRTC object from its ID
* @dev: DRM device
diff --git a/linaro/configs/android.conf b/linaro/configs/android.conf
index 637c36580a45..c9309874c1de 100644
--- a/linaro/configs/android.conf
+++ b/linaro/configs/android.conf
@@ -3,6 +3,7 @@
# CONFIG_INET_LRO is not set
# CONFIG_MODULES is not set
# CONFIG_OABI_COMPAT is not set
+# CONFIG_SYSVIPC is not set
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
@@ -19,13 +20,16 @@ CONFIG_CGROUP_SCHED=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_DM_CRYPT=y
CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
CONFIG_EMBEDDED=y
CONFIG_FB=y
+CONFIG_HARDENED_USERCOPY=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_INET6_AH=y
CONFIG_INET6_ESP=y
CONFIG_INET6_IPCOMP=y
CONFIG_INET=y
+CONFIG_INET_DIAG_DESTROY=y
CONFIG_INET_ESP=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_IP6_NF_FILTER=y
@@ -33,7 +37,6 @@ CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MANGLE=y
CONFIG_IP6_NF_RAW=y
CONFIG_IP6_NF_TARGET_REJECT=y
-CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
CONFIG_IPV6=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -42,6 +45,7 @@ CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTICAST=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARPTABLES=y
@@ -52,13 +56,13 @@ CONFIG_IP_NF_MANGLE=y
CONFIG_IP_NF_MATCH_AH=y
CONFIG_IP_NF_MATCH_ECN=y
CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_NAT=y
CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_SECURITY=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_REJECT_SKERR=y
CONFIG_NET=y
CONFIG_NETDEVICES=y
CONFIG_NETFILTER=y
@@ -133,19 +137,26 @@ CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
CONFIG_PPP_MPPE=y
CONFIG_PREEMPT=y
-CONFIG_RESOURCE_COUNTERS=y
+CONFIG_PROFILING=y
+CONFIG_QFMT_V2=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QUOTA_TREE=y
+CONFIG_QUOTACTL=y
+CONFIG_RANDOMIZE_BASE=y
CONFIG_RTC_CLASS=y
CONFIG_RT_GROUP_SCHED=y
+CONFIG_SECCOMP=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SETEND_EMULATION=y
CONFIG_STAGING=y
-CONFIG_SWITCH=y
CONFIG_SWP_EMULATION=y
CONFIG_SYNC=y
-CONFIG_SYSVIPC=y
CONFIG_TUN=y
+CONFIG_UID_CPUTIME=y
CONFIG_UNIX=y
CONFIG_USB_GADGET=y
CONFIG_USB_CONFIGFS=y
@@ -155,8 +166,10 @@ CONFIG_USB_CONFIGFS_F_PTP=y
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_OTG_WAKELOCK=y
CONFIG_XFRM_USER=y
+# CONFIG_AIO is not set
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_LEGACY_PTYS is not set
@@ -164,11 +177,14 @@ CONFIG_XFRM_USER=y
# CONFIG_PM_WAKELOCKS_GC is not set
# CONFIG_VT is not set
CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ARM_KERNMEM_PERMS=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_CC_STACKPROTECTOR_STRONG=y
CONFIG_COMPACTION=y
+CONFIG_DEBUG_RODATA=y
CONFIG_DM_UEVENT=y
CONFIG_DRAGONRISE_FF=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
@@ -266,14 +282,19 @@ CONFIG_TABLET_USB_AIPTEK=y
CONFIG_TABLET_USB_GTCO=y
CONFIG_TABLET_USB_HANWANG=y
CONFIG_TABLET_USB_KBTAB=y
-CONFIG_TABLET_USB_WACOM=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_TASK_XACCT=y
CONFIG_TIMER_STATS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_UHID=y
-CONFIG_UID_STAT=y
+CONFIG_MEMORY_STATE_TIME=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_HIDDEV=y
CONFIG_USB_USBNET=y
CONFIG_VFAT_FS=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
diff --git a/linaro/configs/big-LITTLE-MP.conf b/linaro/configs/big-LITTLE-MP.conf
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/linaro/configs/big-LITTLE-MP.conf
diff --git a/linaro/configs/vexpress.conf b/linaro/configs/vexpress.conf
index 8370cf15be65..74b53428e7b0 100644
--- a/linaro/configs/vexpress.conf
+++ b/linaro/configs/vexpress.conf
@@ -7,16 +7,20 @@ CONFIG_ARM_PSCI=y
CONFIG_MCPM=y
CONFIG_ARCH_VEXPRESS_DCSCB=y
CONFIG_ARCH_VEXPRESS_TC2_PM=y
+CONFIG_ARM_CPUIDLE=y
CONFIG_ARM_BIG_LITTLE_CPUIDLE=y
CONFIG_BIG_LITTLE=y
CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
CONFIG_ARM_VEXPRESS_SPC_CPUFREQ=y
CONFIG_PM_OPP=y
CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
CONFIG_CMDLINE="console=ttyAMA0,38400n8 root=/dev/mmcblk0p2 rootwait mmci.fmax=4000000"
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_SCSI=y
@@ -24,12 +28,22 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SMSC911X=y
CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
CONFIG_SERIO_AMBAKMI=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
-CONFIG_FB_ARMHDLCD=y
+CONFIG_DRM=y
+CONFIG_DRM_ARM=y
+CONFIG_DRM_HDLCD=y
+CONFIG_CMA=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+CONFIG_CMA_SIZE_MBYTES=32
+CONFIG_I2C_VERSATILE=y
+CONFIG_DRM_I2C_DUMMY=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
diff --git a/linaro/configs/vexpress64.conf b/linaro/configs/vexpress64.conf
index f9c7acfcdf47..61523c809334 100644
--- a/linaro/configs/vexpress64.conf
+++ b/linaro/configs/vexpress64.conf
@@ -1,12 +1,14 @@
CONFIG_ARCH_VEXPRESS=y
CONFIG_SMP=y
-CONFIG_NR_CPUS=8
CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT=y
CONFIG_CMDLINE="console=ttyAMA0"
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_COMPAT=y
CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
CONFIG_SERIO_AMBAKMI=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
@@ -46,19 +48,6 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_OHCI_HCD=y
-CONFIG_MAILBOX=y
-CONFIG_ARM_MHU=y
-CONFIG_ARM_SCPI_PROTOCOL=y
-CONFIG_SENSORS_ARM_SCPI=y
-CONFIG_COMMON_CLK_SCPI=y
-CONFIG_ARM_SCPI_CPUFREQ=y
-CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
-CONFIG_ARM_DT_BL_CPUFREQ=y
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_PCI_REALLOC_ENABLE_AUTO=y
@@ -74,6 +63,31 @@ CONFIG_CONNECTOR=y
CONFIG_ATA=y
CONFIG_SATA_SIL24=y
CONFIG_SKY2=y
+CONFIG_ARM_TIMER_SP804=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_DRM=y
+CONFIG_DRM_ARM=y
+CONFIG_DRM_HDLCD=y
+CONFIG_DRM_VIRT_ENCODER=y
+CONFIG_CMA=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+CONFIG_CMA_SIZE_MBYTES=32
+CONFIG_DRM_I2C_NXP_TDA998X=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_SEQ_DUMMY=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_DESIGNWARE_I2S=y
+CONFIG_SND_SOC_SPDIF=y
+CONFIG_SND_SIMPLE_CARD=y
+CONFIG_DMADEVICES=y
+CONFIG_PL330_DMA=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y