diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2014-06-10 20:59:03 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2014-06-10 20:59:22 +0200 |
commit | 0b9f665205c36306f5433de78df3aebf08b53082 (patch) | |
tree | 63351b914665dbfedabf8379e952e80c4d59cf1c /target/arm | |
parent | 8c22e3f5cd0880af766fc88fa79d718caebd1d7c (diff) |
update to 3.15, rb532 pci patch no longer required
Diffstat (limited to 'target/arm')
-rw-r--r-- | target/arm/cubox-i/patches/3.15-rc7/rmk.patch | 12452 | ||||
-rw-r--r-- | target/arm/cubox-i/patches/3.15/rmk.patch | 6640 | ||||
-rw-r--r-- | target/arm/cubox-i/patches/3.15/sdma-firmware-cubox-i.patch (renamed from target/arm/cubox-i/patches/3.15-rc7/sdma-firmware-cubox-i.patch) | 0 |
3 files changed, 6640 insertions, 12452 deletions
diff --git a/target/arm/cubox-i/patches/3.15-rc7/rmk.patch b/target/arm/cubox-i/patches/3.15-rc7/rmk.patch deleted file mode 100644 index 83afb1a78..000000000 --- a/target/arm/cubox-i/patches/3.15-rc7/rmk.patch +++ /dev/null @@ -1,12452 +0,0 @@ -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts linux-3.15-rc6/arch/arm/boot/dts/imx6dl-hummingboard.dts ---- linux-3.15-rc6.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-05-23 11:26:48.244939835 +0200 -@@ -67,6 +67,14 @@ - status = "okay"; - }; - -+&hdmi { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_hummingboard_hdmi>; -+ ddc-i2c-bus = <&i2c2>; -+ status = "okay"; -+ crtcs = <&ipu1 0>; -+}; -+ - &i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hummingboard_i2c1>; -@@ -82,6 +90,13 @@ - */ - }; - -+&i2c2 { -+ clock-frequency = <100000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_hummingboard_i2c2>; -+ status = "okay"; -+}; -+ - &iomuxc { - hummingboard { - pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 { -@@ -97,6 +112,12 @@ - >; - }; - -+ pinctrl_hummingboard_hdmi: hummingboard-hdmi { -+ fsl,pins = < -+ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 -+ >; -+ }; -+ - pinctrl_hummingboard_i2c1: hummingboard-i2c1 { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 -@@ -104,6 +125,13 @@ - >; - }; - -+ pinctrl_hummingboard_i2c2: hummingboard-i2c2 { -+ fsl,pins = < -+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 -+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 -+ >; -+ }; -+ - pinctrl_hummingboard_spdif: hummingboard-spdif { - fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>; - }; -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/imx6q-cubox-i.dts linux-3.15-rc6/arch/arm/boot/dts/imx6q-cubox-i.dts ---- linux-3.15-rc6.orig/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-05-23 11:26:48.244939835 +0200 -@@ -13,4 +13,8 @@ - - &sata { - status = "okay"; -+ fsl,transmit-level-mV = <1104>; -+ fsl,transmit-boost-mdB = <0>; -+ fsl,transmit-atten-16ths = <9>; -+ fsl,no-spread-spectrum; - }; -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-3.15-rc6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi ---- linux-3.15-rc6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-05-23 11:26:48.244939835 +0200 -@@ -12,6 +12,19 @@ - pinctrl-0 = <&pinctrl_cubox_i_ir>; - }; - -+ pwmleds { -+ compatible = "pwm-leds"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_pwm1>; -+ -+ front { -+ active-low; -+ label = "imx6:red:front"; -+ max-brightness = <248>; -+ pwms = <&pwm1 0 50000>; -+ }; -+ }; -+ - regulators { - compatible = "simple-bus"; - -@@ -55,6 +68,21 @@ - }; - }; - -+&hdmi { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_hdmi>; -+ ddc-i2c-bus = <&i2c2>; -+ status = "okay"; -+ crtcs = <&ipu1 0>; -+}; -+ -+&i2c2 { -+ clock-frequency = <100000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_i2c2>; -+ status = "okay"; -+}; -+ - &i2c3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cubox_i_i2c3>; -@@ -69,6 +97,19 @@ - - &iomuxc { - cubox_i { -+ pinctrl_cubox_i_hdmi: cubox-i-hdmi { -+ fsl,pins = < -+ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 -+ >; -+ }; -+ -+ pinctrl_cubox_i_i2c2: cubox-i-i2c2 { -+ fsl,pins = < -+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 -+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 -+ >; -+ }; -+ - pinctrl_cubox_i_i2c3: cubox-i-i2c3 { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 -@@ -82,6 +123,10 @@ - >; - }; - -+ pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led { -+ fsl,pins = <MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0>; -+ }; -+ - pinctrl_cubox_i_spdif: cubox-i-spdif { - fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>; - }; -@@ -111,6 +156,28 @@ - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 - >; - }; -+ -+ pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz { -+ fsl,pins = < -+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 -+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 -+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 -+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 -+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 -+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 -+ >; -+ }; -+ -+ pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz { -+ fsl,pins = < -+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 -+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 -+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 -+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 -+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 -+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 -+ >; -+ }; - }; - }; - -@@ -130,9 +197,19 @@ - status = "okay"; - }; - -+&uart4 { -+ status = "okay"; -+}; -+ -+&usdhc1 { -+ status = "okay"; -+}; -+ - &usdhc2 { -- pinctrl-names = "default"; -+ pinctrl-names = "default", "state_100mhz", "state_200mhz"; - pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; -+ pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>; -+ pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>; - vmmc-supply = <®_3p3v>; - cd-gpios = <&gpio1 4 0>; - status = "okay"; -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/imx6qdl.dtsi linux-3.15-rc6/arch/arm/boot/dts/imx6qdl.dtsi ---- linux-3.15-rc6.orig/arch/arm/boot/dts/imx6qdl.dtsi 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/imx6qdl.dtsi 2014-05-23 11:26:48.244939835 +0200 -@@ -128,6 +128,8 @@ - cache-level = <2>; - arm,tag-latency = <4 2 3>; - arm,data-latency = <4 2 3>; -+ arm,dynamic-clk-gating; -+ arm,standby-mode; - }; - - pcie: pcie@0x01000000 { -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-3.15-rc6/arch/arm/boot/dts/imx6qdl-microsom.dtsi ---- linux-3.15-rc6.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-05-23 11:26:48.244939835 +0200 -@@ -1,9 +1,69 @@ - /* - * Copyright (C) 2013,2014 Russell King - */ -+#include <dt-bindings/gpio/gpio.h> -+/ { -+ regulators { -+ compatible = "simple-bus"; -+ -+ reg_brcm_osc: brcm-osc-reg { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio5 5 0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_microsom_brcm_osc_reg>; -+ regulator-name = "brcm_osc_reg"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-boot-on; -+ }; -+ -+ reg_brcm: brcm-reg { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio3 19 0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_microsom_brcm_reg>; -+ regulator-name = "brcm_reg"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ startup-delay-us = <200000>; -+ }; -+ }; -+}; - - &iomuxc { - microsom { -+ pinctrl_microsom_brcm_osc_reg: microsom-brcm-osc-reg { -+ fsl,pins = < -+ MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 -+ >; -+ }; -+ -+ pinctrl_microsom_brcm_reg: microsom-brcm-reg { -+ fsl,pins = < -+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070 -+ >; -+ }; -+ -+ pinctrl_microsom_brcm_wifi: microsom-brcm-wifi { -+ fsl,pins = < -+ MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 -+ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070 -+ MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 -+ MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070 -+ >; -+ }; -+ -+ pinctrl_microsom_brcm_bt: microsom-brcm-bt { -+ fsl,pins = < -+ MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 -+ MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070 -+ MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 -+ >; -+ }; -+ - pinctrl_microsom_uart1: microsom-uart1 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 -@@ -11,6 +71,15 @@ - >; - }; - -+ pinctrl_microsom_uart4_1: microsom-uart4 { -+ fsl,pins = < -+ MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 -+ MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 -+ MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 -+ MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 -+ >; -+ }; -+ - pinctrl_microsom_usbotg: microsom-usbotg { - /* - * Similar to pinctrl_usbotg_2, but we want it -@@ -18,6 +87,17 @@ - */ - fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>; - }; -+ -+ pinctrl_microsom_usdhc1: microsom-usdhc1 { -+ fsl,pins = < -+ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 -+ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 -+ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 -+ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 -+ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 -+ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 -+ >; -+ }; - }; - }; - -@@ -27,7 +107,25 @@ - status = "okay"; - }; - -+/* UART4 - Connected to optional BRCM Wifi/BT/FM */ -+&uart4 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4_1>; -+ fsl,uart-has-rtscts; -+}; -+ - &usbotg { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_microsom_usbotg>; - }; -+ -+/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */ -+&usdhc1 { -+ card-external-vcc-supply = <®_brcm>; -+ card-reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>; -+ keep-power-in-suspend; -+ non-removable; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>; -+ vmmc-supply = <®_brcm>; -+}; -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/imx6sl.dtsi linux-3.15-rc6/arch/arm/boot/dts/imx6sl.dtsi ---- linux-3.15-rc6.orig/arch/arm/boot/dts/imx6sl.dtsi 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/imx6sl.dtsi 2014-05-23 11:26:48.244939835 +0200 -@@ -111,6 +111,8 @@ - cache-level = <2>; - arm,tag-latency = <4 2 3>; - arm,data-latency = <4 2 3>; -+ arm,dynamic-clk-gating; -+ arm,standby-mode; - }; - - pmu { -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/marco.dtsi linux-3.15-rc6/arch/arm/boot/dts/marco.dtsi ---- linux-3.15-rc6.orig/arch/arm/boot/dts/marco.dtsi 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/marco.dtsi 2014-05-23 11:26:48.244939835 +0200 -@@ -36,7 +36,7 @@ - ranges = <0x40000000 0x40000000 0xa0000000>; - - l2-cache-controller@c0030000 { -- compatible = "sirf,marco-pl310-cache", "arm,pl310-cache"; -+ compatible = "arm,pl310-cache"; - reg = <0xc0030000 0x1000>; - interrupts = <0 59 0>; - arm,tag-latency = <1 1 1>; -diff -Nur linux-3.15-rc6.orig/arch/arm/boot/dts/prima2.dtsi linux-3.15-rc6/arch/arm/boot/dts/prima2.dtsi ---- linux-3.15-rc6.orig/arch/arm/boot/dts/prima2.dtsi 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/boot/dts/prima2.dtsi 2014-05-23 11:26:48.244939835 +0200 -@@ -48,7 +48,7 @@ - ranges = <0x40000000 0x40000000 0x80000000>; - - l2-cache-controller@80040000 { -- compatible = "arm,pl310-cache", "sirf,prima2-pl310-cache"; -+ compatible = "arm,pl310-cache"; - reg = <0x80040000 0x1000>; - interrupts = <59>; - arm,tag-latency = <1 1 1>; -diff -Nur linux-3.15-rc6.orig/arch/arm/configs/imx_v6_v7_defconfig linux-3.15-rc6/arch/arm/configs/imx_v6_v7_defconfig ---- linux-3.15-rc6.orig/arch/arm/configs/imx_v6_v7_defconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/configs/imx_v6_v7_defconfig 2014-05-23 11:26:48.248939848 +0200 -@@ -245,6 +245,7 @@ - CONFIG_DRM_IMX_LDB=y - CONFIG_DRM_IMX_IPUV3_CORE=y - CONFIG_DRM_IMX_IPUV3=y -+CONFIG_DRM_IMX_HDMI=y - CONFIG_COMMON_CLK_DEBUG=y - # CONFIG_IOMMU_SUPPORT is not set - CONFIG_PWM=y -diff -Nur linux-3.15-rc6.orig/arch/arm/include/asm/hardware/cache-l2x0.h linux-3.15-rc6/arch/arm/include/asm/hardware/cache-l2x0.h ---- linux-3.15-rc6.orig/arch/arm/include/asm/hardware/cache-l2x0.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/include/asm/hardware/cache-l2x0.h 2014-05-23 11:26:48.248939848 +0200 -@@ -26,8 +26,8 @@ - #define L2X0_CACHE_TYPE 0x004 - #define L2X0_CTRL 0x100 - #define L2X0_AUX_CTRL 0x104 --#define L2X0_TAG_LATENCY_CTRL 0x108 --#define L2X0_DATA_LATENCY_CTRL 0x10C -+#define L310_TAG_LATENCY_CTRL 0x108 -+#define L310_DATA_LATENCY_CTRL 0x10C - #define L2X0_EVENT_CNT_CTRL 0x200 - #define L2X0_EVENT_CNT1_CFG 0x204 - #define L2X0_EVENT_CNT0_CFG 0x208 -@@ -54,53 +54,93 @@ - #define L2X0_LOCKDOWN_WAY_D_BASE 0x900 - #define L2X0_LOCKDOWN_WAY_I_BASE 0x904 - #define L2X0_LOCKDOWN_STRIDE 0x08 --#define L2X0_ADDR_FILTER_START 0xC00 --#define L2X0_ADDR_FILTER_END 0xC04 -+#define L310_ADDR_FILTER_START 0xC00 -+#define L310_ADDR_FILTER_END 0xC04 - #define L2X0_TEST_OPERATION 0xF00 - #define L2X0_LINE_DATA 0xF10 - #define L2X0_LINE_TAG 0xF30 - #define L2X0_DEBUG_CTRL 0xF40 --#define L2X0_PREFETCH_CTRL 0xF60 --#define L2X0_POWER_CTRL 0xF80 --#define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) --#define L2X0_STNDBY_MODE_EN (1 << 0) -+#define L310_PREFETCH_CTRL 0xF60 -+#define L310_POWER_CTRL 0xF80 -+#define L310_DYNAMIC_CLK_GATING_EN (1 << 1) -+#define L310_STNDBY_MODE_EN (1 << 0) - - /* Registers shifts and masks */ - #define L2X0_CACHE_ID_PART_MASK (0xf << 6) - #define L2X0_CACHE_ID_PART_L210 (1 << 6) -+#define L2X0_CACHE_ID_PART_L220 (2 << 6) - #define L2X0_CACHE_ID_PART_L310 (3 << 6) - #define L2X0_CACHE_ID_RTL_MASK 0x3f --#define L2X0_CACHE_ID_RTL_R0P0 0x0 --#define L2X0_CACHE_ID_RTL_R1P0 0x2 --#define L2X0_CACHE_ID_RTL_R2P0 0x4 --#define L2X0_CACHE_ID_RTL_R3P0 0x5 --#define L2X0_CACHE_ID_RTL_R3P1 0x6 --#define L2X0_CACHE_ID_RTL_R3P2 0x8 -- --#define L2X0_AUX_CTRL_MASK 0xc0000fff -+#define L210_CACHE_ID_RTL_R0P2_02 0x00 -+#define L210_CACHE_ID_RTL_R0P1 0x01 -+#define L210_CACHE_ID_RTL_R0P2_01 0x02 -+#define L210_CACHE_ID_RTL_R0P3 0x03 -+#define L210_CACHE_ID_RTL_R0P4 0x0b -+#define L210_CACHE_ID_RTL_R0P5 0x0f -+#define L220_CACHE_ID_RTL_R1P7_01REL0 0x06 -+#define L310_CACHE_ID_RTL_R0P0 0x00 -+#define L310_CACHE_ID_RTL_R1P0 0x02 -+#define L310_CACHE_ID_RTL_R2P0 0x04 -+#define L310_CACHE_ID_RTL_R3P0 0x05 -+#define L310_CACHE_ID_RTL_R3P1 0x06 -+#define L310_CACHE_ID_RTL_R3P1_50REL0 0x07 -+#define L310_CACHE_ID_RTL_R3P2 0x08 -+#define L310_CACHE_ID_RTL_R3P3 0x09 -+ -+/* L2C auxiliary control register - bits common to L2C-210/220/310 */ -+#define L2C_AUX_CTRL_WAY_SIZE_SHIFT 17 -+#define L2C_AUX_CTRL_WAY_SIZE_MASK (7 << 17) -+#define L2C_AUX_CTRL_WAY_SIZE(n) ((n) << 17) -+#define L2C_AUX_CTRL_EVTMON_ENABLE BIT(20) -+#define L2C_AUX_CTRL_PARITY_ENABLE BIT(21) -+#define L2C_AUX_CTRL_SHARED_OVERRIDE BIT(22) -+/* L2C-210/220 common bits */ - #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0 --#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7 -+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK (7 << 0) - #define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3 --#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3) -+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (7 << 3) - #define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6 --#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6) -+#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (7 << 6) - #define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9 --#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9) --#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16 --#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17 --#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17) --#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22 --#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26 --#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27 --#define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT 28 --#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29 --#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30 -- --#define L2X0_LATENCY_CTRL_SETUP_SHIFT 0 --#define L2X0_LATENCY_CTRL_RD_SHIFT 4 --#define L2X0_LATENCY_CTRL_WR_SHIFT 8 -- --#define L2X0_ADDR_FILTER_EN 1 -+#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (7 << 9) -+#define L2X0_AUX_CTRL_ASSOC_SHIFT 13 -+#define L2X0_AUX_CTRL_ASSOC_MASK (15 << 13) -+/* L2C-210 specific bits */ -+#define L210_AUX_CTRL_WRAP_DISABLE BIT(12) -+#define L210_AUX_CTRL_WA_OVERRIDE BIT(23) -+#define L210_AUX_CTRL_EXCLUSIVE_ABORT BIT(24) -+/* L2C-220 specific bits */ -+#define L220_AUX_CTRL_EXCLUSIVE_CACHE BIT(12) -+#define L220_AUX_CTRL_FWA_SHIFT 23 -+#define L220_AUX_CTRL_FWA_MASK (3 << 23) -+#define L220_AUX_CTRL_NS_LOCKDOWN BIT(26) -+#define L220_AUX_CTRL_NS_INT_CTRL BIT(27) -+/* L2C-310 specific bits */ -+#define L310_AUX_CTRL_FULL_LINE_ZERO BIT(0) /* R2P0+ */ -+#define L310_AUX_CTRL_HIGHPRIO_SO_DEV BIT(10) /* R2P0+ */ -+#define L310_AUX_CTRL_STORE_LIMITATION BIT(11) /* R2P0+ */ -+#define L310_AUX_CTRL_EXCLUSIVE_CACHE BIT(12) -+#define L310_AUX_CTRL_ASSOCIATIVITY_16 BIT(16) -+#define L310_AUX_CTRL_CACHE_REPLACE_RR BIT(25) /* R2P0+ */ -+#define L310_AUX_CTRL_NS_LOCKDOWN BIT(26) -+#define L310_AUX_CTRL_NS_INT_CTRL BIT(27) -+#define L310_AUX_CTRL_DATA_PREFETCH BIT(28) -+#define L310_AUX_CTRL_INSTR_PREFETCH BIT(29) -+#define L310_AUX_CTRL_EARLY_BRESP BIT(30) /* R2P0+ */ -+ -+#define L310_LATENCY_CTRL_SETUP(n) ((n) << 0) -+#define L310_LATENCY_CTRL_RD(n) ((n) << 4) -+#define L310_LATENCY_CTRL_WR(n) ((n) << 8) -+ -+#define L310_ADDR_FILTER_EN 1 -+ -+#define L310_PREFETCH_CTRL_OFFSET_MASK 0x1f -+#define L310_PREFETCH_CTRL_DBL_LINEFILL_INCR BIT(23) -+#define L310_PREFETCH_CTRL_PREFETCH_DROP BIT(24) -+#define L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP BIT(27) -+#define L310_PREFETCH_CTRL_DATA_PREFETCH BIT(28) -+#define L310_PREFETCH_CTRL_INSTR_PREFETCH BIT(29) -+#define L310_PREFETCH_CTRL_DBL_LINEFILL BIT(30) - - #define L2X0_CTRL_EN 1 - -diff -Nur linux-3.15-rc6.orig/arch/arm/include/asm/outercache.h linux-3.15-rc6/arch/arm/include/asm/outercache.h ---- linux-3.15-rc6.orig/arch/arm/include/asm/outercache.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/include/asm/outercache.h 2014-05-23 11:26:48.248939848 +0200 -@@ -21,6 +21,7 @@ - #ifndef __ASM_OUTERCACHE_H - #define __ASM_OUTERCACHE_H - -+#include <linux/bug.h> - #include <linux/types.h> - - struct outer_cache_fns { -@@ -28,53 +29,84 @@ - void (*clean_range)(unsigned long, unsigned long); - void (*flush_range)(unsigned long, unsigned long); - void (*flush_all)(void); -- void (*inv_all)(void); - void (*disable)(void); - #ifdef CONFIG_OUTER_CACHE_SYNC - void (*sync)(void); - #endif -- void (*set_debug)(unsigned long); - void (*resume)(void); -+ -+ /* This is an ARM L2C thing */ -+ void (*write_sec)(unsigned long, unsigned); - }; - - extern struct outer_cache_fns outer_cache; - - #ifdef CONFIG_OUTER_CACHE -- -+/** -+ * outer_inv_range - invalidate range of outer cache lines -+ * @start: starting physical address, inclusive -+ * @end: end physical address, exclusive -+ */ - static inline void outer_inv_range(phys_addr_t start, phys_addr_t end) - { - if (outer_cache.inv_range) - outer_cache.inv_range(start, end); - } -+ -+/** -+ * outer_clean_range - clean dirty outer cache lines -+ * @start: starting physical address, inclusive -+ * @end: end physical address, exclusive -+ */ - static inline void outer_clean_range(phys_addr_t start, phys_addr_t end) - { - if (outer_cache.clean_range) - outer_cache.clean_range(start, end); - } -+ -+/** -+ * outer_flush_range - clean and invalidate outer cache lines -+ * @start: starting physical address, inclusive -+ * @end: end physical address, exclusive -+ */ - static inline void outer_flush_range(phys_addr_t start, phys_addr_t end) - { - if (outer_cache.flush_range) - outer_cache.flush_range(start, end); - } - -+/** -+ * outer_flush_all - clean and invalidate all cache lines in the outer cache -+ * -+ * Note: depending on implementation, this may not be atomic - it must -+ * only be called with interrupts disabled and no other active outer -+ * cache masters. -+ * -+ * It is intended that this function is only used by implementations -+ * needing to override the outer_cache.disable() method due to security. -+ * (Some implementations perform this as a clean followed by an invalidate.) -+ */ - static inline void outer_flush_all(void) - { - if (outer_cache.flush_all) - outer_cache.flush_all(); - } - --static inline void outer_inv_all(void) --{ -- if (outer_cache.inv_all) -- outer_cache.inv_all(); --} -- --static inline void outer_disable(void) --{ -- if (outer_cache.disable) -- outer_cache.disable(); --} -- -+/** -+ * outer_disable - clean, invalidate and disable the outer cache -+ * -+ * Disable the outer cache, ensuring that any data contained in the outer -+ * cache is pushed out to lower levels of system memory. The note and -+ * conditions above concerning outer_flush_all() applies here. -+ */ -+extern void outer_disable(void); -+ -+/** -+ * outer_resume - restore the cache configuration and re-enable outer cache -+ * -+ * Restore any configuration that the cache had when previously enabled, -+ * and re-enable the outer cache. -+ */ - static inline void outer_resume(void) - { - if (outer_cache.resume) -@@ -90,13 +122,18 @@ - static inline void outer_flush_range(phys_addr_t start, phys_addr_t end) - { } - static inline void outer_flush_all(void) { } --static inline void outer_inv_all(void) { } - static inline void outer_disable(void) { } - static inline void outer_resume(void) { } - - #endif - - #ifdef CONFIG_OUTER_CACHE_SYNC -+/** -+ * outer_sync - perform a sync point for outer cache -+ * -+ * Ensure that all outer cache operations are complete and any store -+ * buffers are drained. -+ */ - static inline void outer_sync(void) - { - if (outer_cache.sync) -diff -Nur linux-3.15-rc6.orig/arch/arm/Kconfig linux-3.15-rc6/arch/arm/Kconfig ---- linux-3.15-rc6.orig/arch/arm/Kconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/Kconfig 2014-05-23 11:26:48.248939848 +0200 -@@ -1230,19 +1230,6 @@ - register of the Cortex-A9 which reduces the linefill issuing - capabilities of the processor. - --config PL310_ERRATA_588369 -- bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines" -- depends on CACHE_L2X0 -- help -- The PL310 L2 cache controller implements three types of Clean & -- Invalidate maintenance operations: by Physical Address -- (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC). -- They are architecturally defined to behave as the execution of a -- clean operation followed immediately by an invalidate operation, -- both performing to the same memory location. This functionality -- is not correctly implemented in PL310 as clean lines are not -- invalidated as a result of these operations. -- - config ARM_ERRATA_643719 - bool "ARM errata: LoUIS bit field in CLIDR register is incorrect" - depends on CPU_V7 && SMP -@@ -1265,17 +1252,6 @@ - tables. The workaround changes the TLB flushing routines to invalidate - entries regardless of the ASID. - --config PL310_ERRATA_727915 -- bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption" -- depends on CACHE_L2X0 -- help -- PL310 implements the Clean & Invalidate by Way L2 cache maintenance -- operation (offset 0x7FC). This operation runs in background so that -- PL310 can handle normal accesses while it is in progress. Under very -- rare circumstances, due to this erratum, write data can be lost when -- PL310 treats a cacheable write transaction during a Clean & -- Invalidate by Way operation. -- - config ARM_ERRATA_743622 - bool "ARM errata: Faulty hazard checking in the Store Buffer may lead to data corruption" - depends on CPU_V7 -@@ -1301,21 +1277,6 @@ - operation is received by a CPU before the ICIALLUIS has completed, - potentially leading to corrupted entries in the cache or TLB. - --config PL310_ERRATA_753970 -- bool "PL310 errata: cache sync operation may be faulty" -- depends on CACHE_PL310 -- help -- This option enables the workaround for the 753970 PL310 (r3p0) erratum. -- -- Under some condition the effect of cache sync operation on -- the store buffer still remains when the operation completes. -- This means that the store buffer is always asked to drain and -- this prevents it from merging any further writes. The workaround -- is to replace the normal offset of cache sync operation (0x730) -- by another offset targeting an unmapped PL310 register 0x740. -- This has the same effect as the cache sync operation: store buffer -- drain and waiting for all buffers empty. -- - config ARM_ERRATA_754322 - bool "ARM errata: possible faulty MMU translations following an ASID switch" - depends on CPU_V7 -@@ -1364,18 +1325,6 @@ - relevant cache maintenance functions and sets a specific bit - in the diagnostic control register of the SCU. - --config PL310_ERRATA_769419 -- bool "PL310 errata: no automatic Store Buffer drain" -- depends on CACHE_L2X0 -- help -- On revisions of the PL310 prior to r3p2, the Store Buffer does -- not automatically drain. This can cause normal, non-cacheable -- writes to be retained when the memory system is idle, leading -- to suboptimal I/O performance for drivers using coherent DMA. -- This option adds a write barrier to the cpu_idle loop so that, -- on systems with an outer cache, the store buffer is drained -- explicitly. -- - config ARM_ERRATA_775420 - bool "ARM errata: A data cache maintenance operation which aborts, might lead to deadlock" - depends on CPU_V7 -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-berlin/berlin.c linux-3.15-rc6/arch/arm/mach-berlin/berlin.c ---- linux-3.15-rc6.orig/arch/arm/mach-berlin/berlin.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-berlin/berlin.c 2014-05-23 11:26:48.256939874 +0200 -@@ -24,7 +24,7 @@ - * with DT probing for L2CCs, berlin_init_machine can be removed. - * Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc - */ -- l2x0_of_init(0x70c00000, 0xfeffffff); -+ l2x0_of_init(0x30c00000, 0xfeffffff); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-cns3xxx/core.c linux-3.15-rc6/arch/arm/mach-cns3xxx/core.c ---- linux-3.15-rc6.orig/arch/arm/mach-cns3xxx/core.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-cns3xxx/core.c 2014-05-23 11:26:48.256939874 +0200 -@@ -272,9 +272,9 @@ - * - * 1 cycle of latency for setup, read and write accesses - */ -- val = readl(base + L2X0_TAG_LATENCY_CTRL); -+ val = readl(base + L310_TAG_LATENCY_CTRL); - val &= 0xfffff888; -- writel(val, base + L2X0_TAG_LATENCY_CTRL); -+ writel(val, base + L310_TAG_LATENCY_CTRL); - - /* - * Data RAM Control register -@@ -285,12 +285,12 @@ - * - * 1 cycle of latency for setup, read and write accesses - */ -- val = readl(base + L2X0_DATA_LATENCY_CTRL); -+ val = readl(base + L310_DATA_LATENCY_CTRL); - val &= 0xfffff888; -- writel(val, base + L2X0_DATA_LATENCY_CTRL); -+ writel(val, base + L310_DATA_LATENCY_CTRL); - - /* 32 KiB, 8-way, parity disable */ -- l2x0_init(base, 0x00540000, 0xfe000fff); -+ l2x0_init(base, 0x00500000, 0xfe0f0fff); - } - - #endif /* CONFIG_CACHE_L2X0 */ -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-exynos/common.h linux-3.15-rc6/arch/arm/mach-exynos/common.h ---- linux-3.15-rc6.orig/arch/arm/mach-exynos/common.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-exynos/common.h 2014-05-23 11:26:48.256939874 +0200 -@@ -55,7 +55,6 @@ - NUM_SYS_POWERDOWN, - }; - --extern unsigned long l2x0_regs_phys; - struct exynos_pmu_conf { - void __iomem *reg; - unsigned int val[NUM_SYS_POWERDOWN]; -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-exynos/exynos.c linux-3.15-rc6/arch/arm/mach-exynos/exynos.c ---- linux-3.15-rc6.orig/arch/arm/mach-exynos/exynos.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-exynos/exynos.c 2014-05-23 11:26:48.256939874 +0200 -@@ -32,9 +32,6 @@ - #include "mfc.h" - #include "regs-pmu.h" - --#define L2_AUX_VAL 0x7C470001 --#define L2_AUX_MASK 0xC200ffff -- - static struct map_desc exynos4_iodesc[] __initdata = { - { - .virtual = (unsigned long)S3C_VA_SYS, -@@ -321,17 +318,7 @@ - - static int __init exynos4_l2x0_cache_init(void) - { -- int ret; -- -- ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK); -- if (ret) -- return ret; -- -- if (IS_ENABLED(CONFIG_S5P_SLEEP)) { -- l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); -- clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); -- } -- return 0; -+ return l2x0_of_init(0x3c400001, 0xc20fffff); - } - early_initcall(exynos4_l2x0_cache_init); - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-exynos/sleep.S linux-3.15-rc6/arch/arm/mach-exynos/sleep.S ---- linux-3.15-rc6.orig/arch/arm/mach-exynos/sleep.S 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-exynos/sleep.S 2014-05-23 11:26:48.256939874 +0200 -@@ -16,8 +16,6 @@ - */ - - #include <linux/linkage.h> --#include <asm/asm-offsets.h> --#include <asm/hardware/cache-l2x0.h> - - #define CPU_MASK 0xff0ffff0 - #define CPU_CORTEX_A9 0x410fc090 -@@ -53,33 +51,7 @@ - and r0, r0, r1 - ldr r1, =CPU_CORTEX_A9 - cmp r0, r1 -- bne skip_l2_resume -- adr r0, l2x0_regs_phys -- ldr r0, [r0] -- cmp r0, #0 -- beq skip_l2_resume -- ldr r1, [r0, #L2X0_R_PHY_BASE] -- ldr r2, [r1, #L2X0_CTRL] -- tst r2, #0x1 -- bne skip_l2_resume -- ldr r2, [r0, #L2X0_R_AUX_CTRL] -- str r2, [r1, #L2X0_AUX_CTRL] -- ldr r2, [r0, #L2X0_R_TAG_LATENCY] -- str r2, [r1, #L2X0_TAG_LATENCY_CTRL] -- ldr r2, [r0, #L2X0_R_DATA_LATENCY] -- str r2, [r1, #L2X0_DATA_LATENCY_CTRL] -- ldr r2, [r0, #L2X0_R_PREFETCH_CTRL] -- str r2, [r1, #L2X0_PREFETCH_CTRL] -- ldr r2, [r0, #L2X0_R_PWR_CTRL] -- str r2, [r1, #L2X0_POWER_CTRL] -- mov r2, #1 -- str r2, [r1, #L2X0_CTRL] --skip_l2_resume: -+ bleq l2c310_early_resume - #endif - b cpu_resume - ENDPROC(exynos_cpu_resume) --#ifdef CONFIG_CACHE_L2X0 -- .globl l2x0_regs_phys --l2x0_regs_phys: -- .long 0 --#endif -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-highbank/highbank.c linux-3.15-rc6/arch/arm/mach-highbank/highbank.c ---- linux-3.15-rc6.orig/arch/arm/mach-highbank/highbank.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-highbank/highbank.c 2014-05-23 11:26:48.256939874 +0200 -@@ -51,11 +51,13 @@ - } - - --static void highbank_l2x0_disable(void) -+static void highbank_l2c310_write_sec(unsigned long val, unsigned reg) - { -- outer_flush_all(); -- /* Disable PL310 L2 Cache controller */ -- highbank_smc1(0x102, 0x0); -+ if (reg == L2X0_CTRL) -+ highbank_smc1(0x102, val); -+ else -+ WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n", -+ reg); - } - - static void __init highbank_init_irq(void) -@@ -66,11 +68,9 @@ - highbank_scu_map_io(); - - /* Enable PL310 L2 Cache controller */ -- if (IS_ENABLED(CONFIG_CACHE_L2X0) && -- of_find_compatible_node(NULL, NULL, "arm,pl310-cache")) { -- highbank_smc1(0x102, 0x1); -- l2x0_of_init(0, ~0UL); -- outer_cache.disable = highbank_l2x0_disable; -+ if (IS_ENABLED(CONFIG_CACHE_L2X0)) { -+ outer_cache.write_sec = highbank_l2c310_write_sec; -+ l2x0_of_init(0, ~0); - } - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-imx/clk-pllv3.c linux-3.15-rc6/arch/arm/mach-imx/clk-pllv3.c ---- linux-3.15-rc6.orig/arch/arm/mach-imx/clk-pllv3.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-imx/clk-pllv3.c 2014-05-23 11:26:48.256939874 +0200 -@@ -273,9 +273,10 @@ - struct clk_pllv3 *pll = to_clk_pllv3(hw); - unsigned long min_rate = parent_rate * 27; - unsigned long max_rate = parent_rate * 54; -- u32 val, div; -+ u32 val, newval, div; - u32 mfn, mfd = 1000000; - s64 temp64; -+ int ret; - - if (rate < min_rate || rate > max_rate) - return -EINVAL; -@@ -287,13 +288,27 @@ - mfn = temp64; - - val = readl_relaxed(pll->base); -- val &= ~pll->div_mask; -- val |= div; -- writel_relaxed(val, pll->base); -+ -+ /* set the PLL into bypass mode */ -+ newval = val | BM_PLL_BYPASS; -+ writel_relaxed(newval, pll->base); -+ -+ /* configure the new frequency */ -+ newval &= ~pll->div_mask; -+ newval |= div; -+ writel_relaxed(newval, pll->base); - writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); -- writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); -+ writel(mfd, pll->base + PLL_DENOM_OFFSET); -+ -+ ret = clk_pllv3_wait_lock(pll); -+ if (ret == 0 && val & BM_PLL_POWER) { -+ /* only if it locked can we switch back to the PLL */ -+ newval &= ~BM_PLL_BYPASS; -+ newval |= val & BM_PLL_BYPASS; -+ writel(newval, pll->base); -+ } - -- return clk_pllv3_wait_lock(pll); -+ return ret; - } - - static const struct clk_ops clk_pllv3_av_ops = { -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-imx/mach-vf610.c linux-3.15-rc6/arch/arm/mach-imx/mach-vf610.c ---- linux-3.15-rc6.orig/arch/arm/mach-imx/mach-vf610.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-imx/mach-vf610.c 2014-05-23 11:26:48.256939874 +0200 -@@ -22,7 +22,7 @@ - - static void __init vf610_init_irq(void) - { -- l2x0_of_init(0, ~0UL); -+ l2x0_of_init(0, ~0); - irqchip_init(); - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-imx/suspend-imx6.S linux-3.15-rc6/arch/arm/mach-imx/suspend-imx6.S ---- linux-3.15-rc6.orig/arch/arm/mach-imx/suspend-imx6.S 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-imx/suspend-imx6.S 2014-05-23 11:26:48.256939874 +0200 -@@ -334,28 +334,10 @@ - * turned into relative ones. - */ - --#ifdef CONFIG_CACHE_L2X0 -- .macro pl310_resume -- adr r0, l2x0_saved_regs_offset -- ldr r2, [r0] -- add r2, r2, r0 -- ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 -- ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value -- str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl -- mov r1, #0x1 -- str r1, [r0, #L2X0_CTRL] @ re-enable L2 -- .endm -- --l2x0_saved_regs_offset: -- .word l2x0_saved_regs - . -- --#else -- .macro pl310_resume -- .endm --#endif -- - ENTRY(v7_cpu_resume) - bl v7_invalidate_l1 -- pl310_resume -+#ifdef CONFIG_CACHE_L2X0 -+ bl l2c310_early_resume -+#endif - b cpu_resume - ENDPROC(v7_cpu_resume) -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-imx/system.c linux-3.15-rc6/arch/arm/mach-imx/system.c ---- linux-3.15-rc6.orig/arch/arm/mach-imx/system.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-imx/system.c 2014-05-23 11:26:48.260939887 +0200 -@@ -124,7 +124,7 @@ - } - - /* Configure the L2 PREFETCH and POWER registers */ -- val = readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL); -+ val = readl_relaxed(l2x0_base + L310_PREFETCH_CTRL); - val |= 0x70800000; - /* - * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0 -@@ -137,14 +137,12 @@ - */ - if (cpu_is_imx6q()) - val &= ~(1 << 30 | 1 << 23); -- writel_relaxed(val, l2x0_base + L2X0_PREFETCH_CTRL); -- val = L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; -- writel_relaxed(val, l2x0_base + L2X0_POWER_CTRL); -+ writel_relaxed(val, l2x0_base + L310_PREFETCH_CTRL); - - iounmap(l2x0_base); - of_node_put(np); - - out: -- l2x0_of_init(0, ~0UL); -+ l2x0_of_init(0, ~0); - } - #endif -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-mvebu/board-v7.c linux-3.15-rc6/arch/arm/mach-mvebu/board-v7.c ---- linux-3.15-rc6.orig/arch/arm/mach-mvebu/board-v7.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-mvebu/board-v7.c 2014-05-23 11:26:48.260939887 +0200 -@@ -60,7 +60,7 @@ - coherency_init(); - BUG_ON(mvebu_mbus_dt_init()); - #ifdef CONFIG_CACHE_L2X0 -- l2x0_of_init(0, ~0UL); -+ l2x0_of_init(0, ~0); - #endif - - if (of_machine_is_compatible("marvell,armada375")) -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-nomadik/cpu-8815.c linux-3.15-rc6/arch/arm/mach-nomadik/cpu-8815.c ---- linux-3.15-rc6.orig/arch/arm/mach-nomadik/cpu-8815.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-nomadik/cpu-8815.c 2014-05-23 11:26:48.260939887 +0200 -@@ -147,7 +147,7 @@ - { - #ifdef CONFIG_CACHE_L2X0 - /* At full speed latency must be >=2, so 0x249 in low bits */ -- l2x0_of_init(0x00730249, 0xfe000fff); -+ l2x0_of_init(0x00700249, 0xfe0fefff); - #endif - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - } -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-omap2/common.h linux-3.15-rc6/arch/arm/mach-omap2/common.h ---- linux-3.15-rc6.orig/arch/arm/mach-omap2/common.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-omap2/common.h 2014-05-23 11:26:48.260939887 +0200 -@@ -91,6 +91,7 @@ - extern void omap3_secure_sync32k_timer_init(void); - extern void omap3_gptimer_timer_init(void); - extern void omap4_local_timer_init(void); -+int omap_l2_cache_init(void); - extern void omap5_realtime_timer_init(void); - - void omap2420_init_early(void); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-omap2/io.c linux-3.15-rc6/arch/arm/mach-omap2/io.c ---- linux-3.15-rc6.orig/arch/arm/mach-omap2/io.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-omap2/io.c 2014-05-23 11:26:48.260939887 +0200 -@@ -609,6 +609,7 @@ - am43xx_clockdomains_init(); - am43xx_hwmod_init(); - omap_hwmod_init_postsetup(); -+ omap_l2_cache_init(); - omap_clk_soc_init = am43xx_dt_clk_init; - } - -@@ -640,6 +641,7 @@ - omap44xx_clockdomains_init(); - omap44xx_hwmod_init(); - omap_hwmod_init_postsetup(); -+ omap_l2_cache_init(); - omap_clk_soc_init = omap4xxx_dt_clk_init; - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-omap2/Kconfig linux-3.15-rc6/arch/arm/mach-omap2/Kconfig ---- linux-3.15-rc6.orig/arch/arm/mach-omap2/Kconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-omap2/Kconfig 2014-05-23 11:26:48.260939887 +0200 -@@ -65,6 +65,7 @@ - select ARCH_HAS_OPP - select ARM_GIC - select MACH_OMAP_GENERIC -+ select MIGHT_HAVE_CACHE_L2X0 - - config SOC_DRA7XX - bool "TI DRA7XX" -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-omap2/omap4-common.c linux-3.15-rc6/arch/arm/mach-omap2/omap4-common.c ---- linux-3.15-rc6.orig/arch/arm/mach-omap2/omap4-common.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-omap2/omap4-common.c 2014-05-23 11:26:48.260939887 +0200 -@@ -167,75 +167,57 @@ - return l2cache_base; - } - --static void omap4_l2x0_disable(void) -+static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) - { -- outer_flush_all(); -- /* Disable PL310 L2 Cache controller */ -- omap_smc1(0x102, 0x0); --} -+ unsigned smc_op; - --static void omap4_l2x0_set_debug(unsigned long val) --{ -- /* Program PL310 L2 Cache controller debug register */ -- omap_smc1(0x100, val); -+ switch (reg) { -+ case L2X0_CTRL: -+ smc_op = OMAP4_MON_L2X0_CTRL_INDEX; -+ break; -+ -+ case L2X0_AUX_CTRL: -+ smc_op = OMAP4_MON_L2X0_AUXCTRL_INDEX; -+ break; -+ -+ case L2X0_DEBUG_CTRL: -+ smc_op = OMAP4_MON_L2X0_DBG_CTRL_INDEX; -+ break; -+ -+ case L310_PREFETCH_CTRL: -+ smc_op = OMAP4_MON_L2X0_PREFETCH_INDEX; -+ break; -+ -+ default: -+ WARN_ONCE(1, "OMAP L2C310: ignoring write to reg 0x%x\n", reg); -+ return; -+ } -+ -+ omap_smc1(smc_op, val); - } - --static int __init omap_l2_cache_init(void) -+int __init omap_l2_cache_init(void) - { -- u32 aux_ctrl = 0; -- -- /* -- * To avoid code running on other OMAPs in -- * multi-omap builds -- */ -- if (!cpu_is_omap44xx()) -- return -ENODEV; -+ u32 aux_ctrl; - - /* Static mapping, never released */ - l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); - if (WARN_ON(!l2cache_base)) - return -ENOMEM; - -- /* -- * 16-way associativity, parity disabled -- * Way size - 32KB (es1.0) -- * Way size - 64KB (es2.0 +) -- */ -- aux_ctrl = ((1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) | -- (0x1 << 25) | -- (0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) | -- (0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT)); -- -- if (omap_rev() == OMAP4430_REV_ES1_0) { -- aux_ctrl |= 0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT; -- } else { -- aux_ctrl |= ((0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | -- (1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | -- (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | -- (1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | -- (1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT)); -- } -- if (omap_rev() != OMAP4430_REV_ES1_0) -- omap_smc1(0x109, aux_ctrl); -- -- /* Enable PL310 L2 Cache controller */ -- omap_smc1(0x102, 0x1); -+ /* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */ -+ aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE | -+ L310_AUX_CTRL_DATA_PREFETCH | -+ L310_AUX_CTRL_INSTR_PREFETCH; - -+ outer_cache.write_sec = omap4_l2c310_write_sec; - if (of_have_populated_dt()) -- l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK); -+ l2x0_of_init(aux_ctrl, 0xcf9fffff); - else -- l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK); -- -- /* -- * Override default outer_cache.disable with a OMAP4 -- * specific one -- */ -- outer_cache.disable = omap4_l2x0_disable; -- outer_cache.set_debug = omap4_l2x0_set_debug; -+ l2x0_init(l2cache_base, aux_ctrl, 0xcf9fffff); - - return 0; - } --omap_early_initcall(omap_l2_cache_init); - #endif - - void __iomem *omap4_get_sar_ram_base(void) -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c linux-3.15-rc6/arch/arm/mach-omap2/omap-mpuss-lowpower.c ---- linux-3.15-rc6.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2014-05-23 11:26:48.268939913 +0200 -@@ -187,19 +187,15 @@ - * in every restore MPUSS OFF path. - */ - #ifdef CONFIG_CACHE_L2X0 --static void save_l2x0_context(void) -+static void __init save_l2x0_context(void) - { -- u32 val; -- void __iomem *l2x0_base = omap4_get_l2cache_base(); -- if (l2x0_base) { -- val = __raw_readl(l2x0_base + L2X0_AUX_CTRL); -- __raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET); -- val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL); -- __raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET); -- } -+ __raw_writel(l2x0_saved_regs.aux_ctrl, -+ sar_base + L2X0_AUXCTRL_OFFSET); -+ __raw_writel(l2x0_saved_regs.prefetch_ctrl, -+ sar_base + L2X0_PREFETCH_CTRL_OFFSET); - } - #else --static void save_l2x0_context(void) -+static void __init save_l2x0_context(void) - {} - #endif - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-prima2/l2x0.c linux-3.15-rc6/arch/arm/mach-prima2/l2x0.c ---- linux-3.15-rc6.orig/arch/arm/mach-prima2/l2x0.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-prima2/l2x0.c 2014-05-23 11:26:48.268939913 +0200 -@@ -8,42 +8,10 @@ - - #include <linux/init.h> - #include <linux/kernel.h> --#include <linux/of.h> - #include <asm/hardware/cache-l2x0.h> - --struct l2x0_aux { -- u32 val; -- u32 mask; --}; -- --static const struct l2x0_aux prima2_l2x0_aux __initconst = { -- .val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT, -- .mask = 0, --}; -- --static const struct l2x0_aux marco_l2x0_aux __initconst = { -- .val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | -- (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT), -- .mask = L2X0_AUX_CTRL_MASK, --}; -- --static const struct of_device_id sirf_l2x0_ids[] __initconst = { -- { .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, }, -- { .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, }, -- {}, --}; -- - static int __init sirfsoc_l2x0_init(void) - { -- struct device_node *np; -- const struct l2x0_aux *aux; -- -- np = of_find_matching_node(NULL, sirf_l2x0_ids); -- if (np) { -- aux = of_match_node(sirf_l2x0_ids, np)->data; -- return l2x0_of_init(aux->val, aux->mask); -- } -- -- return 0; -+ return l2x0_of_init(0, ~0); - } - early_initcall(sirfsoc_l2x0_init); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-prima2/pm.c linux-3.15-rc6/arch/arm/mach-prima2/pm.c ---- linux-3.15-rc6.orig/arch/arm/mach-prima2/pm.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-prima2/pm.c 2014-05-23 11:26:48.268939913 +0200 -@@ -71,7 +71,6 @@ - case PM_SUSPEND_MEM: - sirfsoc_pre_suspend_power_off(); - -- outer_flush_all(); - outer_disable(); - /* go zzz */ - cpu_suspend(0, sirfsoc_finish_suspend); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-realview/realview_eb.c linux-3.15-rc6/arch/arm/mach-realview/realview_eb.c ---- linux-3.15-rc6.orig/arch/arm/mach-realview/realview_eb.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-realview/realview_eb.c 2014-05-23 11:26:48.268939913 +0200 -@@ -442,8 +442,13 @@ - realview_eb11mp_fixup(); - - #ifdef CONFIG_CACHE_L2X0 -- /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled -- * Bits: .... ...0 0111 1001 0000 .... .... .... */ -+ /* -+ * The PL220 needs to be manually configured as the hardware -+ * doesn't report the correct sizes. -+ * 1MB (128KB/way), 8-way associativity, event monitor and -+ * parity enabled, ignore share bit, no force write allocate -+ * Bits: .... ...0 0111 1001 0000 .... .... .... -+ */ - l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff); - #endif - platform_device_register(&pmu_device); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-realview/realview_pb1176.c linux-3.15-rc6/arch/arm/mach-realview/realview_pb1176.c ---- linux-3.15-rc6.orig/arch/arm/mach-realview/realview_pb1176.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-realview/realview_pb1176.c 2014-05-23 11:26:48.268939913 +0200 -@@ -355,7 +355,13 @@ - int i; - - #ifdef CONFIG_CACHE_L2X0 -- /* 128Kb (16Kb/way) 8-way associativity. evmon/parity/share enabled. */ -+ /* -+ * The PL220 needs to be manually configured as the hardware -+ * doesn't report the correct sizes. -+ * 128kB (16kB/way), 8-way associativity, event monitor and -+ * parity enabled, ignore share bit, no force write allocate -+ * Bits: .... ...0 0111 0011 0000 .... .... .... -+ */ - l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff); - #endif - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-realview/realview_pb11mp.c linux-3.15-rc6/arch/arm/mach-realview/realview_pb11mp.c ---- linux-3.15-rc6.orig/arch/arm/mach-realview/realview_pb11mp.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-realview/realview_pb11mp.c 2014-05-23 11:26:48.268939913 +0200 -@@ -337,8 +337,13 @@ - int i; - - #ifdef CONFIG_CACHE_L2X0 -- /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled -- * Bits: .... ...0 0111 1001 0000 .... .... .... */ -+ /* -+ * The PL220 needs to be manually configured as the hardware -+ * doesn't report the correct sizes. -+ * 1MB (128KB/way), 8-way associativity, event monitor and -+ * parity enabled, ignore share bit, no force write allocate -+ * Bits: .... ...0 0111 1001 0000 .... .... .... -+ */ - l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff); - #endif - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-realview/realview_pbx.c linux-3.15-rc6/arch/arm/mach-realview/realview_pbx.c ---- linux-3.15-rc6.orig/arch/arm/mach-realview/realview_pbx.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-realview/realview_pbx.c 2014-05-23 11:26:48.268939913 +0200 -@@ -370,8 +370,8 @@ - __io_address(REALVIEW_PBX_TILE_L220_BASE); - - /* set RAM latencies to 1 cycle for eASIC */ -- writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); -- writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); -+ writel(0, l2x0_base + L310_TAG_LATENCY_CTRL); -+ writel(0, l2x0_base + L310_DATA_LATENCY_CTRL); - - /* 16KB way size, 8-way associativity, parity disabled - * Bits: .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */ -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-rockchip/rockchip.c linux-3.15-rc6/arch/arm/mach-rockchip/rockchip.c ---- linux-3.15-rc6.orig/arch/arm/mach-rockchip/rockchip.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-rockchip/rockchip.c 2014-05-23 11:26:48.268939913 +0200 -@@ -26,7 +26,7 @@ - - static void __init rockchip_dt_init(void) - { -- l2x0_of_init(0, ~0UL); -+ l2x0_of_init(0, ~0); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-armadillo800eva.c linux-3.15-rc6/arch/arm/mach-shmobile/board-armadillo800eva.c ---- linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-armadillo800eva.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-shmobile/board-armadillo800eva.c 2014-05-23 11:26:48.272939927 +0200 -@@ -1271,8 +1271,8 @@ - - - #ifdef CONFIG_CACHE_L2X0 -- /* Early BRESP enable, Shared attribute override enable, 32K*8way */ -- l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff); -+ /* Shared attribute override enable, 32K*8way */ -+ l2x0_init(IOMEM(0xf0002000), 0x00400000, 0xc20f0fff); - #endif - - i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-armadillo800eva-reference.c linux-3.15-rc6/arch/arm/mach-shmobile/board-armadillo800eva-reference.c ---- linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-armadillo800eva-reference.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-shmobile/board-armadillo800eva-reference.c 2014-05-23 11:26:48.272939927 +0200 -@@ -164,8 +164,8 @@ - r8a7740_meram_workaround(); - - #ifdef CONFIG_CACHE_L2X0 -- /* Early BRESP enable, Shared attribute override enable, 32K*8way */ -- l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff); -+ /* Shared attribute override enable, 32K*8way */ -+ l2x0_init(IOMEM(0xf0002000), 0x00400000, 0xc20f0fff); - #endif - - r8a7740_add_standard_devices_dt(); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-kzm9g.c linux-3.15-rc6/arch/arm/mach-shmobile/board-kzm9g.c ---- linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-kzm9g.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-shmobile/board-kzm9g.c 2014-05-23 11:26:48.272939927 +0200 -@@ -876,8 +876,8 @@ - gpio_request_one(223, GPIOF_IN, NULL); /* IRQ8 */ - - #ifdef CONFIG_CACHE_L2X0 -- /* Early BRESP enable, Shared attribute override enable, 64K*8way */ -- l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); -+ /* Shared attribute override enable, 64K*8way */ -+ l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff); - #endif - - i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-kzm9g-reference.c linux-3.15-rc6/arch/arm/mach-shmobile/board-kzm9g-reference.c ---- linux-3.15-rc6.orig/arch/arm/mach-shmobile/board-kzm9g-reference.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-shmobile/board-kzm9g-reference.c 2014-05-23 11:26:48.272939927 +0200 -@@ -36,8 +36,8 @@ - sh73a0_add_standard_devices_dt(); - - #ifdef CONFIG_CACHE_L2X0 -- /* Early BRESP enable, Shared attribute override enable, 64K*8way */ -- l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); -+ /* Shared attribute override enable, 64K*8way */ -+ l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff); - #endif - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-shmobile/setup-r8a7778.c linux-3.15-rc6/arch/arm/mach-shmobile/setup-r8a7778.c ---- linux-3.15-rc6.orig/arch/arm/mach-shmobile/setup-r8a7778.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-shmobile/setup-r8a7778.c 2014-05-23 11:26:48.272939927 +0200 -@@ -298,10 +298,10 @@ - void __iomem *base = ioremap_nocache(0xf0100000, 0x1000); - if (base) { - /* -- * Early BRESP enable, Shared attribute override enable, 64K*16way -+ * Shared attribute override enable, 64K*16way - * don't call iounmap(base) - */ -- l2x0_init(base, 0x40470000, 0x82000fff); -+ l2x0_init(base, 0x00400000, 0xc20f0fff); - } - #endif - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-shmobile/setup-r8a7779.c linux-3.15-rc6/arch/arm/mach-shmobile/setup-r8a7779.c ---- linux-3.15-rc6.orig/arch/arm/mach-shmobile/setup-r8a7779.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-shmobile/setup-r8a7779.c 2014-05-23 11:26:48.272939927 +0200 -@@ -700,8 +700,8 @@ - void __init r8a7779_add_standard_devices(void) - { - #ifdef CONFIG_CACHE_L2X0 -- /* Early BRESP enable, Shared attribute override enable, 64K*16way */ -- l2x0_init(IOMEM(0xf0100000), 0x40470000, 0x82000fff); -+ /* Shared attribute override enable, 64K*16way */ -+ l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff); - #endif - r8a7779_pm_init(); - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-socfpga/socfpga.c linux-3.15-rc6/arch/arm/mach-socfpga/socfpga.c ---- linux-3.15-rc6.orig/arch/arm/mach-socfpga/socfpga.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-socfpga/socfpga.c 2014-05-23 11:26:48.272939927 +0200 -@@ -100,7 +100,7 @@ - - static void __init socfpga_cyclone5_init(void) - { -- l2x0_of_init(0, ~0UL); -+ l2x0_of_init(0, ~0); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-spear/platsmp.c linux-3.15-rc6/arch/arm/mach-spear/platsmp.c ---- linux-3.15-rc6.orig/arch/arm/mach-spear/platsmp.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-spear/platsmp.c 2014-05-23 11:26:48.272939927 +0200 -@@ -20,6 +20,18 @@ - #include <mach/spear.h> - #include "generic.h" - -+/* -+ * Write pen_release in a way that is guaranteed to be visible to all -+ * observers, irrespective of whether they're taking part in coherency -+ * or not. This is necessary for the hotplug code to work reliably. -+ */ -+static void write_pen_release(int val) -+{ -+ pen_release = val; -+ smp_wmb(); -+ sync_cache_w(&pen_release); -+} -+ - static DEFINE_SPINLOCK(boot_lock); - - static void __iomem *scu_base = IOMEM(VA_SCU_BASE); -@@ -30,8 +42,7 @@ - * let the primary processor know we're out of the - * pen, then head off into the C entry point - */ -- pen_release = -1; -- smp_wmb(); -+ write_pen_release(-1); - - /* - * Synchronise with the boot thread. -@@ -58,9 +69,7 @@ - * Note that "pen_release" is the hardware CPU ID, whereas - * "cpu" is Linux's internal ID. - */ -- pen_release = cpu; -- flush_cache_all(); -- outer_flush_all(); -+ write_pen_release(cpu); - - timeout = jiffies + (1 * HZ); - while (time_before(jiffies, timeout)) { -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-spear/spear13xx.c linux-3.15-rc6/arch/arm/mach-spear/spear13xx.c ---- linux-3.15-rc6.orig/arch/arm/mach-spear/spear13xx.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-spear/spear13xx.c 2014-05-23 11:26:48.272939927 +0200 -@@ -38,15 +38,15 @@ - if (!IS_ENABLED(CONFIG_CACHE_L2X0)) - return; - -- writel_relaxed(0x06, VA_L2CC_BASE + L2X0_PREFETCH_CTRL); -+ writel_relaxed(0x06, VA_L2CC_BASE + L310_PREFETCH_CTRL); - - /* - * Program following latencies in order to make - * SPEAr1340 work at 600 MHz - */ -- writel_relaxed(0x221, VA_L2CC_BASE + L2X0_TAG_LATENCY_CTRL); -- writel_relaxed(0x441, VA_L2CC_BASE + L2X0_DATA_LATENCY_CTRL); -- l2x0_init(VA_L2CC_BASE, 0x70A60001, 0xfe00ffff); -+ writel_relaxed(0x221, VA_L2CC_BASE + L310_TAG_LATENCY_CTRL); -+ writel_relaxed(0x441, VA_L2CC_BASE + L310_DATA_LATENCY_CTRL); -+ l2x0_init(VA_L2CC_BASE, 0x30a00001, 0xfe0fffff); - } - - /* -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-sti/board-dt.c linux-3.15-rc6/arch/arm/mach-sti/board-dt.c ---- linux-3.15-rc6.orig/arch/arm/mach-sti/board-dt.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-sti/board-dt.c 2014-05-23 11:26:48.272939927 +0200 -@@ -16,15 +16,9 @@ - - void __init stih41x_l2x0_init(void) - { -- u32 way_size = 0x4; -- u32 aux_ctrl; -- /* may be this can be encoded in macros like BIT*() */ -- aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | -- (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | -- (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | -- (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); -- -- l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK); -+ l2x0_of_init(L2C_AUX_CTRL_SHARED_OVERRIDE | -+ L310_AUX_CTRL_DATA_PREFETCH | -+ L310_AUX_CTRL_INSTR_PREFETCH, 0xc00f0fff); - } - - static void __init stih41x_machine_init(void) -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-tegra/pm.h linux-3.15-rc6/arch/arm/mach-tegra/pm.h ---- linux-3.15-rc6.orig/arch/arm/mach-tegra/pm.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-tegra/pm.h 2014-05-23 11:26:48.272939927 +0200 -@@ -35,8 +35,6 @@ - void tegra30_lp1_iram_hook(void); - void tegra30_sleep_core_init(void); - --extern unsigned long l2x0_saved_regs_addr; -- - void tegra_clear_cpu_in_lp2(void); - bool tegra_set_cpu_in_lp2(void); - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-tegra/reset-handler.S linux-3.15-rc6/arch/arm/mach-tegra/reset-handler.S ---- linux-3.15-rc6.orig/arch/arm/mach-tegra/reset-handler.S 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-tegra/reset-handler.S 2014-05-23 11:26:48.276939940 +0200 -@@ -19,7 +19,6 @@ - - #include <asm/cache.h> - #include <asm/asm-offsets.h> --#include <asm/hardware/cache-l2x0.h> - - #include "flowctrl.h" - #include "fuse.h" -@@ -78,8 +77,10 @@ - str r1, [r0] - #endif - -+#ifdef CONFIG_CACHE_L2X0 - /* L2 cache resume & re-enable */ -- l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr -+ bl l2c310_early_resume -+#endif - end_ca9_scu_l2_resume: - mov32 r9, 0xc0f - cmp r8, r9 -@@ -89,12 +90,6 @@ - ENDPROC(tegra_resume) - #endif - --#ifdef CONFIG_CACHE_L2X0 -- .globl l2x0_saved_regs_addr --l2x0_saved_regs_addr: -- .long 0 --#endif -- - .align L1_CACHE_SHIFT - ENTRY(__tegra_cpu_reset_handler_start) - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-tegra/sleep.h linux-3.15-rc6/arch/arm/mach-tegra/sleep.h ---- linux-3.15-rc6.orig/arch/arm/mach-tegra/sleep.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-tegra/sleep.h 2014-05-23 11:26:48.276939940 +0200 -@@ -120,37 +120,6 @@ - mov \tmp1, \tmp1, lsr #8 - .endm - --/* Macro to resume & re-enable L2 cache */ --#ifndef L2X0_CTRL_EN --#define L2X0_CTRL_EN 1 --#endif -- --#ifdef CONFIG_CACHE_L2X0 --.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs -- W(adr) \tmp1, \phys_l2x0_saved_regs -- ldr \tmp1, [\tmp1] -- ldr \tmp2, [\tmp1, #L2X0_R_PHY_BASE] -- ldr \tmp3, [\tmp2, #L2X0_CTRL] -- tst \tmp3, #L2X0_CTRL_EN -- bne exit_l2_resume -- ldr \tmp3, [\tmp1, #L2X0_R_TAG_LATENCY] -- str \tmp3, [\tmp2, #L2X0_TAG_LATENCY_CTRL] -- ldr \tmp3, [\tmp1, #L2X0_R_DATA_LATENCY] -- str \tmp3, [\tmp2, #L2X0_DATA_LATENCY_CTRL] -- ldr \tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL] -- str \tmp3, [\tmp2, #L2X0_PREFETCH_CTRL] -- ldr \tmp3, [\tmp1, #L2X0_R_PWR_CTRL] -- str \tmp3, [\tmp2, #L2X0_POWER_CTRL] -- ldr \tmp3, [\tmp1, #L2X0_R_AUX_CTRL] -- str \tmp3, [\tmp2, #L2X0_AUX_CTRL] -- mov \tmp3, #L2X0_CTRL_EN -- str \tmp3, [\tmp2, #L2X0_CTRL] --exit_l2_resume: --.endm --#else /* CONFIG_CACHE_L2X0 */ --.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs --.endm --#endif /* CONFIG_CACHE_L2X0 */ - #else - void tegra_pen_lock(void); - void tegra_pen_unlock(void); -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-tegra/tegra.c linux-3.15-rc6/arch/arm/mach-tegra/tegra.c ---- linux-3.15-rc6.orig/arch/arm/mach-tegra/tegra.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-tegra/tegra.c 2014-05-23 11:26:48.276939940 +0200 -@@ -73,27 +73,7 @@ - static void __init tegra_init_cache(void) - { - #ifdef CONFIG_CACHE_L2X0 -- static const struct of_device_id pl310_ids[] __initconst = { -- { .compatible = "arm,pl310-cache", }, -- {} -- }; -- -- struct device_node *np; -- int ret; -- void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; -- u32 aux_ctrl, cache_type; -- -- np = of_find_matching_node(NULL, pl310_ids); -- if (!np) -- return; -- -- cache_type = readl(p + L2X0_CACHE_TYPE); -- aux_ctrl = (cache_type & 0x700) << (17-8); -- aux_ctrl |= 0x7C400001; -- -- ret = l2x0_of_init(aux_ctrl, 0x8200c3fe); -- if (!ret) -- l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs); -+ l2x0_of_init(0x3c400001, 0xc20fc3fe); - #endif - } - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-ux500/cache-l2x0.c linux-3.15-rc6/arch/arm/mach-ux500/cache-l2x0.c ---- linux-3.15-rc6.orig/arch/arm/mach-ux500/cache-l2x0.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-ux500/cache-l2x0.c 2014-05-23 11:26:48.276939940 +0200 -@@ -35,10 +35,16 @@ - return 0; - } - --static int __init ux500_l2x0_init(void) -+static void ux500_l2c310_write_sec(unsigned long val, unsigned reg) - { -- u32 aux_val = 0x3e000000; -+ /* -+ * We can't write to secure registers as we are in non-secure -+ * mode, until we have some SMI service available. -+ */ -+} - -+static int __init ux500_l2x0_init(void) -+{ - if (cpu_is_u8500_family() || cpu_is_ux540_family()) - l2x0_base = __io_address(U8500_L2CC_BASE); - else -@@ -48,28 +54,12 @@ - /* Unlock before init */ - ux500_l2x0_unlock(); - -- /* DBx540's L2 has 128KB way size */ -- if (cpu_is_ux540_family()) -- /* 128KB way size */ -- aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); -- else -- /* 64KB way size */ -- aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); -+ outer_cache.write_sec = ux500_l2c310_write_sec; - -- /* 64KB way size, 8 way associativity, force WA */ - if (of_have_populated_dt()) -- l2x0_of_init(aux_val, 0xc0000fff); -+ l2x0_of_init(0, ~0); - else -- l2x0_init(l2x0_base, aux_val, 0xc0000fff); -- -- /* -- * We can't disable l2 as we are in non secure mode, currently -- * this seems be called only during kexec path. So let's -- * override outer.disable with nasty assignment until we have -- * some SMI service available. -- */ -- outer_cache.disable = NULL; -- outer_cache.set_debug = NULL; -+ l2x0_init(l2x0_base, 0, ~0); - - return 0; - } -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-vexpress/ct-ca9x4.c linux-3.15-rc6/arch/arm/mach-vexpress/ct-ca9x4.c ---- linux-3.15-rc6.orig/arch/arm/mach-vexpress/ct-ca9x4.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-vexpress/ct-ca9x4.c 2014-05-23 11:26:48.276939940 +0200 -@@ -45,6 +45,23 @@ - iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); - } - -+static void __init ca9x4_l2_init(void) -+{ -+#ifdef CONFIG_CACHE_L2X0 -+ void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); -+ -+ if (l2x0_base) { -+ /* set RAM latencies to 1 cycle for this core tile. */ -+ writel(0, l2x0_base + L310_TAG_LATENCY_CTRL); -+ writel(0, l2x0_base + L310_DATA_LATENCY_CTRL); -+ -+ l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); -+ } else { -+ pr_err("L2C: unable to map L2 cache controller\n"); -+ } -+#endif -+} -+ - #ifdef CONFIG_HAVE_ARM_TWD - static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER); - -@@ -63,6 +80,7 @@ - gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), - ioremap(A9_MPCORE_GIC_CPU, SZ_256)); - ca9x4_twd_init(); -+ ca9x4_l2_init(); - } - - static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) -@@ -141,16 +159,6 @@ - { - int i; - --#ifdef CONFIG_CACHE_L2X0 -- void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); -- -- /* set RAM latencies to 1 cycle for this core tile. */ -- writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); -- writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); -- -- l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); --#endif -- - for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) - amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); - -diff -Nur linux-3.15-rc6.orig/arch/arm/mach-zynq/common.c linux-3.15-rc6/arch/arm/mach-zynq/common.c ---- linux-3.15-rc6.orig/arch/arm/mach-zynq/common.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mach-zynq/common.c 2014-05-23 11:26:48.276939940 +0200 -@@ -70,7 +70,7 @@ - /* - * 64KB way size, 8-way associativity, parity disabled - */ -- l2x0_of_init(0x02060000, 0xF0F0FFFF); -+ l2x0_of_init(0x02000000, 0xf0ffffff); - - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - -diff -Nur linux-3.15-rc6.orig/arch/arm/mm/cache-feroceon-l2.c linux-3.15-rc6/arch/arm/mm/cache-feroceon-l2.c ---- linux-3.15-rc6.orig/arch/arm/mm/cache-feroceon-l2.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mm/cache-feroceon-l2.c 2014-05-23 11:26:48.280939953 +0200 -@@ -350,7 +350,6 @@ - outer_cache.inv_range = feroceon_l2_inv_range; - outer_cache.clean_range = feroceon_l2_clean_range; - outer_cache.flush_range = feroceon_l2_flush_range; -- outer_cache.inv_all = l2_inv_all; - - enable_l2(); - -diff -Nur linux-3.15-rc6.orig/arch/arm/mm/cache-l2x0.c linux-3.15-rc6/arch/arm/mm/cache-l2x0.c ---- linux-3.15-rc6.orig/arch/arm/mm/cache-l2x0.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mm/cache-l2x0.c 2014-05-23 11:26:48.280939953 +0200 -@@ -16,18 +16,33 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -+#include <linux/cpu.h> - #include <linux/err.h> - #include <linux/init.h> -+#include <linux/smp.h> - #include <linux/spinlock.h> - #include <linux/io.h> - #include <linux/of.h> - #include <linux/of_address.h> - - #include <asm/cacheflush.h> -+#include <asm/cp15.h> -+#include <asm/cputype.h> - #include <asm/hardware/cache-l2x0.h> - #include "cache-tauros3.h" - #include "cache-aurora-l2.h" - -+struct l2c_init_data { -+ const char *type; -+ unsigned way_size_0; -+ unsigned num_lock; -+ void (*of_parse)(const struct device_node *, u32 *, u32 *); -+ void (*enable)(void __iomem *, u32, unsigned); -+ void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); -+ void (*save)(void __iomem *); -+ struct outer_cache_fns outer_cache; -+}; -+ - #define CACHE_LINE_SIZE 32 - - static void __iomem *l2x0_base; -@@ -36,96 +51,116 @@ - static u32 l2x0_size; - static unsigned long sync_reg_offset = L2X0_CACHE_SYNC; - --/* Aurora don't have the cache ID register available, so we have to -- * pass it though the device tree */ --static u32 cache_id_part_number_from_dt; -- - struct l2x0_regs l2x0_saved_regs; - --struct l2x0_of_data { -- void (*setup)(const struct device_node *, u32 *, u32 *); -- void (*save)(void); -- struct outer_cache_fns outer_cache; --}; -- --static bool of_init = false; -- --static inline void cache_wait_way(void __iomem *reg, unsigned long mask) -+/* -+ * Common code for all cache controllers. -+ */ -+static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask) - { - /* wait for cache operation by line or way to complete */ - while (readl_relaxed(reg) & mask) - cpu_relax(); - } - --#ifdef CONFIG_CACHE_PL310 --static inline void cache_wait(void __iomem *reg, unsigned long mask) -+/* -+ * By default, we write directly to secure registers. Platforms must -+ * override this if they are running non-secure. -+ */ -+static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg) - { -- /* cache operations by line are atomic on PL310 */ -+ if (val == readl_relaxed(base + reg)) -+ return; -+ if (outer_cache.write_sec) -+ outer_cache.write_sec(val, reg); -+ else -+ writel_relaxed(val, base + reg); - } --#else --#define cache_wait cache_wait_way --#endif - --static inline void cache_sync(void) -+/* -+ * This should only be called when we have a requirement that the -+ * register be written due to a work-around, as platforms running -+ * in non-secure mode may not be able to access this register. -+ */ -+static inline void l2c_set_debug(void __iomem *base, unsigned long val) - { -- void __iomem *base = l2x0_base; -- -- writel_relaxed(0, base + sync_reg_offset); -- cache_wait(base + L2X0_CACHE_SYNC, 1); -+ l2c_write_sec(val, base, L2X0_DEBUG_CTRL); - } - --static inline void l2x0_clean_line(unsigned long addr) -+static void __l2c_op_way(void __iomem *reg) - { -- void __iomem *base = l2x0_base; -- cache_wait(base + L2X0_CLEAN_LINE_PA, 1); -- writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA); -+ writel_relaxed(l2x0_way_mask, reg); -+ l2c_wait_mask(reg, l2x0_way_mask); - } - --static inline void l2x0_inv_line(unsigned long addr) -+static inline void l2c_unlock(void __iomem *base, unsigned num) - { -- void __iomem *base = l2x0_base; -- cache_wait(base + L2X0_INV_LINE_PA, 1); -- writel_relaxed(addr, base + L2X0_INV_LINE_PA); -+ unsigned i; -+ -+ for (i = 0; i < num; i++) { -+ writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_D_BASE + -+ i * L2X0_LOCKDOWN_STRIDE); -+ writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_I_BASE + -+ i * L2X0_LOCKDOWN_STRIDE); -+ } - } - --#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) --static inline void debug_writel(unsigned long val) -+/* -+ * Enable the L2 cache controller. This function must only be -+ * called when the cache controller is known to be disabled. -+ */ -+static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) - { -- if (outer_cache.set_debug) -- outer_cache.set_debug(val); -+ unsigned long flags; -+ -+ l2c_write_sec(aux, base, L2X0_AUX_CTRL); -+ -+ l2c_unlock(base, num_lock); -+ -+ local_irq_save(flags); -+ __l2c_op_way(base + L2X0_INV_WAY); -+ writel_relaxed(0, base + sync_reg_offset); -+ l2c_wait_mask(base + sync_reg_offset, 1); -+ local_irq_restore(flags); -+ -+ l2c_write_sec(L2X0_CTRL_EN, base, L2X0_CTRL); - } - --static void pl310_set_debug(unsigned long val) -+static void l2c_disable(void) - { -- writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL); -+ void __iomem *base = l2x0_base; -+ -+ outer_cache.flush_all(); -+ l2c_write_sec(0, base, L2X0_CTRL); -+ dsb(st); - } --#else --/* Optimised out for non-errata case */ --static inline void debug_writel(unsigned long val) -+ -+#ifdef CONFIG_CACHE_PL310 -+static inline void cache_wait(void __iomem *reg, unsigned long mask) - { -+ /* cache operations by line are atomic on PL310 */ - } -- --#define pl310_set_debug NULL -+#else -+#define cache_wait l2c_wait_mask - #endif - --#ifdef CONFIG_PL310_ERRATA_588369 --static inline void l2x0_flush_line(unsigned long addr) -+static inline void cache_sync(void) - { - void __iomem *base = l2x0_base; - -- /* Clean by PA followed by Invalidate by PA */ -- cache_wait(base + L2X0_CLEAN_LINE_PA, 1); -- writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA); -- cache_wait(base + L2X0_INV_LINE_PA, 1); -- writel_relaxed(addr, base + L2X0_INV_LINE_PA); -+ writel_relaxed(0, base + sync_reg_offset); -+ cache_wait(base + L2X0_CACHE_SYNC, 1); - } --#else - --static inline void l2x0_flush_line(unsigned long addr) -+#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) -+static inline void debug_writel(unsigned long val) -+{ -+ l2c_set_debug(l2x0_base, val); -+} -+#else -+/* Optimised out for non-errata case */ -+static inline void debug_writel(unsigned long val) - { -- void __iomem *base = l2x0_base; -- cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); -- writel_relaxed(addr, base + L2X0_CLEAN_INV_LINE_PA); - } - #endif - -@@ -141,8 +176,7 @@ - static void __l2x0_flush_all(void) - { - debug_writel(0x03); -- writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); -- cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); -+ __l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY); - cache_sync(); - debug_writel(0x00); - } -@@ -157,274 +191,882 @@ - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - } - --static void l2x0_clean_all(void) -+static void l2x0_disable(void) - { - unsigned long flags; - -- /* clean all ways */ - raw_spin_lock_irqsave(&l2x0_lock, flags); -- writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); -- cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); -- cache_sync(); -+ __l2x0_flush_all(); -+ l2c_write_sec(0, l2x0_base, L2X0_CTRL); -+ dsb(st); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - } - --static void l2x0_inv_all(void) -+static void l2c_save(void __iomem *base) - { -- unsigned long flags; -+ l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); -+} - -- /* invalidate all ways */ -- raw_spin_lock_irqsave(&l2x0_lock, flags); -- /* Invalidating when L2 is enabled is a nono */ -- BUG_ON(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN); -- writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); -- cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); -- cache_sync(); -- raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+/* -+ * L2C-210 specific code. -+ * -+ * The L2C-2x0 PA, set/way and sync operations are atomic, but we must -+ * ensure that no background operation is running. The way operations -+ * are all background tasks. -+ * -+ * While a background operation is in progress, any new operation is -+ * ignored (unspecified whether this causes an error.) Thankfully, not -+ * used on SMP. -+ * -+ * Never has a different sync register other than L2X0_CACHE_SYNC, but -+ * we use sync_reg_offset here so we can share some of this with L2C-310. -+ */ -+static void __l2c210_cache_sync(void __iomem *base) -+{ -+ writel_relaxed(0, base + sync_reg_offset); - } - --static void l2x0_inv_range(unsigned long start, unsigned long end) -+static void __l2c210_op_pa_range(void __iomem *reg, unsigned long start, -+ unsigned long end) -+{ -+ while (start < end) { -+ writel_relaxed(start, reg); -+ start += CACHE_LINE_SIZE; -+ } -+} -+ -+static void l2c210_inv_range(unsigned long start, unsigned long end) - { - void __iomem *base = l2x0_base; -- unsigned long flags; - -- raw_spin_lock_irqsave(&l2x0_lock, flags); - if (start & (CACHE_LINE_SIZE - 1)) { - start &= ~(CACHE_LINE_SIZE - 1); -- debug_writel(0x03); -- l2x0_flush_line(start); -- debug_writel(0x00); -+ writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA); - start += CACHE_LINE_SIZE; - } - - if (end & (CACHE_LINE_SIZE - 1)) { - end &= ~(CACHE_LINE_SIZE - 1); -- debug_writel(0x03); -- l2x0_flush_line(end); -- debug_writel(0x00); -+ writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA); - } - -+ __l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end); -+ __l2c210_cache_sync(base); -+} -+ -+static void l2c210_clean_range(unsigned long start, unsigned long end) -+{ -+ void __iomem *base = l2x0_base; -+ -+ start &= ~(CACHE_LINE_SIZE - 1); -+ __l2c210_op_pa_range(base + L2X0_CLEAN_LINE_PA, start, end); -+ __l2c210_cache_sync(base); -+} -+ -+static void l2c210_flush_range(unsigned long start, unsigned long end) -+{ -+ void __iomem *base = l2x0_base; -+ -+ start &= ~(CACHE_LINE_SIZE - 1); -+ __l2c210_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, start, end); -+ __l2c210_cache_sync(base); -+} -+ -+static void l2c210_flush_all(void) -+{ -+ void __iomem *base = l2x0_base; -+ -+ BUG_ON(!irqs_disabled()); -+ -+ __l2c_op_way(base + L2X0_CLEAN_INV_WAY); -+ __l2c210_cache_sync(base); -+} -+ -+static void l2c210_sync(void) -+{ -+ __l2c210_cache_sync(l2x0_base); -+} -+ -+static void l2c210_resume(void) -+{ -+ void __iomem *base = l2x0_base; -+ -+ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) -+ l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1); -+} -+ -+static const struct l2c_init_data l2c210_data __initconst = { -+ .type = "L2C-210", -+ .way_size_0 = SZ_8K, -+ .num_lock = 1, -+ .enable = l2c_enable, -+ .save = l2c_save, -+ .outer_cache = { -+ .inv_range = l2c210_inv_range, -+ .clean_range = l2c210_clean_range, -+ .flush_range = l2c210_flush_range, -+ .flush_all = l2c210_flush_all, -+ .disable = l2c_disable, -+ .sync = l2c210_sync, -+ .resume = l2c210_resume, -+ }, -+}; -+ -+/* -+ * L2C-220 specific code. -+ * -+ * All operations are background operations: they have to be waited for. -+ * Conflicting requests generate a slave error (which will cause an -+ * imprecise abort.) Never uses sync_reg_offset, so we hard-code the -+ * sync register here. -+ * -+ * However, we can re-use the l2c210_resume call. -+ */ -+static inline void __l2c220_cache_sync(void __iomem *base) -+{ -+ writel_relaxed(0, base + L2X0_CACHE_SYNC); -+ l2c_wait_mask(base + L2X0_CACHE_SYNC, 1); -+} -+ -+static void l2c220_op_way(void __iomem *base, unsigned reg) -+{ -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&l2x0_lock, flags); -+ __l2c_op_way(base + reg); -+ __l2c220_cache_sync(base); -+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+} -+ -+static unsigned long l2c220_op_pa_range(void __iomem *reg, unsigned long start, -+ unsigned long end, unsigned long flags) -+{ -+ raw_spinlock_t *lock = &l2x0_lock; -+ - while (start < end) { - unsigned long blk_end = start + min(end - start, 4096UL); - - while (start < blk_end) { -- l2x0_inv_line(start); -+ l2c_wait_mask(reg, 1); -+ writel_relaxed(start, reg); - start += CACHE_LINE_SIZE; - } - - if (blk_end < end) { -- raw_spin_unlock_irqrestore(&l2x0_lock, flags); -- raw_spin_lock_irqsave(&l2x0_lock, flags); -+ raw_spin_unlock_irqrestore(lock, flags); -+ raw_spin_lock_irqsave(lock, flags); - } - } -- cache_wait(base + L2X0_INV_LINE_PA, 1); -- cache_sync(); -- raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+ -+ return flags; - } - --static void l2x0_clean_range(unsigned long start, unsigned long end) -+static void l2c220_inv_range(unsigned long start, unsigned long end) - { - void __iomem *base = l2x0_base; - unsigned long flags; - -- if ((end - start) >= l2x0_size) { -- l2x0_clean_all(); -- return; -- } -- - raw_spin_lock_irqsave(&l2x0_lock, flags); -- start &= ~(CACHE_LINE_SIZE - 1); -- while (start < end) { -- unsigned long blk_end = start + min(end - start, 4096UL); -- -- while (start < blk_end) { -- l2x0_clean_line(start); -+ if ((start | end) & (CACHE_LINE_SIZE - 1)) { -+ if (start & (CACHE_LINE_SIZE - 1)) { -+ start &= ~(CACHE_LINE_SIZE - 1); -+ writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA); - start += CACHE_LINE_SIZE; - } - -- if (blk_end < end) { -- raw_spin_unlock_irqrestore(&l2x0_lock, flags); -- raw_spin_lock_irqsave(&l2x0_lock, flags); -+ if (end & (CACHE_LINE_SIZE - 1)) { -+ end &= ~(CACHE_LINE_SIZE - 1); -+ l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1); -+ writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA); - } - } -- cache_wait(base + L2X0_CLEAN_LINE_PA, 1); -- cache_sync(); -+ -+ flags = l2c220_op_pa_range(base + L2X0_INV_LINE_PA, -+ start, end, flags); -+ l2c_wait_mask(base + L2X0_INV_LINE_PA, 1); -+ __l2c220_cache_sync(base); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - } - --static void l2x0_flush_range(unsigned long start, unsigned long end) -+static void l2c220_clean_range(unsigned long start, unsigned long end) - { - void __iomem *base = l2x0_base; - unsigned long flags; - -+ start &= ~(CACHE_LINE_SIZE - 1); - if ((end - start) >= l2x0_size) { -- l2x0_flush_all(); -+ l2c220_op_way(base, L2X0_CLEAN_WAY); - return; - } - - raw_spin_lock_irqsave(&l2x0_lock, flags); -+ flags = l2c220_op_pa_range(base + L2X0_CLEAN_LINE_PA, -+ start, end, flags); -+ l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1); -+ __l2c220_cache_sync(base); -+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+} -+ -+static void l2c220_flush_range(unsigned long start, unsigned long end) -+{ -+ void __iomem *base = l2x0_base; -+ unsigned long flags; -+ - start &= ~(CACHE_LINE_SIZE - 1); -+ if ((end - start) >= l2x0_size) { -+ l2c220_op_way(base, L2X0_CLEAN_INV_WAY); -+ return; -+ } -+ -+ raw_spin_lock_irqsave(&l2x0_lock, flags); -+ flags = l2c220_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, -+ start, end, flags); -+ l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1); -+ __l2c220_cache_sync(base); -+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+} -+ -+static void l2c220_flush_all(void) -+{ -+ l2c220_op_way(l2x0_base, L2X0_CLEAN_INV_WAY); -+} -+ -+static void l2c220_sync(void) -+{ -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&l2x0_lock, flags); -+ __l2c220_cache_sync(l2x0_base); -+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+} -+ -+static void l2c220_enable(void __iomem *base, u32 aux, unsigned num_lock) -+{ -+ /* -+ * Always enable non-secure access to the lockdown registers - -+ * we write to them as part of the L2C enable sequence so they -+ * need to be accessible. -+ */ -+ aux |= L220_AUX_CTRL_NS_LOCKDOWN; -+ -+ l2c_enable(base, aux, num_lock); -+} -+ -+static const struct l2c_init_data l2c220_data = { -+ .type = "L2C-220", -+ .way_size_0 = SZ_8K, -+ .num_lock = 1, -+ .enable = l2c220_enable, -+ .save = l2c_save, -+ .outer_cache = { -+ .inv_range = l2c220_inv_range, -+ .clean_range = l2c220_clean_range, -+ .flush_range = l2c220_flush_range, -+ .flush_all = l2c220_flush_all, -+ .disable = l2c_disable, -+ .sync = l2c220_sync, -+ .resume = l2c210_resume, -+ }, -+}; -+ -+/* -+ * L2C-310 specific code. -+ * -+ * Very similar to L2C-210, the PA, set/way and sync operations are atomic, -+ * and the way operations are all background tasks. However, issuing an -+ * operation while a background operation is in progress results in a -+ * SLVERR response. We can reuse: -+ * -+ * __l2c210_cache_sync (using sync_reg_offset) -+ * l2c210_sync -+ * l2c210_inv_range (if 588369 is not applicable) -+ * l2c210_clean_range -+ * l2c210_flush_range (if 588369 is not applicable) -+ * l2c210_flush_all (if 727915 is not applicable) -+ * -+ * Errata: -+ * 588369: PL310 R0P0->R1P0, fixed R2P0. -+ * Affects: all clean+invalidate operations -+ * clean and invalidate skips the invalidate step, so we need to issue -+ * separate operations. We also require the above debug workaround -+ * enclosing this code fragment on affected parts. On unaffected parts, -+ * we must not use this workaround without the debug register writes -+ * to avoid exposing a problem similar to 727915. -+ * -+ * 727915: PL310 R2P0->R3P0, fixed R3P1. -+ * Affects: clean+invalidate by way -+ * clean and invalidate by way runs in the background, and a store can -+ * hit the line between the clean operation and invalidate operation, -+ * resulting in the store being lost. -+ * -+ * 752271: PL310 R3P0->R3P1-50REL0, fixed R3P2. -+ * Affects: 8x64-bit (double fill) line fetches -+ * double fill line fetches can fail to cause dirty data to be evicted -+ * from the cache before the new data overwrites the second line. -+ * -+ * 753970: PL310 R3P0, fixed R3P1. -+ * Affects: sync -+ * prevents merging writes after the sync operation, until another L2C -+ * operation is performed (or a number of other conditions.) -+ * -+ * 769419: PL310 R0P0->R3P1, fixed R3P2. -+ * Affects: store buffer -+ * store buffer is not automatically drained. -+ */ -+static void l2c310_inv_range_erratum(unsigned long start, unsigned long end) -+{ -+ void __iomem *base = l2x0_base; -+ -+ if ((start | end) & (CACHE_LINE_SIZE - 1)) { -+ unsigned long flags; -+ -+ /* Erratum 588369 for both clean+invalidate operations */ -+ raw_spin_lock_irqsave(&l2x0_lock, flags); -+ l2c_set_debug(base, 0x03); -+ -+ if (start & (CACHE_LINE_SIZE - 1)) { -+ start &= ~(CACHE_LINE_SIZE - 1); -+ writel_relaxed(start, base + L2X0_CLEAN_LINE_PA); -+ writel_relaxed(start, base + L2X0_INV_LINE_PA); -+ start += CACHE_LINE_SIZE; -+ } -+ -+ if (end & (CACHE_LINE_SIZE - 1)) { -+ end &= ~(CACHE_LINE_SIZE - 1); -+ writel_relaxed(end, base + L2X0_CLEAN_LINE_PA); -+ writel_relaxed(end, base + L2X0_INV_LINE_PA); -+ } -+ -+ l2c_set_debug(base, 0x00); -+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+ } -+ -+ __l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end); -+ __l2c210_cache_sync(base); -+} -+ -+static void l2c310_flush_range_erratum(unsigned long start, unsigned long end) -+{ -+ raw_spinlock_t *lock = &l2x0_lock; -+ unsigned long flags; -+ void __iomem *base = l2x0_base; -+ -+ raw_spin_lock_irqsave(lock, flags); - while (start < end) { - unsigned long blk_end = start + min(end - start, 4096UL); - -- debug_writel(0x03); -+ l2c_set_debug(base, 0x03); - while (start < blk_end) { -- l2x0_flush_line(start); -+ writel_relaxed(start, base + L2X0_CLEAN_LINE_PA); -+ writel_relaxed(start, base + L2X0_INV_LINE_PA); - start += CACHE_LINE_SIZE; - } -- debug_writel(0x00); -+ l2c_set_debug(base, 0x00); - - if (blk_end < end) { -- raw_spin_unlock_irqrestore(&l2x0_lock, flags); -- raw_spin_lock_irqsave(&l2x0_lock, flags); -+ raw_spin_unlock_irqrestore(lock, flags); -+ raw_spin_lock_irqsave(lock, flags); - } - } -- cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); -- cache_sync(); -- raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+ raw_spin_unlock_irqrestore(lock, flags); -+ __l2c210_cache_sync(base); - } - --static void l2x0_disable(void) -+static void l2c310_flush_all_erratum(void) - { -+ void __iomem *base = l2x0_base; - unsigned long flags; - - raw_spin_lock_irqsave(&l2x0_lock, flags); -- __l2x0_flush_all(); -- writel_relaxed(0, l2x0_base + L2X0_CTRL); -- dsb(st); -+ l2c_set_debug(base, 0x03); -+ __l2c_op_way(base + L2X0_CLEAN_INV_WAY); -+ l2c_set_debug(base, 0x00); -+ __l2c210_cache_sync(base); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - } - --static void l2x0_unlock(u32 cache_id) -+static void __init l2c310_save(void __iomem *base) - { -- int lockregs; -- int i; -+ unsigned revision; - -- switch (cache_id & L2X0_CACHE_ID_PART_MASK) { -- case L2X0_CACHE_ID_PART_L310: -- lockregs = 8; -- break; -- case AURORA_CACHE_ID: -- lockregs = 4; -+ l2c_save(base); -+ -+ l2x0_saved_regs.tag_latency = readl_relaxed(base + -+ L310_TAG_LATENCY_CTRL); -+ l2x0_saved_regs.data_latency = readl_relaxed(base + -+ L310_DATA_LATENCY_CTRL); -+ l2x0_saved_regs.filter_end = readl_relaxed(base + -+ L310_ADDR_FILTER_END); -+ l2x0_saved_regs.filter_start = readl_relaxed(base + -+ L310_ADDR_FILTER_START); -+ -+ revision = readl_relaxed(base + L2X0_CACHE_ID) & -+ L2X0_CACHE_ID_RTL_MASK; -+ -+ /* From r2p0, there is Prefetch offset/control register */ -+ if (revision >= L310_CACHE_ID_RTL_R2P0) -+ l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base + -+ L310_PREFETCH_CTRL); -+ -+ /* From r3p0, there is Power control register */ -+ if (revision >= L310_CACHE_ID_RTL_R3P0) -+ l2x0_saved_regs.pwr_ctrl = readl_relaxed(base + -+ L310_POWER_CTRL); -+} -+ -+static void l2c310_resume(void) -+{ -+ void __iomem *base = l2x0_base; -+ -+ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { -+ unsigned revision; -+ -+ /* restore pl310 setup */ -+ writel_relaxed(l2x0_saved_regs.tag_latency, -+ base + L310_TAG_LATENCY_CTRL); -+ writel_relaxed(l2x0_saved_regs.data_latency, -+ base + L310_DATA_LATENCY_CTRL); -+ writel_relaxed(l2x0_saved_regs.filter_end, -+ base + L310_ADDR_FILTER_END); -+ writel_relaxed(l2x0_saved_regs.filter_start, -+ base + L310_ADDR_FILTER_START); -+ -+ revision = readl_relaxed(base + L2X0_CACHE_ID) & -+ L2X0_CACHE_ID_RTL_MASK; -+ -+ if (revision >= L310_CACHE_ID_RTL_R2P0) -+ l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, -+ L310_PREFETCH_CTRL); -+ if (revision >= L310_CACHE_ID_RTL_R3P0) -+ l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, -+ L310_POWER_CTRL); -+ -+ l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); -+ -+ /* Re-enable full-line-of-zeros for Cortex-A9 */ -+ if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) -+ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); -+ } -+} -+ -+static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) -+{ -+ switch (act & ~CPU_TASKS_FROZEN) { -+ case CPU_STARTING: -+ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); - break; -- default: -- /* L210 and unknown types */ -- lockregs = 1; -+ case CPU_DYING: -+ set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1))); - break; - } -+ return NOTIFY_OK; -+} - -- for (i = 0; i < lockregs; i++) { -- writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + -- i * L2X0_LOCKDOWN_STRIDE); -- writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + -- i * L2X0_LOCKDOWN_STRIDE); -+static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) -+{ -+ unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_PART_MASK; -+ bool cortex_a9 = read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9; -+ -+ if (rev >= L310_CACHE_ID_RTL_R2P0) { -+ if (cortex_a9) { -+ aux |= L310_AUX_CTRL_EARLY_BRESP; -+ pr_info("L2C-310 enabling early BRESP for Cortex-A9\n"); -+ } else if (aux & L310_AUX_CTRL_EARLY_BRESP) { -+ pr_warn("L2C-310 early BRESP only supported with Cortex-A9\n"); -+ aux &= ~L310_AUX_CTRL_EARLY_BRESP; -+ } -+ } -+ -+ if (cortex_a9) { -+ u32 aux_cur = readl_relaxed(base + L2X0_AUX_CTRL); -+ u32 acr = get_auxcr(); -+ -+ pr_debug("Cortex-A9 ACR=0x%08x\n", acr); -+ -+ if (acr & BIT(3) && !(aux_cur & L310_AUX_CTRL_FULL_LINE_ZERO)) -+ pr_err("L2C-310: full line of zeros enabled in Cortex-A9 but not L2C-310 - invalid\n"); -+ -+ if (aux & L310_AUX_CTRL_FULL_LINE_ZERO && !(acr & BIT(3))) -+ pr_err("L2C-310: enabling full line of zeros but not enabled in Cortex-A9\n"); -+ -+ if (!(aux & L310_AUX_CTRL_FULL_LINE_ZERO) && !outer_cache.write_sec) { -+ aux |= L310_AUX_CTRL_FULL_LINE_ZERO; -+ pr_info("L2C-310 full line of zeros enabled for Cortex-A9\n"); -+ } -+ } else if (aux & (L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP)) { -+ pr_err("L2C-310: disabling Cortex-A9 specific feature bits\n"); -+ aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); -+ } -+ -+ if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { -+ u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); -+ -+ pr_info("L2C-310 %s%s prefetch enabled, offset %u lines\n", -+ aux & L310_AUX_CTRL_INSTR_PREFETCH ? "I" : "", -+ aux & L310_AUX_CTRL_DATA_PREFETCH ? "D" : "", -+ 1 + (prefetch & L310_PREFETCH_CTRL_OFFSET_MASK)); -+ } -+ -+ /* r3p0 or later has power control register */ -+ if (rev >= L310_CACHE_ID_RTL_R3P0) { -+ u32 power_ctrl; -+ -+ l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN, -+ base, L310_POWER_CTRL); -+ power_ctrl = readl_relaxed(base + L310_POWER_CTRL); -+ pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", -+ power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", -+ power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); -+ } -+ -+ /* -+ * Always enable non-secure access to the lockdown registers - -+ * we write to them as part of the L2C enable sequence so they -+ * need to be accessible. -+ */ -+ aux |= L310_AUX_CTRL_NS_LOCKDOWN; -+ -+ l2c_enable(base, aux, num_lock); -+ -+ if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { -+ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); -+ cpu_notifier(l2c310_cpu_enable_flz, 0); - } - } - --void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) -+static void __init l2c310_fixup(void __iomem *base, u32 cache_id, -+ struct outer_cache_fns *fns) - { -- u32 aux; -- u32 cache_id; -- u32 way_size = 0; -- int ways; -- int way_size_shift = L2X0_WAY_SIZE_SHIFT; -- const char *type; -+ unsigned revision = cache_id & L2X0_CACHE_ID_RTL_MASK; -+ const char *errata[8]; -+ unsigned n = 0; - -- l2x0_base = base; -- if (cache_id_part_number_from_dt) -- cache_id = cache_id_part_number_from_dt; -- else -- cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); -- aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); -+ if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) && -+ revision < L310_CACHE_ID_RTL_R2P0 && -+ /* For bcm compatibility */ -+ fns->inv_range == l2c210_inv_range) { -+ fns->inv_range = l2c310_inv_range_erratum; -+ fns->flush_range = l2c310_flush_range_erratum; -+ errata[n++] = "588369"; -+ } -+ -+ if (IS_ENABLED(CONFIG_PL310_ERRATA_727915) && -+ revision >= L310_CACHE_ID_RTL_R2P0 && -+ revision < L310_CACHE_ID_RTL_R3P1) { -+ fns->flush_all = l2c310_flush_all_erratum; -+ errata[n++] = "727915"; -+ } -+ -+ if (revision >= L310_CACHE_ID_RTL_R3P0 && -+ revision < L310_CACHE_ID_RTL_R3P2) { -+ u32 val = readl_relaxed(base + L310_PREFETCH_CTRL); -+ /* I don't think bit23 is required here... but iMX6 does so */ -+ if (val & (BIT(30) | BIT(23))) { -+ val &= ~(BIT(30) | BIT(23)); -+ l2c_write_sec(val, base, L310_PREFETCH_CTRL); -+ errata[n++] = "752271"; -+ } -+ } -+ -+ if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) && -+ revision == L310_CACHE_ID_RTL_R3P0) { -+ sync_reg_offset = L2X0_DUMMY_REG; -+ errata[n++] = "753970"; -+ } -+ -+ if (IS_ENABLED(CONFIG_PL310_ERRATA_769419)) -+ errata[n++] = "769419"; -+ -+ if (n) { -+ unsigned i; -+ -+ pr_info("L2C-310 errat%s", n > 1 ? "a" : "um"); -+ for (i = 0; i < n; i++) -+ pr_cont(" %s", errata[i]); -+ pr_cont(" enabled\n"); -+ } -+} -+ -+static void l2c310_disable(void) -+{ -+ /* -+ * If full-line-of-zeros is enabled, we must first disable it in the -+ * Cortex-A9 auxiliary control register before disabling the L2 cache. -+ */ -+ if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) -+ set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1))); - -+ l2c_disable(); -+} -+ -+static const struct l2c_init_data l2c310_init_fns __initconst = { -+ .type = "L2C-310", -+ .way_size_0 = SZ_8K, -+ .num_lock = 8, -+ .enable = l2c310_enable, -+ .fixup = l2c310_fixup, -+ .save = l2c310_save, -+ .outer_cache = { -+ .inv_range = l2c210_inv_range, -+ .clean_range = l2c210_clean_range, -+ .flush_range = l2c210_flush_range, -+ .flush_all = l2c210_flush_all, -+ .disable = l2c310_disable, -+ .sync = l2c210_sync, -+ .resume = l2c310_resume, -+ }, -+}; -+ -+static void __init __l2c_init(const struct l2c_init_data *data, -+ u32 aux_val, u32 aux_mask, u32 cache_id) -+{ -+ struct outer_cache_fns fns; -+ unsigned way_size_bits, ways; -+ u32 aux, old_aux; -+ -+ /* -+ * Sanity check the aux values. aux_mask is the bits we preserve -+ * from reading the hardware register, and aux_val is the bits we -+ * set. -+ */ -+ if (aux_val & aux_mask) -+ pr_alert("L2C: platform provided aux values permit register corruption.\n"); -+ -+ old_aux = aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); - aux &= aux_mask; - aux |= aux_val; - -+ if (old_aux != aux) -+ pr_warn("L2C: DT/platform modifies aux control register: 0x%08x -> 0x%08x\n", -+ old_aux, aux); -+ - /* Determine the number of ways */ - switch (cache_id & L2X0_CACHE_ID_PART_MASK) { - case L2X0_CACHE_ID_PART_L310: -+ if ((aux_val | ~aux_mask) & (L2C_AUX_CTRL_WAY_SIZE_MASK | L310_AUX_CTRL_ASSOCIATIVITY_16)) -+ pr_warn("L2C: DT/platform tries to modify or specify cache size\n"); - if (aux & (1 << 16)) - ways = 16; - else - ways = 8; -- type = "L310"; --#ifdef CONFIG_PL310_ERRATA_753970 -- /* Unmapped register. */ -- sync_reg_offset = L2X0_DUMMY_REG; --#endif -- if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L2X0_CACHE_ID_RTL_R3P0) -- outer_cache.set_debug = pl310_set_debug; - break; -+ - case L2X0_CACHE_ID_PART_L210: -+ case L2X0_CACHE_ID_PART_L220: - ways = (aux >> 13) & 0xf; -- type = "L210"; - break; - - case AURORA_CACHE_ID: -- sync_reg_offset = AURORA_SYNC_REG; - ways = (aux >> 13) & 0xf; - ways = 2 << ((ways + 1) >> 2); -- way_size_shift = AURORA_WAY_SIZE_SHIFT; -- type = "Aurora"; - break; -+ - default: - /* Assume unknown chips have 8 ways */ - ways = 8; -- type = "L2x0 series"; - break; - } - - l2x0_way_mask = (1 << ways) - 1; - - /* -- * L2 cache Size = Way size * Number of ways -+ * way_size_0 is the size that a way_size value of zero would be -+ * given the calculation: way_size = way_size_0 << way_size_bits. -+ * So, if way_size_bits=0 is reserved, but way_size_bits=1 is 16k, -+ * then way_size_0 would be 8k. -+ * -+ * L2 cache size = number of ways * way size. -+ */ -+ way_size_bits = (aux & L2C_AUX_CTRL_WAY_SIZE_MASK) >> -+ L2C_AUX_CTRL_WAY_SIZE_SHIFT; -+ l2x0_size = ways * (data->way_size_0 << way_size_bits); -+ -+ fns = data->outer_cache; -+ fns.write_sec = outer_cache.write_sec; -+ if (data->fixup) -+ data->fixup(l2x0_base, cache_id, &fns); -+ -+ /* -+ * Check if l2x0 controller is already enabled. If we are booting -+ * in non-secure mode accessing the below registers will fault. - */ -- way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17; -- way_size = 1 << (way_size + way_size_shift); -+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) -+ data->enable(l2x0_base, aux, data->num_lock); - -- l2x0_size = ways * way_size * SZ_1K; -+ outer_cache = fns; - - /* -- * Check if l2x0 controller is already enabled. -- * If you are booting from non-secure mode -- * accessing the below registers will fault. -+ * It is strange to save the register state before initialisation, -+ * but hey, this is what the DT implementations decided to do. - */ -- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { -- /* Make sure that I&D is not locked down when starting */ -- l2x0_unlock(cache_id); -+ if (data->save) -+ data->save(l2x0_base); -+ -+ /* Re-read it in case some bits are reserved. */ -+ aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); -+ -+ pr_info("%s cache controller enabled, %d ways, %d kB\n", -+ data->type, ways, l2x0_size >> 10); -+ pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", -+ data->type, cache_id, aux); -+} - -- /* l2x0 controller is disabled */ -- writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); -+void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) -+{ -+ const struct l2c_init_data *data; -+ u32 cache_id; - -- l2x0_inv_all(); -+ l2x0_base = base; - -- /* enable L2X0 */ -- writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); -+ cache_id = readl_relaxed(base + L2X0_CACHE_ID); -+ -+ switch (cache_id & L2X0_CACHE_ID_PART_MASK) { -+ default: -+ case L2X0_CACHE_ID_PART_L210: -+ data = &l2c210_data; -+ break; -+ -+ case L2X0_CACHE_ID_PART_L220: -+ data = &l2c220_data; -+ break; -+ -+ case L2X0_CACHE_ID_PART_L310: -+ data = &l2c310_init_fns; -+ break; - } - -- /* Re-read it in case some bits are reserved. */ -- aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); -+ __l2c_init(data, aux_val, aux_mask, cache_id); -+} -+ -+#ifdef CONFIG_OF -+static int l2_wt_override; -+ -+/* Aurora don't have the cache ID register available, so we have to -+ * pass it though the device tree */ -+static u32 cache_id_part_number_from_dt; -+ -+static void __init l2x0_of_parse(const struct device_node *np, -+ u32 *aux_val, u32 *aux_mask) -+{ -+ u32 data[2] = { 0, 0 }; -+ u32 tag = 0; -+ u32 dirty = 0; -+ u32 val = 0, mask = 0; -+ -+ of_property_read_u32(np, "arm,tag-latency", &tag); -+ if (tag) { -+ mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; -+ val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; -+ } -+ -+ of_property_read_u32_array(np, "arm,data-latency", -+ data, ARRAY_SIZE(data)); -+ if (data[0] && data[1]) { -+ mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | -+ L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; -+ val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | -+ ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); -+ } -+ -+ of_property_read_u32(np, "arm,dirty-latency", &dirty); -+ if (dirty) { -+ mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; -+ val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; -+ } - -- /* Save the value for resuming. */ -- l2x0_saved_regs.aux_ctrl = aux; -+ *aux_val &= ~mask; -+ *aux_val |= val; -+ *aux_mask &= ~mask; -+} -+ -+static const struct l2c_init_data of_l2c210_data __initconst = { -+ .type = "L2C-210", -+ .way_size_0 = SZ_8K, -+ .num_lock = 1, -+ .of_parse = l2x0_of_parse, -+ .enable = l2c_enable, -+ .save = l2c_save, -+ .outer_cache = { -+ .inv_range = l2c210_inv_range, -+ .clean_range = l2c210_clean_range, -+ .flush_range = l2c210_flush_range, -+ .flush_all = l2c210_flush_all, -+ .disable = l2c_disable, -+ .sync = l2c210_sync, -+ .resume = l2c210_resume, -+ }, -+}; -+ -+static const struct l2c_init_data of_l2c220_data __initconst = { -+ .type = "L2C-220", -+ .way_size_0 = SZ_8K, -+ .num_lock = 1, -+ .of_parse = l2x0_of_parse, -+ .enable = l2c220_enable, -+ .save = l2c_save, -+ .outer_cache = { -+ .inv_range = l2c220_inv_range, -+ .clean_range = l2c220_clean_range, -+ .flush_range = l2c220_flush_range, -+ .flush_all = l2c220_flush_all, -+ .disable = l2c_disable, -+ .sync = l2c220_sync, -+ .resume = l2c210_resume, -+ }, -+}; -+ -+static void __init l2c310_of_parse(const struct device_node *np, -+ u32 *aux_val, u32 *aux_mask) -+{ -+ u32 data[3] = { 0, 0, 0 }; -+ u32 tag[3] = { 0, 0, 0 }; -+ u32 filter[2] = { 0, 0 }; -+ -+ of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); -+ if (tag[0] && tag[1] && tag[2]) -+ writel_relaxed( -+ L310_LATENCY_CTRL_RD(tag[0] - 1) | -+ L310_LATENCY_CTRL_WR(tag[1] - 1) | -+ L310_LATENCY_CTRL_SETUP(tag[2] - 1), -+ l2x0_base + L310_TAG_LATENCY_CTRL); -+ -+ of_property_read_u32_array(np, "arm,data-latency", -+ data, ARRAY_SIZE(data)); -+ if (data[0] && data[1] && data[2]) -+ writel_relaxed( -+ L310_LATENCY_CTRL_RD(data[0] - 1) | -+ L310_LATENCY_CTRL_WR(data[1] - 1) | -+ L310_LATENCY_CTRL_SETUP(data[2] - 1), -+ l2x0_base + L310_DATA_LATENCY_CTRL); - -- if (!of_init) { -- outer_cache.inv_range = l2x0_inv_range; -- outer_cache.clean_range = l2x0_clean_range; -- outer_cache.flush_range = l2x0_flush_range; -- outer_cache.sync = l2x0_cache_sync; -- outer_cache.flush_all = l2x0_flush_all; -- outer_cache.inv_all = l2x0_inv_all; -- outer_cache.disable = l2x0_disable; -- } -- -- pr_info("%s cache controller enabled\n", type); -- pr_info("l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d kB\n", -- ways, cache_id, aux, l2x0_size >> 10); -+ of_property_read_u32_array(np, "arm,filter-ranges", -+ filter, ARRAY_SIZE(filter)); -+ if (filter[1]) { -+ writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), -+ l2x0_base + L310_ADDR_FILTER_END); -+ writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN, -+ l2x0_base + L310_ADDR_FILTER_START); -+ } - } - --#ifdef CONFIG_OF --static int l2_wt_override; -+static const struct l2c_init_data of_l2c310_data __initconst = { -+ .type = "L2C-310", -+ .way_size_0 = SZ_8K, -+ .num_lock = 8, -+ .of_parse = l2c310_of_parse, -+ .enable = l2c310_enable, -+ .fixup = l2c310_fixup, -+ .save = l2c310_save, -+ .outer_cache = { -+ .inv_range = l2c210_inv_range, -+ .clean_range = l2c210_clean_range, -+ .flush_range = l2c210_flush_range, -+ .flush_all = l2c210_flush_all, -+ .disable = l2c310_disable, -+ .sync = l2c210_sync, -+ .resume = l2c310_resume, -+ }, -+}; - - /* - * Note that the end addresses passed to Linux primitives are -@@ -524,6 +1166,100 @@ - } - } - -+static void aurora_save(void __iomem *base) -+{ -+ l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); -+ l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); -+} -+ -+static void aurora_resume(void) -+{ -+ void __iomem *base = l2x0_base; -+ -+ if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) { -+ writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL); -+ writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL); -+ } -+} -+ -+/* -+ * For Aurora cache in no outer mode, enable via the CP15 coprocessor -+ * broadcasting of cache commands to L2. -+ */ -+static void __init aurora_enable_no_outer(void __iomem *base, u32 aux, -+ unsigned num_lock) -+{ -+ u32 u; -+ -+ asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u)); -+ u |= AURORA_CTRL_FW; /* Set the FW bit */ -+ asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u)); -+ -+ isb(); -+ -+ l2c_enable(base, aux, num_lock); -+} -+ -+static void __init aurora_fixup(void __iomem *base, u32 cache_id, -+ struct outer_cache_fns *fns) -+{ -+ sync_reg_offset = AURORA_SYNC_REG; -+} -+ -+static void __init aurora_of_parse(const struct device_node *np, -+ u32 *aux_val, u32 *aux_mask) -+{ -+ u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; -+ u32 mask = AURORA_ACR_REPLACEMENT_MASK; -+ -+ of_property_read_u32(np, "cache-id-part", -+ &cache_id_part_number_from_dt); -+ -+ /* Determine and save the write policy */ -+ l2_wt_override = of_property_read_bool(np, "wt-override"); -+ -+ if (l2_wt_override) { -+ val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY; -+ mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK; -+ } -+ -+ *aux_val &= ~mask; -+ *aux_val |= val; -+ *aux_mask &= ~mask; -+} -+ -+static const struct l2c_init_data of_aurora_with_outer_data __initconst = { -+ .type = "Aurora", -+ .way_size_0 = SZ_4K, -+ .num_lock = 4, -+ .of_parse = aurora_of_parse, -+ .enable = l2c_enable, -+ .fixup = aurora_fixup, -+ .save = aurora_save, -+ .outer_cache = { -+ .inv_range = aurora_inv_range, -+ .clean_range = aurora_clean_range, -+ .flush_range = aurora_flush_range, -+ .flush_all = l2x0_flush_all, -+ .disable = l2x0_disable, -+ .sync = l2x0_cache_sync, -+ .resume = aurora_resume, -+ }, -+}; -+ -+static const struct l2c_init_data of_aurora_no_outer_data __initconst = { -+ .type = "Aurora", -+ .way_size_0 = SZ_4K, -+ .num_lock = 4, -+ .of_parse = aurora_of_parse, -+ .enable = aurora_enable_no_outer, -+ .fixup = aurora_fixup, -+ .save = aurora_save, -+ .outer_cache = { -+ .resume = aurora_resume, -+ }, -+}; -+ - /* - * For certain Broadcom SoCs, depending on the address range, different offsets - * need to be added to the address before passing it to L2 for -@@ -588,16 +1324,16 @@ - - /* normal case, no cross section between start and end */ - if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { -- l2x0_inv_range(new_start, new_end); -+ l2c210_inv_range(new_start, new_end); - return; - } - - /* They cross sections, so it can only be a cross from section - * 2 to section 3 - */ -- l2x0_inv_range(new_start, -+ l2c210_inv_range(new_start, - bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); -- l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), -+ l2c210_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), - new_end); - } - -@@ -610,26 +1346,21 @@ - if (unlikely(end <= start)) - return; - -- if ((end - start) >= l2x0_size) { -- l2x0_clean_all(); -- return; -- } -- - new_start = bcm_l2_phys_addr(start); - new_end = bcm_l2_phys_addr(end); - - /* normal case, no cross section between start and end */ - if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { -- l2x0_clean_range(new_start, new_end); -+ l2c210_clean_range(new_start, new_end); - return; - } - - /* They cross sections, so it can only be a cross from section - * 2 to section 3 - */ -- l2x0_clean_range(new_start, -+ l2c210_clean_range(new_start, - bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); -- l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), -+ l2c210_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), - new_end); - } - -@@ -643,7 +1374,7 @@ - return; - - if ((end - start) >= l2x0_size) { -- l2x0_flush_all(); -+ outer_cache.flush_all(); - return; - } - -@@ -652,283 +1383,67 @@ - - /* normal case, no cross section between start and end */ - if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { -- l2x0_flush_range(new_start, new_end); -+ l2c210_flush_range(new_start, new_end); - return; - } - - /* They cross sections, so it can only be a cross from section - * 2 to section 3 - */ -- l2x0_flush_range(new_start, -+ l2c210_flush_range(new_start, - bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); -- l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), -+ l2c210_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), - new_end); - } - --static void __init l2x0_of_setup(const struct device_node *np, -- u32 *aux_val, u32 *aux_mask) --{ -- u32 data[2] = { 0, 0 }; -- u32 tag = 0; -- u32 dirty = 0; -- u32 val = 0, mask = 0; -- -- of_property_read_u32(np, "arm,tag-latency", &tag); -- if (tag) { -- mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; -- val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; -- } -- -- of_property_read_u32_array(np, "arm,data-latency", -- data, ARRAY_SIZE(data)); -- if (data[0] && data[1]) { -- mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | -- L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; -- val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | -- ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); -- } -- -- of_property_read_u32(np, "arm,dirty-latency", &dirty); -- if (dirty) { -- mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; -- val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; -- } -- -- *aux_val &= ~mask; -- *aux_val |= val; -- *aux_mask &= ~mask; --} -- --static void __init pl310_of_setup(const struct device_node *np, -- u32 *aux_val, u32 *aux_mask) --{ -- u32 data[3] = { 0, 0, 0 }; -- u32 tag[3] = { 0, 0, 0 }; -- u32 filter[2] = { 0, 0 }; -- -- of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); -- if (tag[0] && tag[1] && tag[2]) -- writel_relaxed( -- ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | -- ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | -- ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), -- l2x0_base + L2X0_TAG_LATENCY_CTRL); -- -- of_property_read_u32_array(np, "arm,data-latency", -- data, ARRAY_SIZE(data)); -- if (data[0] && data[1] && data[2]) -- writel_relaxed( -- ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | -- ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | -- ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), -- l2x0_base + L2X0_DATA_LATENCY_CTRL); -- -- of_property_read_u32_array(np, "arm,filter-ranges", -- filter, ARRAY_SIZE(filter)); -- if (filter[1]) { -- writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), -- l2x0_base + L2X0_ADDR_FILTER_END); -- writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN, -- l2x0_base + L2X0_ADDR_FILTER_START); -- } --} -- --static void __init pl310_save(void) --{ -- u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & -- L2X0_CACHE_ID_RTL_MASK; -- -- l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base + -- L2X0_TAG_LATENCY_CTRL); -- l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base + -- L2X0_DATA_LATENCY_CTRL); -- l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base + -- L2X0_ADDR_FILTER_END); -- l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base + -- L2X0_ADDR_FILTER_START); -- -- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { -- /* -- * From r2p0, there is Prefetch offset/control register -- */ -- l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base + -- L2X0_PREFETCH_CTRL); -- /* -- * From r3p0, there is Power control register -- */ -- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) -- l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base + -- L2X0_POWER_CTRL); -- } --} -+/* Broadcom L2C-310 start from ARMs R3P2 or later, and require no fixups */ -+static const struct l2c_init_data of_bcm_l2x0_data __initconst = { -+ .type = "BCM-L2C-310", -+ .way_size_0 = SZ_8K, -+ .num_lock = 8, -+ .of_parse = l2c310_of_parse, -+ .enable = l2c310_enable, -+ .save = l2c310_save, -+ .outer_cache = { -+ .inv_range = bcm_inv_range, -+ .clean_range = bcm_clean_range, -+ .flush_range = bcm_flush_range, -+ .flush_all = l2c210_flush_all, -+ .disable = l2c310_disable, -+ .sync = l2c210_sync, -+ .resume = l2c310_resume, -+ }, -+}; - --static void aurora_save(void) -+static void __init tauros3_save(void __iomem *base) - { -- l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL); -- l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); --} -+ l2c_save(base); - --static void __init tauros3_save(void) --{ - l2x0_saved_regs.aux2_ctrl = -- readl_relaxed(l2x0_base + TAUROS3_AUX2_CTRL); -+ readl_relaxed(base + TAUROS3_AUX2_CTRL); - l2x0_saved_regs.prefetch_ctrl = -- readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL); --} -- --static void l2x0_resume(void) --{ -- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { -- /* restore aux ctrl and enable l2 */ -- l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID)); -- -- writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base + -- L2X0_AUX_CTRL); -- -- l2x0_inv_all(); -- -- writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); -- } --} -- --static void pl310_resume(void) --{ -- u32 l2x0_revision; -- -- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { -- /* restore pl310 setup */ -- writel_relaxed(l2x0_saved_regs.tag_latency, -- l2x0_base + L2X0_TAG_LATENCY_CTRL); -- writel_relaxed(l2x0_saved_regs.data_latency, -- l2x0_base + L2X0_DATA_LATENCY_CTRL); -- writel_relaxed(l2x0_saved_regs.filter_end, -- l2x0_base + L2X0_ADDR_FILTER_END); -- writel_relaxed(l2x0_saved_regs.filter_start, -- l2x0_base + L2X0_ADDR_FILTER_START); -- -- l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & -- L2X0_CACHE_ID_RTL_MASK; -- -- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { -- writel_relaxed(l2x0_saved_regs.prefetch_ctrl, -- l2x0_base + L2X0_PREFETCH_CTRL); -- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) -- writel_relaxed(l2x0_saved_regs.pwr_ctrl, -- l2x0_base + L2X0_POWER_CTRL); -- } -- } -- -- l2x0_resume(); --} -- --static void aurora_resume(void) --{ -- if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { -- writel_relaxed(l2x0_saved_regs.aux_ctrl, -- l2x0_base + L2X0_AUX_CTRL); -- writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL); -- } -+ readl_relaxed(base + L310_PREFETCH_CTRL); - } - - static void tauros3_resume(void) - { -- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { -+ void __iomem *base = l2x0_base; -+ -+ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { - writel_relaxed(l2x0_saved_regs.aux2_ctrl, -- l2x0_base + TAUROS3_AUX2_CTRL); -+ base + TAUROS3_AUX2_CTRL); - writel_relaxed(l2x0_saved_regs.prefetch_ctrl, -- l2x0_base + L2X0_PREFETCH_CTRL); -- } -- -- l2x0_resume(); --} -- --static void __init aurora_broadcast_l2_commands(void) --{ -- __u32 u; -- /* Enable Broadcasting of cache commands to L2*/ -- __asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u)); -- u |= AURORA_CTRL_FW; /* Set the FW bit */ -- __asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u)); -- isb(); --} -- --static void __init aurora_of_setup(const struct device_node *np, -- u32 *aux_val, u32 *aux_mask) --{ -- u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; -- u32 mask = AURORA_ACR_REPLACEMENT_MASK; -+ base + L310_PREFETCH_CTRL); - -- of_property_read_u32(np, "cache-id-part", -- &cache_id_part_number_from_dt); -- -- /* Determine and save the write policy */ -- l2_wt_override = of_property_read_bool(np, "wt-override"); -- -- if (l2_wt_override) { -- val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY; -- mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK; -+ l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); - } -- -- *aux_val &= ~mask; -- *aux_val |= val; -- *aux_mask &= ~mask; - } - --static const struct l2x0_of_data pl310_data = { -- .setup = pl310_of_setup, -- .save = pl310_save, -- .outer_cache = { -- .resume = pl310_resume, -- .inv_range = l2x0_inv_range, -- .clean_range = l2x0_clean_range, -- .flush_range = l2x0_flush_range, -- .sync = l2x0_cache_sync, -- .flush_all = l2x0_flush_all, -- .inv_all = l2x0_inv_all, -- .disable = l2x0_disable, -- }, --}; -- --static const struct l2x0_of_data l2x0_data = { -- .setup = l2x0_of_setup, -- .save = NULL, -- .outer_cache = { -- .resume = l2x0_resume, -- .inv_range = l2x0_inv_range, -- .clean_range = l2x0_clean_range, -- .flush_range = l2x0_flush_range, -- .sync = l2x0_cache_sync, -- .flush_all = l2x0_flush_all, -- .inv_all = l2x0_inv_all, -- .disable = l2x0_disable, -- }, --}; -- --static const struct l2x0_of_data aurora_with_outer_data = { -- .setup = aurora_of_setup, -- .save = aurora_save, -- .outer_cache = { -- .resume = aurora_resume, -- .inv_range = aurora_inv_range, -- .clean_range = aurora_clean_range, -- .flush_range = aurora_flush_range, -- .sync = l2x0_cache_sync, -- .flush_all = l2x0_flush_all, -- .inv_all = l2x0_inv_all, -- .disable = l2x0_disable, -- }, --}; -- --static const struct l2x0_of_data aurora_no_outer_data = { -- .setup = aurora_of_setup, -- .save = aurora_save, -- .outer_cache = { -- .resume = aurora_resume, -- }, --}; -- --static const struct l2x0_of_data tauros3_data = { -- .setup = NULL, -+static const struct l2c_init_data of_tauros3_data __initconst = { -+ .type = "Tauros3", -+ .way_size_0 = SZ_8K, -+ .num_lock = 8, -+ .enable = l2c_enable, - .save = tauros3_save, - /* Tauros3 broadcasts L1 cache operations to L2 */ - .outer_cache = { -@@ -936,43 +1451,26 @@ - }, - }; - --static const struct l2x0_of_data bcm_l2x0_data = { -- .setup = pl310_of_setup, -- .save = pl310_save, -- .outer_cache = { -- .resume = pl310_resume, -- .inv_range = bcm_inv_range, -- .clean_range = bcm_clean_range, -- .flush_range = bcm_flush_range, -- .sync = l2x0_cache_sync, -- .flush_all = l2x0_flush_all, -- .inv_all = l2x0_inv_all, -- .disable = l2x0_disable, -- }, --}; -- -+#define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } - static const struct of_device_id l2x0_ids[] __initconst = { -- { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data }, -- { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, -- { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, -- { .compatible = "bcm,bcm11351-a2-pl310-cache", /* deprecated name */ -- .data = (void *)&bcm_l2x0_data}, -- { .compatible = "brcm,bcm11351-a2-pl310-cache", -- .data = (void *)&bcm_l2x0_data}, -- { .compatible = "marvell,aurora-outer-cache", -- .data = (void *)&aurora_with_outer_data}, -- { .compatible = "marvell,aurora-system-cache", -- .data = (void *)&aurora_no_outer_data}, -- { .compatible = "marvell,tauros3-cache", -- .data = (void *)&tauros3_data }, -+ L2C_ID("arm,l210-cache", of_l2c210_data), -+ L2C_ID("arm,l220-cache", of_l2c220_data), -+ L2C_ID("arm,pl310-cache", of_l2c310_data), -+ L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), -+ L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data), -+ L2C_ID("marvell,aurora-system-cache", of_aurora_no_outer_data), -+ L2C_ID("marvell,tauros3-cache", of_tauros3_data), -+ /* Deprecated IDs */ -+ L2C_ID("bcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), - {} - }; - - int __init l2x0_of_init(u32 aux_val, u32 aux_mask) - { -+ const struct l2c_init_data *data; - struct device_node *np; -- const struct l2x0_of_data *data; - struct resource res; -+ u32 cache_id, old_aux; - - np = of_find_matching_node(NULL, l2x0_ids); - if (!np) -@@ -989,23 +1487,29 @@ - - data = of_match_node(l2x0_ids, np)->data; - -- /* L2 configuration can only be changed if the cache is disabled */ -- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { -- if (data->setup) -- data->setup(np, &aux_val, &aux_mask); -- -- /* For aurora cache in no outer mode select the -- * correct mode using the coprocessor*/ -- if (data == &aurora_no_outer_data) -- aurora_broadcast_l2_commands(); -+ old_aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); -+ if (old_aux != ((old_aux & aux_mask) | aux_val)) { -+ pr_warn("L2C: platform modifies aux control register: 0x%08x -> 0x%08x\n", -+ old_aux, (old_aux & aux_mask) | aux_val); -+ } else if (aux_mask != ~0U && aux_val != 0) { -+ pr_alert("L2C: platform provided aux values match the hardware, so have no effect. Please remove them.\n"); - } - -- if (data->save) -- data->save(); -+ /* All L2 caches are unified, so this property should be specified */ -+ if (!of_property_read_bool(np, "cache-unified")) -+ pr_err("L2C: device tree omits to specify unified cache\n"); -+ -+ /* L2 configuration can only be changed if the cache is disabled */ -+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) -+ if (data->of_parse) -+ data->of_parse(np, &aux_val, &aux_mask); -+ -+ if (cache_id_part_number_from_dt) -+ cache_id = cache_id_part_number_from_dt; -+ else -+ cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); - -- of_init = true; -- memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache)); -- l2x0_init(l2x0_base, aux_val, aux_mask); -+ __l2c_init(data, aux_val, aux_mask, cache_id); - - return 0; - } -diff -Nur linux-3.15-rc6.orig/arch/arm/mm/Kconfig linux-3.15-rc6/arch/arm/mm/Kconfig ---- linux-3.15-rc6.orig/arch/arm/mm/Kconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mm/Kconfig 2014-05-23 11:26:48.280939953 +0200 -@@ -897,6 +897,57 @@ - This option enables optimisations for the PL310 cache - controller. - -+config PL310_ERRATA_588369 -+ bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines" -+ depends on CACHE_L2X0 -+ help -+ The PL310 L2 cache controller implements three types of Clean & -+ Invalidate maintenance operations: by Physical Address -+ (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC). -+ They are architecturally defined to behave as the execution of a -+ clean operation followed immediately by an invalidate operation, -+ both performing to the same memory location. This functionality -+ is not correctly implemented in PL310 as clean lines are not -+ invalidated as a result of these operations. -+ -+config PL310_ERRATA_727915 -+ bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption" -+ depends on CACHE_L2X0 -+ help -+ PL310 implements the Clean & Invalidate by Way L2 cache maintenance -+ operation (offset 0x7FC). This operation runs in background so that -+ PL310 can handle normal accesses while it is in progress. Under very -+ rare circumstances, due to this erratum, write data can be lost when -+ PL310 treats a cacheable write transaction during a Clean & -+ Invalidate by Way operation. -+ -+config PL310_ERRATA_753970 -+ bool "PL310 errata: cache sync operation may be faulty" -+ depends on CACHE_PL310 -+ help -+ This option enables the workaround for the 753970 PL310 (r3p0) erratum. -+ -+ Under some condition the effect of cache sync operation on -+ the store buffer still remains when the operation completes. -+ This means that the store buffer is always asked to drain and -+ this prevents it from merging any further writes. The workaround -+ is to replace the normal offset of cache sync operation (0x730) -+ by another offset targeting an unmapped PL310 register 0x740. -+ This has the same effect as the cache sync operation: store buffer -+ drain and waiting for all buffers empty. -+ -+config PL310_ERRATA_769419 -+ bool "PL310 errata: no automatic Store Buffer drain" -+ depends on CACHE_L2X0 -+ help -+ On revisions of the PL310 prior to r3p2, the Store Buffer does -+ not automatically drain. This can cause normal, non-cacheable -+ writes to be retained when the memory system is idle, leading -+ to suboptimal I/O performance for drivers using coherent DMA. -+ This option adds a write barrier to the cpu_idle loop so that, -+ on systems with an outer cache, the store buffer is drained -+ explicitly. -+ - config CACHE_TAUROS2 - bool "Enable the Tauros2 L2 cache controller" - depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4) -diff -Nur linux-3.15-rc6.orig/arch/arm/mm/l2c-common.c linux-3.15-rc6/arch/arm/mm/l2c-common.c ---- linux-3.15-rc6.orig/arch/arm/mm/l2c-common.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/arch/arm/mm/l2c-common.c 2014-05-23 11:26:48.284939966 +0200 -@@ -0,0 +1,20 @@ -+/* -+ * Copyright (C) 2010 ARM Ltd. -+ * Written by Catalin Marinas <catalin.marinas@arm.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/bug.h> -+#include <linux/smp.h> -+#include <asm/outercache.h> -+ -+void outer_disable(void) -+{ -+ WARN_ON(!irqs_disabled()); -+ WARN_ON(num_online_cpus() > 1); -+ -+ if (outer_cache.disable) -+ outer_cache.disable(); -+} -diff -Nur linux-3.15-rc6.orig/arch/arm/mm/l2c-l2x0-resume.S linux-3.15-rc6/arch/arm/mm/l2c-l2x0-resume.S ---- linux-3.15-rc6.orig/arch/arm/mm/l2c-l2x0-resume.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/arch/arm/mm/l2c-l2x0-resume.S 2014-05-23 11:26:48.284939966 +0200 -@@ -0,0 +1,58 @@ -+/* -+ * L2C-310 early resume code. This can be used by platforms to restore -+ * the settings of their L2 cache controller before restoring the -+ * processor state. -+ * -+ * This code can only be used to if you are running in the secure world. -+ */ -+#include <linux/linkage.h> -+#include <asm/hardware/cache-l2x0.h> -+ -+ .text -+ -+ENTRY(l2c310_early_resume) -+ adr r0, 1f -+ ldr r2, [r0] -+ add r0, r2, r0 -+ -+ ldmia r0, {r1, r2, r3, r4, r5, r6, r7, r8} -+ @ r1 = phys address of L2C-310 controller -+ @ r2 = aux_ctrl -+ @ r3 = tag_latency -+ @ r4 = data_latency -+ @ r5 = filter_start -+ @ r6 = filter_end -+ @ r7 = prefetch_ctrl -+ @ r8 = pwr_ctrl -+ -+ @ Check that the address has been initialised -+ teq r1, #0 -+ moveq pc, lr -+ -+ @ The prefetch and power control registers are revision dependent -+ @ and can be written whether or not the L2 cache is enabled -+ ldr r0, [r1, #L2X0_CACHE_ID] -+ and r0, r0, #L2X0_CACHE_ID_RTL_MASK -+ cmp r0, #L310_CACHE_ID_RTL_R2P0 -+ strcs r7, [r1, #L310_PREFETCH_CTRL] -+ cmp r0, #L310_CACHE_ID_RTL_R3P0 -+ strcs r8, [r1, #L310_POWER_CTRL] -+ -+ @ Don't setup the L2 cache if it is already enabled -+ ldr r0, [r1, #L2X0_CTRL] -+ tst r0, #L2X0_CTRL_EN -+ movne pc, lr -+ -+ str r3, [r1, #L310_TAG_LATENCY_CTRL] -+ str r4, [r1, #L310_DATA_LATENCY_CTRL] -+ str r6, [r1, #L310_ADDR_FILTER_END] -+ str r5, [r1, #L310_ADDR_FILTER_START] -+ -+ str r2, [r1, #L2X0_AUX_CTRL] -+ mov r9, #L2X0_CTRL_EN -+ str r9, [r1, #L2X0_CTRL] -+ mov pc, lr -+ENDPROC(l2c310_early_resume) -+ -+ .align -+1: .long l2x0_saved_regs - . -diff -Nur linux-3.15-rc6.orig/arch/arm/mm/Makefile linux-3.15-rc6/arch/arm/mm/Makefile ---- linux-3.15-rc6.orig/arch/arm/mm/Makefile 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/mm/Makefile 2014-05-23 11:26:48.284939966 +0200 -@@ -95,7 +95,8 @@ - AFLAGS_proc-v6.o :=-Wa,-march=armv6 - AFLAGS_proc-v7.o :=-Wa,-march=armv7-a - -+obj-$(CONFIG_OUTER_CACHE) += l2c-common.o - obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o --obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o -+obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o - obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o - obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o -diff -Nur linux-3.15-rc6.orig/arch/arm/plat-samsung/s5p-sleep.S linux-3.15-rc6/arch/arm/plat-samsung/s5p-sleep.S ---- linux-3.15-rc6.orig/arch/arm/plat-samsung/s5p-sleep.S 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/arch/arm/plat-samsung/s5p-sleep.S 2014-05-23 11:26:48.284939966 +0200 -@@ -22,7 +22,6 @@ - */ - - #include <linux/linkage.h> --#include <asm/asm-offsets.h> - - .data - .align -diff -Nur linux-3.15-rc6.orig/Documentation/devicetree/bindings/leds/leds-pwm.txt linux-3.15-rc6/Documentation/devicetree/bindings/leds/leds-pwm.txt ---- linux-3.15-rc6.orig/Documentation/devicetree/bindings/leds/leds-pwm.txt 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/Documentation/devicetree/bindings/leds/leds-pwm.txt 2014-05-23 11:26:48.284939966 +0200 -@@ -13,6 +13,8 @@ - For the pwms and pwm-names property please refer to: - Documentation/devicetree/bindings/pwm/pwm.txt - - max-brightness : Maximum brightness possible for the LED -+- active-low : (optional) For PWMs where the LED is wired to supply -+ rather than ground. - - label : (optional) - see Documentation/devicetree/bindings/leds/common.txt - - linux,default-trigger : (optional) -diff -Nur linux-3.15-rc6.orig/Documentation/devicetree/bindings/mmc/mmc.txt linux-3.15-rc6/Documentation/devicetree/bindings/mmc/mmc.txt ---- linux-3.15-rc6.orig/Documentation/devicetree/bindings/mmc/mmc.txt 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/Documentation/devicetree/bindings/mmc/mmc.txt 2014-05-23 11:26:48.284939966 +0200 -@@ -5,6 +5,8 @@ - Interpreted by the OF core: - - reg: Registers location and length. - - interrupts: Interrupts used by the MMC controller. -+- clocks: Clocks needed for the host controller, if any. -+- clock-names: Goes with clocks above. - - Card detection: - If no property below is supplied, host native card detect is used. -@@ -39,6 +41,15 @@ - - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported - - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported - -+Card power and reset control: -+The following properties can be specified for cases where the MMC -+peripheral needs additional reset, regulator and clock lines. It is for -+example common for WiFi/BT adapters to have these separate from the main -+MMC bus: -+ - card-reset-gpios: Specify GPIOs for card reset (reset active low) -+ - card-external-vcc-supply: Regulator to drive (independent) card VCC -+ - clock with name "card_ext_clock": External clock provided to the card -+ - *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line - polarity properties, we have to fix the meaning of the "normal" and "inverted" - line levels. We choose to follow the SDHCI standard, which specifies both those -diff -Nur linux-3.15-rc6.orig/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt linux-3.15-rc6/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt ---- linux-3.15-rc6.orig/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt 2014-05-23 11:26:48.288939979 +0200 -@@ -60,7 +60,8 @@ - - compatible: Should be "fsl,imx-parallel-display" - Optional properties: - - interface_pix_fmt: How this display is connected to the -- display interface. Currently supported types: "rgb24", "rgb565", "bgr666" -+ display interface. Currently supported types: "rgb24", "rgb565", "bgr666", -+ "rgb666" - - edid: verbatim EDID data block describing attached display. - - ddc: phandle describing the i2c bus handling the display data - channel -diff -Nur linux-3.15-rc6.orig/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml linux-3.15-rc6/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml ---- linux-3.15-rc6.orig/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml 2014-05-23 11:26:48.288939979 +0200 -@@ -279,6 +279,45 @@ - <entry></entry> - <entry></entry> - </row> -+ <row id="V4L2-PIX-FMT-RGB666"> -+ <entry><constant>V4L2_PIX_FMT_RGB666</constant></entry> -+ <entry>'RGBH'</entry> -+ <entry></entry> -+ <entry>r<subscript>5</subscript></entry> -+ <entry>r<subscript>4</subscript></entry> -+ <entry>r<subscript>3</subscript></entry> -+ <entry>r<subscript>2</subscript></entry> -+ <entry>r<subscript>1</subscript></entry> -+ <entry>r<subscript>0</subscript></entry> -+ <entry>g<subscript>5</subscript></entry> -+ <entry>g<subscript>4</subscript></entry> -+ <entry></entry> -+ <entry>g<subscript>3</subscript></entry> -+ <entry>g<subscript>2</subscript></entry> -+ <entry>g<subscript>1</subscript></entry> -+ <entry>g<subscript>0</subscript></entry> -+ <entry>b<subscript>5</subscript></entry> -+ <entry>b<subscript>4</subscript></entry> -+ <entry>b<subscript>3</subscript></entry> -+ <entry>b<subscript>2</subscript></entry> -+ <entry></entry> -+ <entry>b<subscript>1</subscript></entry> -+ <entry>b<subscript>0</subscript></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ <entry></entry> -+ </row> - <row id="V4L2-PIX-FMT-BGR24"> - <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry> - <entry>'BGR3'</entry> -diff -Nur linux-3.15-rc6.orig/drivers/ata/ahci_imx.c linux-3.15-rc6/drivers/ata/ahci_imx.c ---- linux-3.15-rc6.orig/drivers/ata/ahci_imx.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/ata/ahci_imx.c 2014-05-23 11:26:48.288939979 +0200 -@@ -62,6 +62,7 @@ - struct regmap *gpr; - bool no_device; - bool first_time; -+ u32 phy_params; - }; - - static int ahci_imx_hotplug; -@@ -246,14 +247,7 @@ - IMX6Q_GPR13_SATA_TX_LVL_MASK | - IMX6Q_GPR13_SATA_MPLL_CLK_EN | - IMX6Q_GPR13_SATA_TX_EDGE_RATE, -- IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | -- IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | -- IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | -- IMX6Q_GPR13_SATA_SPD_MODE_3P0G | -- IMX6Q_GPR13_SATA_MPLL_SS_EN | -- IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | -- IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | -- IMX6Q_GPR13_SATA_TX_LVL_1_025_V); -+ imxpriv->phy_params); - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_MPLL_CLK_EN, - IMX6Q_GPR13_SATA_MPLL_CLK_EN); -@@ -324,6 +318,10 @@ - writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); - imx_sata_disable(hpriv); - imxpriv->no_device = true; -+ -+ dev_info(ap->dev, "no device found, disabling link.\n"); -+ dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX -+ ".hotplug=1 to enable hotplug\n"); - } - - static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, -@@ -364,6 +362,165 @@ - }; - MODULE_DEVICE_TABLE(of, imx_ahci_of_match); - -+struct reg_value { -+ u32 of_value; -+ u32 reg_value; -+}; -+ -+struct reg_property { -+ const char *name; -+ const struct reg_value *values; -+ size_t num_values; -+ u32 def_value; -+ u32 set_value; -+}; -+ -+static const struct reg_value gpr13_tx_level[] = { -+ { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V }, -+ { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V }, -+ { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V }, -+ { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V }, -+ { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V }, -+ { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V }, -+ { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V }, -+ { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V }, -+ { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V }, -+ { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V }, -+ { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V }, -+ { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V }, -+ { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V }, -+ { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V }, -+ { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V }, -+ { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V }, -+ { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V }, -+ { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V }, -+ { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V }, -+ { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V }, -+ { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V }, -+ { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V }, -+ { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V }, -+ { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V }, -+ { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V }, -+ { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V }, -+ { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V }, -+ { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V }, -+ { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V }, -+ { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V }, -+ { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V }, -+ { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V } -+}; -+ -+static const struct reg_value gpr13_tx_boost[] = { -+ { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB }, -+ { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB }, -+ { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB }, -+ { 111, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, -+ { 148, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, -+ { 185, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, -+ { 222, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, -+ { 259, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, -+ { 296, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, -+ { 333, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, -+ { 370, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, -+ { 407, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, -+ { 444, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, -+ { 481, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, -+ { 528, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, -+ { 575, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB } -+}; -+ -+static const struct reg_value gpr13_tx_atten[] = { -+ { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 }, -+ { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 }, -+ { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 }, -+ { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 }, -+ { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 }, -+ { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 }, -+}; -+ -+static const struct reg_value gpr13_rx_eq[] = { -+ { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB }, -+ { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB }, -+ { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB }, -+ { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB }, -+ { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB }, -+ { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB }, -+ { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB }, -+ { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB }, -+}; -+ -+static const struct reg_property gpr13_props[] = { -+ { -+ .name = "fsl,transmit-level-mV", -+ .values = gpr13_tx_level, -+ .num_values = ARRAY_SIZE(gpr13_tx_level), -+ .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V, -+ }, { -+ .name = "fsl,transmit-boost-mdB", -+ .values = gpr13_tx_boost, -+ .num_values = ARRAY_SIZE(gpr13_tx_boost), -+ .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB, -+ }, { -+ .name = "fsl,transmit-atten-16ths", -+ .values = gpr13_tx_atten, -+ .num_values = ARRAY_SIZE(gpr13_tx_atten), -+ .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16, -+ }, { -+ .name = "fsl,receive-eq-mdB", -+ .values = gpr13_rx_eq, -+ .num_values = ARRAY_SIZE(gpr13_rx_eq), -+ .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB, -+ }, { -+ .name = "fsl,no-spread-spectrum", -+ .def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN, -+ .set_value = 0, -+ }, -+}; -+ -+static u32 imx_ahci_parse_props(struct device *dev, -+ const struct reg_property *prop, size_t num) -+{ -+ struct device_node *np = dev->of_node; -+ u32 reg_value = 0; -+ int i, j; -+ -+ for (i = 0; i < num; i++, prop++) { -+ u32 of_val; -+ -+ if (prop->num_values == 0) { -+ if (of_property_read_bool(np, prop->name)) -+ reg_value |= prop->set_value; -+ else -+ reg_value |= prop->def_value; -+ continue; -+ } -+ -+ if (of_property_read_u32(np, prop->name, &of_val)) { -+ dev_info(dev, "%s not specified, using %08x\n", -+ prop->name, prop->def_value); -+ reg_value |= prop->def_value; -+ continue; -+ } -+ -+ for (j = 0; j < prop->num_values; j++) { -+ if (prop->values[j].of_value == of_val) { -+ dev_info(dev, "%s value %u, using %08x\n", -+ prop->name, of_val, prop->values[j].reg_value); -+ reg_value |= prop->values[j].reg_value; -+ break; -+ } -+ } -+ -+ if (j == prop->num_values) { -+ dev_err(dev, "DT property %s is not a valid value\n", -+ prop->name); -+ reg_value |= prop->def_value; -+ } -+ } -+ -+ return reg_value; -+} -+ - static int imx_ahci_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -392,6 +549,8 @@ - } - - if (imxpriv->type == AHCI_IMX6Q) { -+ u32 reg_value; -+ - imxpriv->gpr = syscon_regmap_lookup_by_compatible( - "fsl,imx6q-iomuxc-gpr"); - if (IS_ERR(imxpriv->gpr)) { -@@ -399,6 +558,15 @@ - "failed to find fsl,imx6q-iomux-gpr regmap\n"); - return PTR_ERR(imxpriv->gpr); - } -+ -+ reg_value = imx_ahci_parse_props(dev, gpr13_props, -+ ARRAY_SIZE(gpr13_props)); -+ -+ imxpriv->phy_params = -+ IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | -+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | -+ IMX6Q_GPR13_SATA_SPD_MODE_3P0G | -+ reg_value; - } - - hpriv = ahci_platform_get_resources(pdev); -diff -Nur linux-3.15-rc6.orig/drivers/cec/cec-dev.c linux-3.15-rc6/drivers/cec/cec-dev.c ---- linux-3.15-rc6.orig/drivers/cec/cec-dev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/cec/cec-dev.c 2014-05-23 11:26:48.296940005 +0200 -@@ -0,0 +1,384 @@ -+/* -+ * HDMI Consumer Electronics Control -+ * -+ * This provides the user API for communication with HDMI CEC complaint -+ * devices in kernel drivers, and is based upon the protocol developed -+ * by Freescale for their i.MX SoCs. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/cec-dev.h> -+#include <linux/device.h> -+#include <linux/fs.h> -+#include <linux/module.h> -+#include <linux/poll.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+ -+struct cec_event { -+ struct cec_user_event usr; -+ struct list_head node; -+}; -+ -+static struct class *cec_class; -+static int cec_major; -+ -+static void cec_dev_send_message(struct cec_dev *cec_dev, u8 *msg, -+ size_t count) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&cec_dev->lock, flags); -+ cec_dev->retries = 5; -+ cec_dev->write_busy = 1; -+ cec_dev->send_message(cec_dev, msg, count); -+ spin_unlock_irqrestore(&cec_dev->lock, flags); -+} -+ -+void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len) -+{ -+ struct cec_event *event; -+ unsigned long flags; -+ -+ event = kzalloc(sizeof(*event), GFP_ATOMIC); -+ if (event) { -+ event->usr.event_type = type; -+ event->usr.msg_len = len; -+ if (msg) -+ memcpy(event->usr.msg, msg, len); -+ -+ spin_lock_irqsave(&cec_dev->lock, flags); -+ list_add_tail(&event->node, &cec_dev->events); -+ spin_unlock_irqrestore(&cec_dev->lock, flags); -+ wake_up(&cec_dev->waitq); -+ } -+} -+EXPORT_SYMBOL_GPL(cec_dev_event); -+ -+static int cec_dev_lock_write(struct cec_dev *cec_dev, struct file *file) -+ __acquires(cec_dev->mutex) -+{ -+ int ret; -+ -+ do { -+ if (file->f_flags & O_NONBLOCK) { -+ if (cec_dev->write_busy) -+ return -EAGAIN; -+ } else { -+ ret = wait_event_interruptible(cec_dev->waitq, -+ !cec_dev->write_busy); -+ if (ret) -+ break; -+ } -+ -+ ret = mutex_lock_interruptible(&cec_dev->mutex); -+ if (ret) -+ break; -+ -+ if (!cec_dev->write_busy) -+ break; -+ -+ mutex_unlock(&cec_dev->mutex); -+ } while (1); -+ -+ return ret; -+} -+ -+static ssize_t cec_dev_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct cec_dev *cec_dev = file->private_data; -+ ssize_t ret; -+ -+ if (count > sizeof(struct cec_user_event)) -+ count = sizeof(struct cec_user_event); -+ -+ if (!access_ok(VERIFY_WRITE, buf, count)) -+ return -EFAULT; -+ -+ do { -+ struct cec_event *event = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&cec_dev->lock, flags); -+ if (!list_empty(&cec_dev->events)) { -+ event = list_first_entry(&cec_dev->events, -+ struct cec_event, node); -+ list_del(&event->node); -+ } -+ spin_unlock_irqrestore(&cec_dev->lock, flags); -+ -+ if (event) { -+ ret = __copy_to_user(buf, &event->usr, count) ? -+ -EFAULT : count; -+ kfree(event); -+ break; -+ } -+ -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EAGAIN; -+ break; -+ } -+ -+ ret = wait_event_interruptible(cec_dev->waitq, -+ !list_empty(&cec_dev->events)); -+ if (ret) -+ break; -+ } while (1); -+ -+ return ret; -+} -+ -+static ssize_t cec_dev_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct cec_dev *cec_dev = file->private_data; -+ u8 msg[MAX_MESSAGE_LEN]; -+ int ret; -+ -+ if (count > sizeof(msg)) -+ return -E2BIG; -+ -+ if (copy_from_user(msg, buf, count)) -+ return -EFAULT; -+ -+ ret = cec_dev_lock_write(cec_dev, file); -+ if (ret) -+ return ret; -+ -+ cec_dev_send_message(cec_dev, msg, count); -+ -+ mutex_unlock(&cec_dev->mutex); -+ -+ return count; -+} -+ -+static long cec_dev_ioctl(struct file *file, u_int cmd, unsigned long arg) -+{ -+ struct cec_dev *cec_dev = file->private_data; -+ int ret; -+ -+ switch (cmd) { -+ case HDMICEC_IOC_O_SETLOGICALADDRESS: -+ case HDMICEC_IOC_SETLOGICALADDRESS: -+ if (arg > 15) { -+ ret = -EINVAL; -+ break; -+ } -+ -+ ret = cec_dev_lock_write(cec_dev, file); -+ if (ret == 0) { -+ unsigned char msg[1]; -+ -+ cec_dev->addresses = BIT(arg); -+ cec_dev->set_address(cec_dev, cec_dev->addresses); -+ -+ /* -+ * Send a ping message with the source and destination -+ * set to our address; the result indicates whether -+ * unit has chosen our address simultaneously. -+ */ -+ msg[0] = arg << 4 | arg; -+ cec_dev_send_message(cec_dev, msg, sizeof(msg)); -+ mutex_unlock(&cec_dev->mutex); -+ } -+ break; -+ -+ case HDMICEC_IOC_STARTDEVICE: -+ ret = mutex_lock_interruptible(&cec_dev->mutex); -+ if (ret == 0) { -+ cec_dev->addresses = BIT(15); -+ cec_dev->set_address(cec_dev, cec_dev->addresses); -+ mutex_unlock(&cec_dev->mutex); -+ } -+ break; -+ -+ case HDMICEC_IOC_STOPDEVICE: -+ ret = 0; -+ break; -+ -+ case HDMICEC_IOC_GETPHYADDRESS: -+ ret = put_user(cec_dev->physical, (u16 __user *)arg); -+ ret = -ENOIOCTLCMD; -+ break; -+ -+ default: -+ ret = -ENOIOCTLCMD; -+ break; -+ } -+ -+ return ret; -+} -+ -+static unsigned cec_dev_poll(struct file *file, poll_table *wait) -+{ -+ struct cec_dev *cec_dev = file->private_data; -+ unsigned mask = 0; -+ -+ poll_wait(file, &cec_dev->waitq, wait); -+ -+ if (cec_dev->write_busy == 0) -+ mask |= POLLOUT | POLLWRNORM; -+ if (!list_empty(&cec_dev->events)) -+ mask |= POLLIN | POLLRDNORM; -+ -+ return mask; -+} -+ -+static int cec_dev_release(struct inode *inode, struct file *file) -+{ -+ struct cec_dev *cec_dev = file->private_data; -+ -+ mutex_lock(&cec_dev->mutex); -+ if (cec_dev->users >= 1) -+ cec_dev->users -= 1; -+ if (cec_dev->users == 0) { -+ /* -+ * Wait for any write to complete before shutting down. -+ * A message should complete in a maximum of 2.75ms * -+ * 160 bits + 4.7ms, or 444.7ms. Let's call that 500ms. -+ * If we time out, shutdown anyway. -+ */ -+ wait_event_timeout(cec_dev->waitq, !cec_dev->write_busy, -+ msecs_to_jiffies(500)); -+ -+ cec_dev->release(cec_dev); -+ -+ while (!list_empty(&cec_dev->events)) { -+ struct cec_event *event; -+ -+ event = list_first_entry(&cec_dev->events, -+ struct cec_event, node); -+ list_del(&event->node); -+ kfree(event); -+ } -+ } -+ mutex_unlock(&cec_dev->mutex); -+ return 0; -+} -+ -+static int cec_dev_open(struct inode *inode, struct file *file) -+{ -+ struct cec_dev *cec_dev = container_of(inode->i_cdev, struct cec_dev, -+ cdev); -+ int ret = 0; -+ -+ nonseekable_open(inode, file); -+ -+ file->private_data = cec_dev; -+ -+ ret = mutex_lock_interruptible(&cec_dev->mutex); -+ if (ret) -+ return ret; -+ -+ if (cec_dev->users++ == 0) { -+ cec_dev->addresses = BIT(15); -+ -+ ret = cec_dev->open(cec_dev); -+ if (ret < 0) -+ cec_dev->users = 0; -+ } -+ mutex_unlock(&cec_dev->mutex); -+ -+ return ret; -+} -+ -+static const struct file_operations hdmi_cec_fops = { -+ .owner = THIS_MODULE, -+ .read = cec_dev_read, -+ .write = cec_dev_write, -+ .open = cec_dev_open, -+ .unlocked_ioctl = cec_dev_ioctl, -+ .release = cec_dev_release, -+ .poll = cec_dev_poll, -+}; -+ -+void cec_dev_init(struct cec_dev *cec_dev, struct module *module) -+{ -+ cec_dev->devn = MKDEV(cec_major, 0); -+ -+ INIT_LIST_HEAD(&cec_dev->events); -+ init_waitqueue_head(&cec_dev->waitq); -+ spin_lock_init(&cec_dev->lock); -+ mutex_init(&cec_dev->mutex); -+ -+ cec_dev->addresses = BIT(15); -+ -+ cdev_init(&cec_dev->cdev, &hdmi_cec_fops); -+ cec_dev->cdev.owner = module; -+} -+EXPORT_SYMBOL_GPL(cec_dev_init); -+ -+int cec_dev_add(struct cec_dev *cec_dev, struct device *dev, const char *name) -+{ -+ struct device *cd; -+ int ret; -+ -+ ret = cdev_add(&cec_dev->cdev, cec_dev->devn, 1); -+ if (ret < 0) -+ goto err_cdev; -+ -+ cd = device_create(cec_class, dev, cec_dev->devn, NULL, name); -+ if (IS_ERR(cd)) { -+ ret = PTR_ERR(cd); -+ dev_err(dev, "can't create device: %d\n", ret); -+ goto err_dev; -+ } -+ -+ return 0; -+ -+ err_dev: -+ cdev_del(&cec_dev->cdev); -+ err_cdev: -+ return ret; -+} -+EXPORT_SYMBOL_GPL(cec_dev_add); -+ -+void cec_dev_remove(struct cec_dev *cec_dev) -+{ -+ device_destroy(cec_class, cec_dev->devn); -+ cdev_del(&cec_dev->cdev); -+} -+EXPORT_SYMBOL_GPL(cec_dev_remove); -+ -+static int cec_init(void) -+{ -+ dev_t dev; -+ int ret; -+ -+ cec_class = class_create(THIS_MODULE, "hdmi-cec"); -+ if (IS_ERR(cec_class)) { -+ ret = PTR_ERR(cec_class); -+ pr_err("cec: can't create cec class: %d\n", ret); -+ goto err_class; -+ } -+ -+ ret = alloc_chrdev_region(&dev, 0, 1, "hdmi-cec"); -+ if (ret) { -+ pr_err("cec: can't create character devices: %d\n", ret); -+ goto err_chrdev; -+ } -+ -+ cec_major = MAJOR(dev); -+ -+ return 0; -+ -+ err_chrdev: -+ class_destroy(cec_class); -+ err_class: -+ return ret; -+} -+subsys_initcall(cec_init); -+ -+static void cec_exit(void) -+{ -+ unregister_chrdev_region(MKDEV(cec_major, 0), 1); -+ class_destroy(cec_class); -+} -+module_exit(cec_exit); -+ -+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); -+MODULE_DESCRIPTION("Generic HDMI CEC driver"); -+MODULE_LICENSE("GPL"); -diff -Nur linux-3.15-rc6.orig/drivers/cec/Kconfig linux-3.15-rc6/drivers/cec/Kconfig ---- linux-3.15-rc6.orig/drivers/cec/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/cec/Kconfig 2014-05-23 11:26:48.296940005 +0200 -@@ -0,0 +1,14 @@ -+# -+# Consumer Electroncs Control support -+# -+ -+menu "Consumer Electronics Control devices" -+ -+config CEC -+ bool -+ -+config HDMI_CEC_CORE -+ tristate -+ select CEC -+ -+endmenu -diff -Nur linux-3.15-rc6.orig/drivers/cec/Makefile linux-3.15-rc6/drivers/cec/Makefile ---- linux-3.15-rc6.orig/drivers/cec/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/cec/Makefile 2014-05-23 11:26:48.296940005 +0200 -@@ -0,0 +1 @@ -+obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o -diff -Nur linux-3.15-rc6.orig/drivers/gpu/drm/drm_crtc_helper.c linux-3.15-rc6/drivers/gpu/drm/drm_crtc_helper.c ---- linux-3.15-rc6.orig/drivers/gpu/drm/drm_crtc_helper.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/gpu/drm/drm_crtc_helper.c 2014-05-23 11:26:48.296940005 +0200 -@@ -140,16 +140,10 @@ - static void __drm_helper_disable_unused_functions(struct drm_device *dev) - { - struct drm_encoder *encoder; -- struct drm_connector *connector; - struct drm_crtc *crtc; - - drm_warn_on_modeset_not_all_locked(dev); - -- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -- if (!connector->encoder) -- continue; -- } -- - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (!drm_helper_encoder_in_use(encoder)) { - drm_encoder_disable(encoder); -diff -Nur linux-3.15-rc6.orig/drivers/Kconfig linux-3.15-rc6/drivers/Kconfig ---- linux-3.15-rc6.orig/drivers/Kconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/Kconfig 2014-05-23 11:26:48.296940005 +0200 -@@ -174,4 +174,6 @@ - - source "drivers/mcb/Kconfig" - -+source "drivers/cec/Kconfig" -+ - endmenu -diff -Nur linux-3.15-rc6.orig/drivers/leds/leds-pwm.c linux-3.15-rc6/drivers/leds/leds-pwm.c ---- linux-3.15-rc6.orig/drivers/leds/leds-pwm.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/leds/leds-pwm.c 2014-05-23 11:26:48.296940005 +0200 -@@ -69,6 +69,10 @@ - - duty *= brightness; - do_div(duty, max); -+ -+ if (led_dat->active_low) -+ duty = led_dat->period - duty; -+ - led_dat->duty = duty; - - if (led_dat->can_sleep) -@@ -92,55 +96,75 @@ - } - } - --static int led_pwm_create_of(struct platform_device *pdev, -- struct led_pwm_priv *priv) -+static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, -+ struct led_pwm *led, struct device_node *child) - { -- struct device_node *child; -+ struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; - int ret; - -- for_each_child_of_node(pdev->dev.of_node, child) { -- struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; -+ led_data->active_low = led->active_low; -+ led_data->period = led->pwm_period_ns; -+ led_data->cdev.name = led->name; -+ led_data->cdev.default_trigger = led->default_trigger; -+ led_data->cdev.brightness_set = led_pwm_set; -+ led_data->cdev.brightness = LED_OFF; -+ led_data->cdev.max_brightness = led->max_brightness; -+ led_data->cdev.flags = LED_CORE_SUSPENDRESUME; -+ -+ if (child) -+ led_data->pwm = devm_of_pwm_get(dev, child, NULL); -+ else -+ led_data->pwm = devm_pwm_get(dev, led->name); -+ if (IS_ERR(led_data->pwm)) { -+ ret = PTR_ERR(led_data->pwm); -+ dev_err(dev, "unable to request PWM for %s: %d\n", -+ led->name, ret); -+ return ret; -+ } - -- led_dat->cdev.name = of_get_property(child, "label", -- NULL) ? : child->name; -+ if (child) -+ led_data->period = pwm_get_period(led_data->pwm); - -- led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL); -- if (IS_ERR(led_dat->pwm)) { -- dev_err(&pdev->dev, "unable to request PWM for %s\n", -- led_dat->cdev.name); -- ret = PTR_ERR(led_dat->pwm); -- goto err; -- } -- /* Get the period from PWM core when n*/ -- led_dat->period = pwm_get_period(led_dat->pwm); -+ led_data->can_sleep = pwm_can_sleep(led_data->pwm); -+ if (led_data->can_sleep) -+ INIT_WORK(&led_data->work, led_pwm_work); - -- led_dat->cdev.default_trigger = of_get_property(child, -+ ret = led_classdev_register(dev, &led_data->cdev); -+ if (ret == 0) { -+ priv->num_leds++; -+ } else { -+ dev_err(dev, "failed to register PWM led for %s: %d\n", -+ led->name, ret); -+ } -+ -+ return ret; -+} -+ -+static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) -+{ -+ struct device_node *child; -+ struct led_pwm led; -+ int ret = 0; -+ -+ memset(&led, 0, sizeof(led)); -+ -+ for_each_child_of_node(dev->of_node, child) { -+ led.name = of_get_property(child, "label", NULL) ? : -+ child->name; -+ -+ led.default_trigger = of_get_property(child, - "linux,default-trigger", NULL); -+ led.active_low = of_property_read_bool(child, "active-low"); - of_property_read_u32(child, "max-brightness", -- &led_dat->cdev.max_brightness); -+ &led.max_brightness); - -- led_dat->cdev.brightness_set = led_pwm_set; -- led_dat->cdev.brightness = LED_OFF; -- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; -- -- led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); -- if (led_dat->can_sleep) -- INIT_WORK(&led_dat->work, led_pwm_work); -- -- ret = led_classdev_register(&pdev->dev, &led_dat->cdev); -- if (ret < 0) { -- dev_err(&pdev->dev, "failed to register for %s\n", -- led_dat->cdev.name); -+ ret = led_pwm_add(dev, priv, &led, child); -+ if (ret) { - of_node_put(child); -- goto err; -+ break; - } -- priv->num_leds++; - } - -- return 0; --err: -- led_pwm_cleanup(priv); -- - return ret; - } - -@@ -166,51 +190,23 @@ - - if (pdata) { - for (i = 0; i < count; i++) { -- struct led_pwm *cur_led = &pdata->leds[i]; -- struct led_pwm_data *led_dat = &priv->leds[i]; -- -- led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name); -- if (IS_ERR(led_dat->pwm)) { -- ret = PTR_ERR(led_dat->pwm); -- dev_err(&pdev->dev, -- "unable to request PWM for %s\n", -- cur_led->name); -- goto err; -- } -- -- led_dat->cdev.name = cur_led->name; -- led_dat->cdev.default_trigger = cur_led->default_trigger; -- led_dat->active_low = cur_led->active_low; -- led_dat->period = cur_led->pwm_period_ns; -- led_dat->cdev.brightness_set = led_pwm_set; -- led_dat->cdev.brightness = LED_OFF; -- led_dat->cdev.max_brightness = cur_led->max_brightness; -- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; -- -- led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); -- if (led_dat->can_sleep) -- INIT_WORK(&led_dat->work, led_pwm_work); -- -- ret = led_classdev_register(&pdev->dev, &led_dat->cdev); -- if (ret < 0) -- goto err; -+ ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i], -+ NULL); -+ if (ret) -+ break; - } -- priv->num_leds = count; - } else { -- ret = led_pwm_create_of(pdev, priv); -- if (ret) -- return ret; -+ ret = led_pwm_create_of(&pdev->dev, priv); -+ } -+ -+ if (ret) { -+ led_pwm_cleanup(priv); -+ return ret; - } - - platform_set_drvdata(pdev, priv); - - return 0; -- --err: -- priv->num_leds = i; -- led_pwm_cleanup(priv); -- -- return ret; - } - - static int led_pwm_remove(struct platform_device *pdev) -diff -Nur linux-3.15-rc6.orig/drivers/Makefile linux-3.15-rc6/drivers/Makefile ---- linux-3.15-rc6.orig/drivers/Makefile 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/Makefile 2014-05-23 11:26:48.296940005 +0200 -@@ -157,3 +157,4 @@ - obj-$(CONFIG_FMC) += fmc/ - obj-$(CONFIG_POWERCAP) += powercap/ - obj-$(CONFIG_MCB) += mcb/ -+obj-$(CONFIG_CEC) += cec/ -diff -Nur linux-3.15-rc6.orig/drivers/mmc/core/core.c linux-3.15-rc6/drivers/mmc/core/core.c ---- linux-3.15-rc6.orig/drivers/mmc/core/core.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/core/core.c 2014-05-23 11:26:48.300940018 +0200 -@@ -13,11 +13,13 @@ - #include <linux/module.h> - #include <linux/init.h> - #include <linux/interrupt.h> -+#include <linux/clk.h> - #include <linux/completion.h> - #include <linux/device.h> - #include <linux/delay.h> - #include <linux/pagemap.h> - #include <linux/err.h> -+#include <linux/gpio.h> - #include <linux/leds.h> - #include <linux/scatterlist.h> - #include <linux/log2.h> -@@ -1504,6 +1506,43 @@ - mmc_host_clk_release(host); - } - -+static void mmc_card_power_up(struct mmc_host *host) -+{ -+ int i; -+ struct gpio_desc **gds = host->card_reset_gpios; -+ -+ for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) { -+ if (gds[i]) { -+ dev_dbg(host->parent, "Asserting reset line %d", i); -+ gpiod_set_value(gds[i], 1); -+ } -+ } -+ -+ if (host->card_regulator) { -+ dev_dbg(host->parent, "Enabling external regulator"); -+ if (regulator_enable(host->card_regulator)) -+ dev_err(host->parent, "Failed to enable external regulator"); -+ } -+ -+ if (host->card_clk) { -+ dev_dbg(host->parent, "Enabling external clock"); -+ clk_prepare_enable(host->card_clk); -+ } -+ -+ /* 2ms delay to let clocks and power settle */ -+ mmc_delay(20); -+ -+ for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) { -+ if (gds[i]) { -+ dev_dbg(host->parent, "Deasserting reset line %d", i); -+ gpiod_set_value(gds[i], 0); -+ } -+ } -+ -+ /* 2ms delay to after reset release */ -+ mmc_delay(20); -+} -+ - /* - * Apply power to the MMC stack. This is a two-stage process. - * First, we enable power to the card without the clock running. -@@ -1520,6 +1559,9 @@ - if (host->ios.power_mode == MMC_POWER_ON) - return; - -+ /* Power up the card/module first, if needed */ -+ mmc_card_power_up(host); -+ - mmc_host_clk_hold(host); - - host->ios.vdd = fls(ocr) - 1; -diff -Nur linux-3.15-rc6.orig/drivers/mmc/core/host.c linux-3.15-rc6/drivers/mmc/core/host.c ---- linux-3.15-rc6.orig/drivers/mmc/core/host.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/core/host.c 2014-05-23 11:26:48.300940018 +0200 -@@ -12,14 +12,18 @@ - * MMC host class device management - */ - -+#include <linux/kernel.h> -+#include <linux/clk.h> - #include <linux/device.h> - #include <linux/err.h> -+#include <linux/gpio/consumer.h> - #include <linux/idr.h> - #include <linux/of.h> - #include <linux/of_gpio.h> - #include <linux/pagemap.h> - #include <linux/export.h> - #include <linux/leds.h> -+#include <linux/regulator/consumer.h> - #include <linux/slab.h> - #include <linux/suspend.h> - -@@ -457,6 +461,66 @@ - - EXPORT_SYMBOL(mmc_of_parse); - -+static int mmc_of_parse_child(struct mmc_host *host) -+{ -+ struct device_node *np; -+ struct clk *clk; -+ int i; -+ -+ if (!host->parent || !host->parent->of_node) -+ return 0; -+ -+ np = host->parent->of_node; -+ -+ host->card_regulator = regulator_get(host->parent, "card-external-vcc"); -+ if (IS_ERR(host->card_regulator)) { -+ if (PTR_ERR(host->card_regulator) == -EPROBE_DEFER) -+ return PTR_ERR(host->card_regulator); -+ host->card_regulator = NULL; -+ } -+ -+ /* Parse card power/reset/clock control */ -+ if (of_find_property(np, "card-reset-gpios", NULL)) { -+ struct gpio_desc *gpd; -+ int level = 0; -+ -+ /* -+ * If the regulator is enabled, then we can hold the -+ * card in reset with an active high resets. Otherwise, -+ * hold the resets low. -+ */ -+ if (host->card_regulator && regulator_is_enabled(host->card_regulator)) -+ level = 1; -+ -+ for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) { -+ gpd = devm_gpiod_get_index(host->parent, "card-reset", i); -+ if (IS_ERR(gpd)) { -+ if (PTR_ERR(gpd) == -EPROBE_DEFER) -+ return PTR_ERR(gpd); -+ break; -+ } -+ gpiod_direction_output(gpd, gpiod_is_active_low(gpd) | level); -+ host->card_reset_gpios[i] = gpd; -+ } -+ -+ gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios)); -+ if (!IS_ERR(gpd)) { -+ dev_warn(host->parent, "More reset gpios than we can handle"); -+ gpiod_put(gpd); -+ } -+ } -+ -+ clk = of_clk_get_by_name(np, "card_ext_clock"); -+ if (IS_ERR(clk)) { -+ if (PTR_ERR(clk) == -EPROBE_DEFER) -+ return PTR_ERR(clk); -+ clk = NULL; -+ } -+ host->card_clk = clk; -+ -+ return 0; -+} -+ - /** - * mmc_alloc_host - initialise the per-host structure. - * @extra: sizeof private data structure -@@ -536,6 +600,10 @@ - { - int err; - -+ err = mmc_of_parse_child(host); -+ if (err) -+ return err; -+ - WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && - !host->ops->enable_sdio_irq); - -diff -Nur linux-3.15-rc6.orig/drivers/mmc/core/sdio_irq.c linux-3.15-rc6/drivers/mmc/core/sdio_irq.c ---- linux-3.15-rc6.orig/drivers/mmc/core/sdio_irq.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/core/sdio_irq.c 2014-05-23 11:26:48.300940018 +0200 -@@ -90,6 +90,15 @@ - return ret; - } - -+void sdio_run_irqs(struct mmc_host *host) -+{ -+ mmc_claim_host(host); -+ host->sdio_irq_pending = true; -+ process_sdio_pending_irqs(host); -+ mmc_release_host(host); -+} -+EXPORT_SYMBOL_GPL(sdio_run_irqs); -+ - static int sdio_irq_thread(void *_host) - { - struct mmc_host *host = _host; -@@ -189,14 +198,20 @@ - WARN_ON(!host->claimed); - - if (!host->sdio_irqs++) { -- atomic_set(&host->sdio_irq_thread_abort, 0); -- host->sdio_irq_thread = -- kthread_run(sdio_irq_thread, host, "ksdioirqd/%s", -- mmc_hostname(host)); -- if (IS_ERR(host->sdio_irq_thread)) { -- int err = PTR_ERR(host->sdio_irq_thread); -- host->sdio_irqs--; -- return err; -+ if (!(host->caps2 & MMC_CAP2_SDIO_NOTHREAD)) { -+ atomic_set(&host->sdio_irq_thread_abort, 0); -+ host->sdio_irq_thread = -+ kthread_run(sdio_irq_thread, host, -+ "ksdioirqd/%s", mmc_hostname(host)); -+ if (IS_ERR(host->sdio_irq_thread)) { -+ int err = PTR_ERR(host->sdio_irq_thread); -+ host->sdio_irqs--; -+ return err; -+ } -+ } else { -+ mmc_host_clk_hold(host); -+ host->ops->enable_sdio_irq(host, 1); -+ mmc_host_clk_release(host); - } - } - -@@ -211,8 +226,14 @@ - BUG_ON(host->sdio_irqs < 1); - - if (!--host->sdio_irqs) { -- atomic_set(&host->sdio_irq_thread_abort, 1); -- kthread_stop(host->sdio_irq_thread); -+ if (!(host->caps2 & MMC_CAP2_SDIO_NOTHREAD)) { -+ atomic_set(&host->sdio_irq_thread_abort, 1); -+ kthread_stop(host->sdio_irq_thread); -+ } else { -+ mmc_host_clk_hold(host); -+ host->ops->enable_sdio_irq(host, 0); -+ mmc_host_clk_release(host); -+ } - } - - return 0; -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/dw_mmc.c linux-3.15-rc6/drivers/mmc/host/dw_mmc.c ---- linux-3.15-rc6.orig/drivers/mmc/host/dw_mmc.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/dw_mmc.c 2014-05-23 11:26:48.300940018 +0200 -@@ -2140,6 +2140,8 @@ - if (!mmc) - return -ENOMEM; - -+ mmc_of_parse(mmc); -+ - slot = mmc_priv(mmc); - slot->id = id; - slot->mmc = mmc; -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/Kconfig linux-3.15-rc6/drivers/mmc/host/Kconfig ---- linux-3.15-rc6.orig/drivers/mmc/host/Kconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/Kconfig 2014-05-23 11:26:48.300940018 +0200 -@@ -25,8 +25,7 @@ - If unsure, say N. - - config MMC_SDHCI -- tristate "Secure Digital Host Controller Interface support" -- depends on HAS_DMA -+ tristate - help - This selects the generic Secure Digital Host Controller Interface. - It is used by manufacturers such as Texas Instruments(R), Ricoh(R) -@@ -59,7 +58,8 @@ - - config MMC_SDHCI_PCI - tristate "SDHCI support on PCI bus" -- depends on MMC_SDHCI && PCI -+ depends on PCI && HAS_DMA -+ select MMC_SDHCI - help - This selects the PCI Secure Digital Host Controller Interface. - Most controllers found today are PCI devices. -@@ -83,7 +83,8 @@ - - config MMC_SDHCI_ACPI - tristate "SDHCI support for ACPI enumerated SDHCI controllers" -- depends on MMC_SDHCI && ACPI -+ depends on ACPI && HAS_DMA -+ select MMC_SDHCI - help - This selects support for ACPI enumerated SDHCI controllers, - identified by ACPI Compatibility ID PNP0D40 or specific -@@ -94,8 +95,8 @@ - If unsure, say N. - - config MMC_SDHCI_PLTFM -- tristate "SDHCI platform and OF driver helper" -- depends on MMC_SDHCI -+ tristate -+ select MMC_SDHCI - help - This selects the common helper functions support for Secure Digital - Host Controller Interface based platform and OF drivers. -@@ -106,8 +107,8 @@ - - config MMC_SDHCI_OF_ARASAN - tristate "SDHCI OF support for the Arasan SDHCI controllers" -- depends on MMC_SDHCI_PLTFM -- depends on OF -+ depends on OF && HAS_DMA -+ select MMC_SDHCI_PLTFM - help - This selects the Arasan Secure Digital Host Controller Interface - (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. -@@ -118,9 +119,9 @@ - - config MMC_SDHCI_OF_ESDHC - tristate "SDHCI OF support for the Freescale eSDHC controller" -- depends on MMC_SDHCI_PLTFM -- depends on PPC_OF -+ depends on PPC_OF && HAS_DMA - select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER -+ select MMC_SDHCI_PLTFM - help - This selects the Freescale eSDHC controller support. - -@@ -130,9 +131,9 @@ - - config MMC_SDHCI_OF_HLWD - tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" -- depends on MMC_SDHCI_PLTFM -- depends on PPC_OF -+ depends on PPC_OF && HAS_DMA - select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER -+ select MMC_SDHCI_PLTFM - help - This selects the Secure Digital Host Controller Interface (SDHCI) - found in the "Hollywood" chipset of the Nintendo Wii video game -@@ -144,8 +145,8 @@ - - config MMC_SDHCI_CNS3XXX - tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" -- depends on ARCH_CNS3XXX -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_CNS3XXX && HAS_DMA -+ select MMC_SDHCI_PLTFM - help - This selects the SDHCI support for CNS3xxx System-on-Chip devices. - -@@ -155,9 +156,9 @@ - - config MMC_SDHCI_ESDHC_IMX - tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" -- depends on ARCH_MXC -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_MXC && HAS_DMA - select MMC_SDHCI_IO_ACCESSORS -+ select MMC_SDHCI_PLTFM - help - This selects the Freescale eSDHC/uSDHC controller support - found on i.MX25, i.MX35 i.MX5x and i.MX6x. -@@ -168,9 +169,9 @@ - - config MMC_SDHCI_DOVE - tristate "SDHCI support on Marvell's Dove SoC" -- depends on ARCH_DOVE -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_DOVE && HAS_DMA - select MMC_SDHCI_IO_ACCESSORS -+ select MMC_SDHCI_PLTFM - help - This selects the Secure Digital Host Controller Interface in - Marvell's Dove SoC. -@@ -181,9 +182,9 @@ - - config MMC_SDHCI_TEGRA - tristate "SDHCI platform support for the Tegra SD/MMC Controller" -- depends on ARCH_TEGRA -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_TEGRA && HAS_DMA - select MMC_SDHCI_IO_ACCESSORS -+ select MMC_SDHCI_PLTFM - help - This selects the Tegra SD/MMC controller. If you have a Tegra - platform with SD or MMC devices, say Y or M here. -@@ -192,7 +193,8 @@ - - config MMC_SDHCI_S3C - tristate "SDHCI support on Samsung S3C SoC" -- depends on MMC_SDHCI && PLAT_SAMSUNG -+ depends on PLAT_SAMSUNG && HAS_DMA -+ select MMC_SDHCI - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the Samsung S3C -@@ -204,8 +206,8 @@ - - config MMC_SDHCI_SIRF - tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" -- depends on ARCH_SIRF -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_SIRF && HAS_DMA -+ select MMC_SDHCI_PLTFM - help - This selects the SDHCI support for SiRF System-on-Chip devices. - -@@ -215,8 +217,7 @@ - - config MMC_SDHCI_PXAV3 - tristate "Marvell MMP2 SD Host Controller support (PXAV3)" -- depends on CLKDEV_LOOKUP -- select MMC_SDHCI -+ depends on CLKDEV_LOOKUP && HAS_DMA - select MMC_SDHCI_PLTFM - default CPU_MMP2 - help -@@ -228,8 +229,7 @@ - - config MMC_SDHCI_PXAV2 - tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" -- depends on CLKDEV_LOOKUP -- select MMC_SDHCI -+ depends on CLKDEV_LOOKUP && HAS_DMA - select MMC_SDHCI_PLTFM - default CPU_PXA910 - help -@@ -241,7 +241,8 @@ - - config MMC_SDHCI_SPEAR - tristate "SDHCI support on ST SPEAr platform" -- depends on MMC_SDHCI && PLAT_SPEAR -+ depends on PLAT_SPEAR && HAS_DMA -+ select MMC_SDHCI - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the ST SPEAR range -@@ -263,7 +264,7 @@ - - config MMC_SDHCI_BCM_KONA - tristate "SDHCI support on Broadcom KONA platform" -- depends on ARCH_BCM_MOBILE -+ depends on ARCH_BCM_MOBILE && HAS_DMA - select MMC_SDHCI_PLTFM - help - This selects the Broadcom Kona Secure Digital Host Controller -@@ -274,9 +275,9 @@ - - config MMC_SDHCI_BCM2835 - tristate "SDHCI platform support for the BCM2835 SD/MMC Controller" -- depends on ARCH_BCM2835 -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_BCM2835 && HAS_DMA - select MMC_SDHCI_IO_ACCESSORS -+ select MMC_SDHCI_PLTFM - help - This selects the BCM2835 SD/MMC controller. If you have a BCM2835 - platform with SD or MMC devices, say Y or M here. -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-acpi.c linux-3.15-rc6/drivers/mmc/host/sdhci-acpi.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-acpi.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-acpi.c 2014-05-23 11:26:48.300940018 +0200 -@@ -102,11 +102,19 @@ - } - - static const struct sdhci_ops sdhci_acpi_ops_dflt = { -+ .set_clock = sdhci_set_clock, - .enable_dma = sdhci_acpi_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static const struct sdhci_ops sdhci_acpi_ops_int = { -+ .set_clock = sdhci_set_clock, - .enable_dma = sdhci_acpi_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - .hw_reset = sdhci_acpi_int_hw_reset, - }; - -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-bcm2835.c linux-3.15-rc6/drivers/mmc/host/sdhci-bcm2835.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-bcm2835.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-bcm2835.c 2014-05-23 11:26:48.300940018 +0200 -@@ -131,8 +131,12 @@ - .read_l = bcm2835_sdhci_readl, - .read_w = bcm2835_sdhci_readw, - .read_b = bcm2835_sdhci_readb, -+ .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .get_min_clock = bcm2835_sdhci_get_min_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-bcm-kona.c linux-3.15-rc6/drivers/mmc/host/sdhci-bcm-kona.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-bcm-kona.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-bcm-kona.c 2014-05-23 11:26:48.300940018 +0200 -@@ -206,9 +206,13 @@ - } - - static struct sdhci_ops sdhci_bcm_kona_ops = { -+ .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_bcm_kona_get_max_clk, - .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, - .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - .card_event = sdhci_bcm_kona_card_event, - }; - -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci.c linux-3.15-rc6/drivers/mmc/host/sdhci.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci.c 2014-05-23 11:26:48.304940032 +0200 -@@ -44,6 +44,8 @@ - - #define MAX_TUNING_LOOP 40 - -+#define ADMA_SIZE ((128 * 2 + 1) * 4) -+ - static unsigned int debug_quirks = 0; - static unsigned int debug_quirks2; - -@@ -131,43 +133,26 @@ - * * - \*****************************************************************************/ - --static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set) --{ -- u32 ier; -- -- ier = sdhci_readl(host, SDHCI_INT_ENABLE); -- ier &= ~clear; -- ier |= set; -- sdhci_writel(host, ier, SDHCI_INT_ENABLE); -- sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); --} -- --static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs) --{ -- sdhci_clear_set_irqs(host, 0, irqs); --} -- --static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs) --{ -- sdhci_clear_set_irqs(host, irqs, 0); --} -- - static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) - { -- u32 present, irqs; -+ u32 present; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - (host->mmc->caps & MMC_CAP_NONREMOVABLE)) - return; - -- present = sdhci_readl(host, SDHCI_PRESENT_STATE) & -- SDHCI_CARD_PRESENT; -- irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; -+ if (enable) { -+ present = sdhci_readl(host, SDHCI_PRESENT_STATE) & -+ SDHCI_CARD_PRESENT; - -- if (enable) -- sdhci_unmask_irqs(host, irqs); -- else -- sdhci_mask_irqs(host, irqs); -+ host->ier |= present ? SDHCI_INT_CARD_REMOVE : -+ SDHCI_INT_CARD_INSERT; -+ } else { -+ host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); -+ } -+ -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - } - - static void sdhci_enable_card_detection(struct sdhci_host *host) -@@ -180,22 +165,9 @@ - sdhci_set_card_detection(host, false); - } - --static void sdhci_reset(struct sdhci_host *host, u8 mask) -+void sdhci_reset(struct sdhci_host *host, u8 mask) - { - unsigned long timeout; -- u32 uninitialized_var(ier); -- -- if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { -- if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & -- SDHCI_CARD_PRESENT)) -- return; -- } -- -- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) -- ier = sdhci_readl(host, SDHCI_INT_ENABLE); -- -- if (host->ops->platform_reset_enter) -- host->ops->platform_reset_enter(host, mask); - - sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); - -@@ -220,16 +192,27 @@ - timeout--; - mdelay(1); - } -+} -+EXPORT_SYMBOL_GPL(sdhci_reset); -+ -+static void sdhci_do_reset(struct sdhci_host *host, u8 mask) -+{ -+ if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { -+ if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & -+ SDHCI_CARD_PRESENT)) -+ return; -+ } - -- if (host->ops->platform_reset_exit) -- host->ops->platform_reset_exit(host, mask); -+ host->ops->reset(host, mask); - -- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) -- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); -+ if (mask & SDHCI_RESET_ALL) { -+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { -+ if (host->ops->enable_dma) -+ host->ops->enable_dma(host); -+ } - -- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { -- if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL)) -- host->ops->enable_dma(host); -+ /* Resetting the controller clears many */ -+ host->preset_enabled = false; - } - } - -@@ -238,15 +221,18 @@ - static void sdhci_init(struct sdhci_host *host, int soft) - { - if (soft) -- sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); -+ sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); - else -- sdhci_reset(host, SDHCI_RESET_ALL); -+ sdhci_do_reset(host, SDHCI_RESET_ALL); -+ -+ host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | -+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | -+ SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | -+ SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | -+ SDHCI_INT_RESPONSE; - -- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, -- SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | -- SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | -- SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | -- SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - - if (soft) { - /* force clock reconfiguration */ -@@ -502,11 +488,6 @@ - else - direction = DMA_TO_DEVICE; - -- /* -- * The ADMA descriptor table is mapped further down as we -- * need to fill it with data first. -- */ -- - host->align_addr = dma_map_single(mmc_dev(host->mmc), - host->align_buffer, 128 * 4, direction); - if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) -@@ -567,7 +548,7 @@ - * If this triggers then we have a calculation bug - * somewhere. :/ - */ -- WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4); -+ WARN_ON((desc - host->adma_desc) > ADMA_SIZE); - } - - if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { -@@ -595,17 +576,8 @@ - host->align_addr, 128 * 4, direction); - } - -- host->adma_addr = dma_map_single(mmc_dev(host->mmc), -- host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); -- if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr)) -- goto unmap_entries; -- BUG_ON(host->adma_addr & 0x3); -- - return 0; - --unmap_entries: -- dma_unmap_sg(mmc_dev(host->mmc), data->sg, -- data->sg_len, direction); - unmap_align: - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); -@@ -623,19 +595,25 @@ - u8 *align; - char *buffer; - unsigned long flags; -+ bool has_unaligned; - - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - -- dma_unmap_single(mmc_dev(host->mmc), host->adma_addr, -- (128 * 2 + 1) * 4, DMA_TO_DEVICE); -- - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); - -- if (data->flags & MMC_DATA_READ) { -+ /* Do a quick scan of the SG list for any unaligned mappings */ -+ has_unaligned = false; -+ for_each_sg(data->sg, sg, host->sg_count, i) -+ if (sg_dma_address(sg) & 3) { -+ has_unaligned = true; -+ break; -+ } -+ -+ if (has_unaligned && data->flags & MMC_DATA_READ) { - dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); - -@@ -721,9 +699,12 @@ - u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR; - - if (host->flags & SDHCI_REQ_USE_DMA) -- sdhci_clear_set_irqs(host, pio_irqs, dma_irqs); -+ host->ier = (host->ier & ~pio_irqs) | dma_irqs; - else -- sdhci_clear_set_irqs(host, dma_irqs, pio_irqs); -+ host->ier = (host->ier & ~dma_irqs) | pio_irqs; -+ -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - } - - static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) -@@ -976,8 +957,8 @@ - * upon error conditions. - */ - if (data->error) { -- sdhci_reset(host, SDHCI_RESET_CMD); -- sdhci_reset(host, SDHCI_RESET_DATA); -+ sdhci_do_reset(host, SDHCI_RESET_CMD); -+ sdhci_do_reset(host, SDHCI_RESET_DATA); - } - - sdhci_send_command(host, data->stop); -@@ -1107,24 +1088,23 @@ - - static u16 sdhci_get_preset_value(struct sdhci_host *host) - { -- u16 ctrl, preset = 0; -+ u16 preset = 0; - -- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -- -- switch (ctrl & SDHCI_CTRL_UHS_MASK) { -- case SDHCI_CTRL_UHS_SDR12: -+ switch (host->timing) { -+ case MMC_TIMING_UHS_SDR12: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12); - break; -- case SDHCI_CTRL_UHS_SDR25: -+ case MMC_TIMING_UHS_SDR25: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25); - break; -- case SDHCI_CTRL_UHS_SDR50: -+ case MMC_TIMING_UHS_SDR50: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50); - break; -- case SDHCI_CTRL_UHS_SDR104: -+ case MMC_TIMING_UHS_SDR104: -+ case MMC_TIMING_MMC_HS200: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104); - break; -- case SDHCI_CTRL_UHS_DDR50: -+ case MMC_TIMING_UHS_DDR50: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); - break; - default: -@@ -1136,32 +1116,22 @@ - return preset; - } - --static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) -+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) - { - int div = 0; /* Initialized for compiler warning */ - int real_div = div, clk_mul = 1; - u16 clk = 0; - unsigned long timeout; - -- if (clock && clock == host->clock) -- return; -- - host->mmc->actual_clock = 0; - -- if (host->ops->set_clock) { -- host->ops->set_clock(host, clock); -- if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) -- return; -- } -- - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) -- goto out; -+ return; - - if (host->version >= SDHCI_SPEC_300) { -- if (sdhci_readw(host, SDHCI_HOST_CONTROL2) & -- SDHCI_CTRL_PRESET_VAL_ENABLE) { -+ if (host->preset_enabled) { - u16 pre_val; - - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); -@@ -1247,26 +1217,16 @@ - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -- --out: -- host->clock = clock; --} -- --static inline void sdhci_update_clock(struct sdhci_host *host) --{ -- unsigned int clock; -- -- clock = host->clock; -- host->clock = 0; -- sdhci_set_clock(host, clock); - } -+EXPORT_SYMBOL_GPL(sdhci_set_clock); - --static int sdhci_set_power(struct sdhci_host *host, unsigned short power) -+static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, -+ unsigned short vdd) - { - u8 pwr = 0; - -- if (power != (unsigned short)-1) { -- switch (1 << power) { -+ if (mode != MMC_POWER_OFF) { -+ switch (1 << vdd) { - case MMC_VDD_165_195: - pwr = SDHCI_POWER_180; - break; -@@ -1284,7 +1244,7 @@ - } - - if (host->pwr == pwr) -- return -1; -+ return; - - host->pwr = pwr; - -@@ -1292,38 +1252,43 @@ - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) - sdhci_runtime_pm_bus_off(host); -- return 0; -- } -- -- /* -- * Spec says that we should clear the power reg before setting -- * a new value. Some controllers don't seem to like this though. -- */ -- if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) -- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); -+ vdd = 0; -+ } else { -+ /* -+ * Spec says that we should clear the power reg before setting -+ * a new value. Some controllers don't seem to like this though. -+ */ -+ if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) -+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - -- /* -- * At least the Marvell CaFe chip gets confused if we set the voltage -- * and set turn on power at the same time, so set the voltage first. -- */ -- if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) -- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); -+ /* -+ * At least the Marvell CaFe chip gets confused if we set the -+ * voltage and set turn on power at the same time, so set the -+ * voltage first. -+ */ -+ if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) -+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - -- pwr |= SDHCI_POWER_ON; -+ pwr |= SDHCI_POWER_ON; - -- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); -+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - -- if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) -- sdhci_runtime_pm_bus_on(host); -+ if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) -+ sdhci_runtime_pm_bus_on(host); - -- /* -- * Some controllers need an extra 10ms delay of 10ms before they -- * can apply clock after applying power -- */ -- if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) -- mdelay(10); -+ /* -+ * Some controllers need an extra 10ms delay of 10ms before -+ * they can apply clock after applying power -+ */ -+ if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) -+ mdelay(10); -+ } - -- return power; -+ if (host->vmmc) { -+ spin_unlock_irq(&host->lock); -+ mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd); -+ spin_lock_irq(&host->lock); -+ } - } - - /*****************************************************************************\ -@@ -1427,10 +1392,52 @@ - spin_unlock_irqrestore(&host->lock, flags); - } - -+void sdhci_set_bus_width(struct sdhci_host *host, int width) -+{ -+ u8 ctrl; -+ -+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); -+ if (width == MMC_BUS_WIDTH_8) { -+ ctrl &= ~SDHCI_CTRL_4BITBUS; -+ if (host->version >= SDHCI_SPEC_300) -+ ctrl |= SDHCI_CTRL_8BITBUS; -+ } else { -+ if (host->version >= SDHCI_SPEC_300) -+ ctrl &= ~SDHCI_CTRL_8BITBUS; -+ if (width == MMC_BUS_WIDTH_4) -+ ctrl |= SDHCI_CTRL_4BITBUS; -+ else -+ ctrl &= ~SDHCI_CTRL_4BITBUS; -+ } -+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -+} -+EXPORT_SYMBOL_GPL(sdhci_set_bus_width); -+ -+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) -+{ -+ u16 ctrl_2; -+ -+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ /* Select Bus Speed Mode for host */ -+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; -+ if ((timing == MMC_TIMING_MMC_HS200) || -+ (timing == MMC_TIMING_UHS_SDR104)) -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104; -+ else if (timing == MMC_TIMING_UHS_SDR12) -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12; -+ else if (timing == MMC_TIMING_UHS_SDR25) -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25; -+ else if (timing == MMC_TIMING_UHS_SDR50) -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50; -+ else if (timing == MMC_TIMING_UHS_DDR50) -+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50; -+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); -+} -+EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); -+ - static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) - { - unsigned long flags; -- int vdd_bit = -1; - u8 ctrl; - - spin_lock_irqsave(&host->lock, flags); -@@ -1456,45 +1463,17 @@ - !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) - sdhci_enable_preset_value(host, false); - -- sdhci_set_clock(host, ios->clock); -- -- if (ios->power_mode == MMC_POWER_OFF) -- vdd_bit = sdhci_set_power(host, -1); -- else -- vdd_bit = sdhci_set_power(host, ios->vdd); -- -- if (host->vmmc && vdd_bit != -1) { -- spin_unlock_irqrestore(&host->lock, flags); -- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); -- spin_lock_irqsave(&host->lock, flags); -+ if (!ios->clock || ios->clock != host->clock) { -+ host->ops->set_clock(host, ios->clock); -+ host->clock = ios->clock; - } - -+ sdhci_set_power(host, ios->power_mode, ios->vdd); -+ - if (host->ops->platform_send_init_74_clocks) - host->ops->platform_send_init_74_clocks(host, ios->power_mode); - -- /* -- * If your platform has 8-bit width support but is not a v3 controller, -- * or if it requires special setup code, you should implement that in -- * platform_bus_width(). -- */ -- if (host->ops->platform_bus_width) { -- host->ops->platform_bus_width(host, ios->bus_width); -- } else { -- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); -- if (ios->bus_width == MMC_BUS_WIDTH_8) { -- ctrl &= ~SDHCI_CTRL_4BITBUS; -- if (host->version >= SDHCI_SPEC_300) -- ctrl |= SDHCI_CTRL_8BITBUS; -- } else { -- if (host->version >= SDHCI_SPEC_300) -- ctrl &= ~SDHCI_CTRL_8BITBUS; -- if (ios->bus_width == MMC_BUS_WIDTH_4) -- ctrl |= SDHCI_CTRL_4BITBUS; -- else -- ctrl &= ~SDHCI_CTRL_4BITBUS; -- } -- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -- } -+ host->ops->set_bus_width(host, ios->bus_width); - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - -@@ -1516,13 +1495,13 @@ - (ios->timing == MMC_TIMING_UHS_SDR25)) - ctrl |= SDHCI_CTRL_HISPD; - -- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -- if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) { -+ if (!host->preset_enabled) { - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - /* - * We only need to set Driver Strength if the - * preset value enable is not set. - */ -+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK; - if (ios->drv_type == MMC_SET_DRIVER_TYPE_A) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A; -@@ -1546,34 +1525,11 @@ - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - /* Re-enable SD Clock */ -- sdhci_update_clock(host); -+ host->ops->set_clock(host, host->clock); - } - -- -- /* Reset SD Clock Enable */ -- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); -- clk &= ~SDHCI_CLOCK_CARD_EN; -- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -- -- if (host->ops->set_uhs_signaling) -- host->ops->set_uhs_signaling(host, ios->timing); -- else { -- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -- /* Select Bus Speed Mode for host */ -- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; -- if ((ios->timing == MMC_TIMING_MMC_HS200) || -- (ios->timing == MMC_TIMING_UHS_SDR104)) -- ctrl_2 |= SDHCI_CTRL_UHS_SDR104; -- else if (ios->timing == MMC_TIMING_UHS_SDR12) -- ctrl_2 |= SDHCI_CTRL_UHS_SDR12; -- else if (ios->timing == MMC_TIMING_UHS_SDR25) -- ctrl_2 |= SDHCI_CTRL_UHS_SDR25; -- else if (ios->timing == MMC_TIMING_UHS_SDR50) -- ctrl_2 |= SDHCI_CTRL_UHS_SDR50; -- else if (ios->timing == MMC_TIMING_UHS_DDR50) -- ctrl_2 |= SDHCI_CTRL_UHS_DDR50; -- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); -- } -+ host->ops->set_uhs_signaling(host, ios->timing); -+ host->timing = ios->timing; - - if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) && - ((ios->timing == MMC_TIMING_UHS_SDR12) || -@@ -1588,9 +1544,6 @@ - ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK) - >> SDHCI_PRESET_DRV_SHIFT; - } -- -- /* Re-enable SD Clock */ -- sdhci_update_clock(host); - } else - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - -@@ -1600,7 +1553,7 @@ - * it on each ios seems to solve the problem. - */ - if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) -- sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); -+ sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); -@@ -1709,24 +1662,16 @@ - - static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) - { -- if (host->flags & SDHCI_DEVICE_DEAD) -- goto out; -- -- if (enable) -- host->flags |= SDHCI_SDIO_IRQ_ENABLED; -- else -- host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; -- -- /* SDIO IRQ will be enabled as appropriate in runtime resume */ -- if (host->runtime_suspended) -- goto out; -+ if (!(host->flags & SDHCI_DEVICE_DEAD)) { -+ if (enable) -+ host->ier |= SDHCI_INT_CARD_INT; -+ else -+ host->ier &= ~SDHCI_INT_CARD_INT; - -- if (enable) -- sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); -- else -- sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); --out: -- mmiowb(); -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -+ mmiowb(); -+ } - } - - static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) -@@ -1734,9 +1679,18 @@ - struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - -+ sdhci_runtime_pm_get(host); -+ - spin_lock_irqsave(&host->lock, flags); -+ if (enable) -+ host->flags |= SDHCI_SDIO_IRQ_ENABLED; -+ else -+ host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; -+ - sdhci_enable_sdio_irq_nolock(host, enable); - spin_unlock_irqrestore(&host->lock, flags); -+ -+ sdhci_runtime_pm_put(host); - } - - static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, -@@ -1798,9 +1752,6 @@ - ctrl |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - -- /* Wait for 5ms */ -- usleep_range(5000, 5500); -- - /* 1.8V regulator output should be stable within 5 ms */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ctrl & SDHCI_CTRL_VDD_180) -@@ -1855,22 +1806,16 @@ - - static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) - { -- struct sdhci_host *host; -+ struct sdhci_host *host = mmc_priv(mmc); - u16 ctrl; -- u32 ier; - int tuning_loop_counter = MAX_TUNING_LOOP; - unsigned long timeout; - int err = 0; -- bool requires_tuning_nonuhs = false; - unsigned long flags; - -- host = mmc_priv(mmc); -- - sdhci_runtime_pm_get(host); - spin_lock_irqsave(&host->lock, flags); - -- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -- - /* - * The Host Controller needs tuning only in case of SDR104 mode - * and for SDR50 mode when Use Tuning for SDR50 is set in the -@@ -1878,15 +1823,18 @@ - * If the Host Controller supports the HS200 mode then the - * tuning function has to be executed. - */ -- if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && -- (host->flags & SDHCI_SDR50_NEEDS_TUNING || -- host->flags & SDHCI_SDR104_NEEDS_TUNING)) -- requires_tuning_nonuhs = true; -- -- if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || -- requires_tuning_nonuhs) -- ctrl |= SDHCI_CTRL_EXEC_TUNING; -- else { -+ switch (host->timing) { -+ case MMC_TIMING_MMC_HS200: -+ case MMC_TIMING_UHS_SDR104: -+ break; -+ -+ case MMC_TIMING_UHS_SDR50: -+ if (host->flags & SDHCI_SDR50_NEEDS_TUNING || -+ host->flags & SDHCI_SDR104_NEEDS_TUNING) -+ break; -+ /* FALLTHROUGH */ -+ -+ default: - spin_unlock_irqrestore(&host->lock, flags); - sdhci_runtime_pm_put(host); - return 0; -@@ -1899,6 +1847,8 @@ - return err; - } - -+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ ctrl |= SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - /* -@@ -1911,8 +1861,8 @@ - * to make sure we don't hit a controller bug, we _only_ - * enable Buffer Read Ready interrupt here. - */ -- ier = sdhci_readl(host, SDHCI_INT_ENABLE); -- sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL); -+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); -+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); - - /* - * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number -@@ -2044,7 +1994,8 @@ - if (err && (host->flags & SDHCI_USING_RETUNING_TIMER)) - err = 0; - -- sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - spin_unlock_irqrestore(&host->lock, flags); - sdhci_runtime_pm_put(host); - -@@ -2054,26 +2005,30 @@ - - static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) - { -- u16 ctrl; -- - /* Host Controller v3.00 defines preset value registers */ - if (host->version < SDHCI_SPEC_300) - return; - -- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -- - /* - * We only enable or disable Preset Value if they are not already - * enabled or disabled respectively. Otherwise, we bail out. - */ -- if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { -- ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; -- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); -- host->flags |= SDHCI_PV_ENABLED; -- } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { -- ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; -+ if (host->preset_enabled != enable) { -+ u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ -+ if (enable) -+ ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; -+ else -+ ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; -+ - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); -- host->flags &= ~SDHCI_PV_ENABLED; -+ -+ if (enable) -+ host->flags |= SDHCI_PV_ENABLED; -+ else -+ host->flags &= ~SDHCI_PV_ENABLED; -+ -+ host->preset_enabled = enable; - } - } - -@@ -2095,8 +2050,8 @@ - pr_err("%s: Resetting controller.\n", - mmc_hostname(host->mmc)); - -- sdhci_reset(host, SDHCI_RESET_CMD); -- sdhci_reset(host, SDHCI_RESET_DATA); -+ sdhci_do_reset(host, SDHCI_RESET_CMD); -+ sdhci_do_reset(host, SDHCI_RESET_DATA); - - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); -@@ -2124,15 +2079,6 @@ - * * - \*****************************************************************************/ - --static void sdhci_tasklet_card(unsigned long param) --{ -- struct sdhci_host *host = (struct sdhci_host*)param; -- -- sdhci_card_event(host->mmc); -- -- mmc_detect_change(host->mmc, msecs_to_jiffies(200)); --} -- - static void sdhci_tasklet_finish(unsigned long param) - { - struct sdhci_host *host; -@@ -2169,12 +2115,12 @@ - /* Some controllers need this kick or reset won't work here */ - if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) - /* This is to force an update */ -- sdhci_update_clock(host); -+ host->ops->set_clock(host, host->clock); - - /* Spec says we should do both at the same time, but Ricoh - controllers do not like that. */ -- sdhci_reset(host, SDHCI_RESET_CMD); -- sdhci_reset(host, SDHCI_RESET_DATA); -+ sdhci_do_reset(host, SDHCI_RESET_CMD); -+ sdhci_do_reset(host, SDHCI_RESET_DATA); - } - - host->mrq = NULL; -@@ -2424,101 +2370,94 @@ - - static irqreturn_t sdhci_irq(int irq, void *dev_id) - { -- irqreturn_t result; -+ irqreturn_t result = IRQ_NONE; - struct sdhci_host *host = dev_id; -- u32 intmask, unexpected = 0; -- int cardint = 0, max_loops = 16; -+ u32 intmask, mask, unexpected = 0; -+ int max_loops = 16; - - spin_lock(&host->lock); - -- if (host->runtime_suspended) { -+ if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) { - spin_unlock(&host->lock); - return IRQ_NONE; - } - - intmask = sdhci_readl(host, SDHCI_INT_STATUS); -- - if (!intmask || intmask == 0xffffffff) { - result = IRQ_NONE; - goto out; - } - --again: -- DBG("*** %s got interrupt: 0x%08x\n", -- mmc_hostname(host->mmc), intmask); -- -- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { -- u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & -- SDHCI_CARD_PRESENT; -- -- /* -- * There is a observation on i.mx esdhc. INSERT bit will be -- * immediately set again when it gets cleared, if a card is -- * inserted. We have to mask the irq to prevent interrupt -- * storm which will freeze the system. And the REMOVE gets -- * the same situation. -- * -- * More testing are needed here to ensure it works for other -- * platforms though. -- */ -- sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT : -- SDHCI_INT_CARD_REMOVE); -- sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE : -- SDHCI_INT_CARD_INSERT); -- -- sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | -- SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); -- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); -- tasklet_schedule(&host->card_tasklet); -- } -- -- if (intmask & SDHCI_INT_CMD_MASK) { -- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, -- SDHCI_INT_STATUS); -- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); -- } -+ do { -+ /* Clear selected interrupts. */ -+ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | -+ SDHCI_INT_BUS_POWER); -+ sdhci_writel(host, mask, SDHCI_INT_STATUS); -+ -+ DBG("*** %s got interrupt: 0x%08x\n", -+ mmc_hostname(host->mmc), intmask); -+ -+ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { -+ u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & -+ SDHCI_CARD_PRESENT; - -- if (intmask & SDHCI_INT_DATA_MASK) { -- sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK, -- SDHCI_INT_STATUS); -- sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); -- } -+ /* -+ * There is a observation on i.mx esdhc. INSERT -+ * bit will be immediately set again when it gets -+ * cleared, if a card is inserted. We have to mask -+ * the irq to prevent interrupt storm which will -+ * freeze the system. And the REMOVE gets the -+ * same situation. -+ * -+ * More testing are needed here to ensure it works -+ * for other platforms though. -+ */ -+ host->ier &= ~(SDHCI_INT_CARD_INSERT | -+ SDHCI_INT_CARD_REMOVE); -+ host->ier |= present ? SDHCI_INT_CARD_REMOVE : -+ SDHCI_INT_CARD_INSERT; -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - -- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); -+ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | -+ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); - -- intmask &= ~SDHCI_INT_ERROR; -+ host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT | -+ SDHCI_INT_CARD_REMOVE); -+ result = IRQ_WAKE_THREAD; -+ } - -- if (intmask & SDHCI_INT_BUS_POWER) { -- pr_err("%s: Card is consuming too much power!\n", -- mmc_hostname(host->mmc)); -- sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); -- } -+ if (intmask & SDHCI_INT_CMD_MASK) -+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); - -- intmask &= ~SDHCI_INT_BUS_POWER; -+ if (intmask & SDHCI_INT_DATA_MASK) -+ sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); - -- if (intmask & SDHCI_INT_CARD_INT) -- cardint = 1; -+ if (intmask & SDHCI_INT_BUS_POWER) -+ pr_err("%s: Card is consuming too much power!\n", -+ mmc_hostname(host->mmc)); - -- intmask &= ~SDHCI_INT_CARD_INT; -+ if (intmask & SDHCI_INT_CARD_INT) { -+ sdhci_enable_sdio_irq_nolock(host, false); -+ host->thread_isr |= SDHCI_INT_CARD_INT; -+ result = IRQ_WAKE_THREAD; -+ } - -- if (intmask) { -- unexpected |= intmask; -- sdhci_writel(host, intmask, SDHCI_INT_STATUS); -- } -+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | -+ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | -+ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | -+ SDHCI_INT_CARD_INT); - -- result = IRQ_HANDLED; -+ if (intmask) { -+ unexpected |= intmask; -+ sdhci_writel(host, intmask, SDHCI_INT_STATUS); -+ } - -- intmask = sdhci_readl(host, SDHCI_INT_STATUS); -+ if (result == IRQ_NONE) -+ result = IRQ_HANDLED; - -- /* -- * If we know we'll call the driver to signal SDIO IRQ, disregard -- * further indications of Card Interrupt in the status to avoid a -- * needless loop. -- */ -- if (cardint) -- intmask &= ~SDHCI_INT_CARD_INT; -- if (intmask && --max_loops) -- goto again; -+ intmask = sdhci_readl(host, SDHCI_INT_STATUS); -+ } while (intmask && --max_loops); - out: - spin_unlock(&host->lock); - -@@ -2527,15 +2466,38 @@ - mmc_hostname(host->mmc), unexpected); - sdhci_dumpregs(host); - } -- /* -- * We have to delay this as it calls back into the driver. -- */ -- if (cardint) -- mmc_signal_sdio_irq(host->mmc); - - return result; - } - -+static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) -+{ -+ struct sdhci_host *host = dev_id; -+ unsigned long flags; -+ u32 isr; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ isr = host->thread_isr; -+ host->thread_isr = 0; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { -+ sdhci_card_event(host->mmc); -+ mmc_detect_change(host->mmc, msecs_to_jiffies(200)); -+ } -+ -+ if (isr & SDHCI_INT_CARD_INT) { -+ sdio_run_irqs(host->mmc); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ if (host->flags & SDHCI_SDIO_IRQ_ENABLED) -+ sdhci_enable_sdio_irq_nolock(host, true); -+ spin_unlock_irqrestore(&host->lock, flags); -+ } -+ -+ return isr ? IRQ_HANDLED : IRQ_NONE; -+} -+ - /*****************************************************************************\ - * * - * Suspend/resume * -@@ -2572,9 +2534,6 @@ - - int sdhci_suspend_host(struct sdhci_host *host) - { -- if (host->ops->platform_suspend) -- host->ops->platform_suspend(host); -- - sdhci_disable_card_detection(host); - - /* Disable tuning since we are suspending */ -@@ -2584,7 +2543,9 @@ - } - - if (!device_may_wakeup(mmc_dev(host->mmc))) { -- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); -+ host->ier = 0; -+ sdhci_writel(host, 0, SDHCI_INT_ENABLE); -+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - free_irq(host->irq, host); - } else { - sdhci_enable_irq_wakeups(host); -@@ -2605,8 +2566,9 @@ - } - - if (!device_may_wakeup(mmc_dev(host->mmc))) { -- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, -- mmc_hostname(host->mmc), host); -+ ret = request_threaded_irq(host->irq, sdhci_irq, -+ sdhci_thread_irq, IRQF_SHARED, -+ mmc_hostname(host->mmc), host); - if (ret) - return ret; - } else { -@@ -2628,9 +2590,6 @@ - - sdhci_enable_card_detection(host); - -- if (host->ops->platform_resume) -- host->ops->platform_resume(host); -- - /* Set the re-tuning expiration flag */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) - host->flags |= SDHCI_NEEDS_RETUNING; -@@ -2682,10 +2641,12 @@ - } - - spin_lock_irqsave(&host->lock, flags); -- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); -+ host->ier &= SDHCI_INT_CARD_INT; -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - spin_unlock_irqrestore(&host->lock, flags); - -- synchronize_irq(host->irq); -+ synchronize_hardirq(host->irq); - - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = true; -@@ -2729,7 +2690,7 @@ - host->runtime_suspended = false; - - /* Enable SDIO IRQ */ -- if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) -+ if (host->flags & SDHCI_SDIO_IRQ_ENABLED) - sdhci_enable_sdio_irq_nolock(host, true); - - /* Enable Card Detection */ -@@ -2788,7 +2749,7 @@ - if (debug_quirks2) - host->quirks2 = debug_quirks2; - -- sdhci_reset(host, SDHCI_RESET_ALL); -+ sdhci_do_reset(host, SDHCI_RESET_ALL); - - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - host->version = (host->version & SDHCI_SPEC_VER_MASK) -@@ -2848,15 +2809,29 @@ - * (128) and potentially one alignment transfer for - * each of those entries. - */ -- host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL); -+ host->adma_desc = dma_alloc_coherent(mmc_dev(host->mmc), -+ ADMA_SIZE, &host->adma_addr, -+ GFP_KERNEL); - host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); - if (!host->adma_desc || !host->align_buffer) { -- kfree(host->adma_desc); -+ dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, -+ host->adma_desc, host->adma_addr); - kfree(host->align_buffer); - pr_warning("%s: Unable to allocate ADMA " - "buffers. Falling back to standard DMA.\n", - mmc_hostname(mmc)); - host->flags &= ~SDHCI_USE_ADMA; -+ host->adma_desc = NULL; -+ host->align_buffer = NULL; -+ } else if (host->adma_addr & 3) { -+ pr_warning("%s: unable to allocate aligned ADMA descriptor\n", -+ mmc_hostname(mmc)); -+ host->flags &= ~SDHCI_USE_ADMA; -+ dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, -+ host->adma_desc, host->adma_addr); -+ kfree(host->align_buffer); -+ host->adma_desc = NULL; -+ host->align_buffer = NULL; - } - } - -@@ -2941,6 +2916,7 @@ - mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; - - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; -+ mmc->caps2 |= MMC_CAP2_SDIO_NOTHREAD; - - if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) - host->flags |= SDHCI_AUTO_CMD12; -@@ -3212,8 +3188,6 @@ - /* - * Init tasklets. - */ -- tasklet_init(&host->card_tasklet, -- sdhci_tasklet_card, (unsigned long)host); - tasklet_init(&host->finish_tasklet, - sdhci_tasklet_finish, (unsigned long)host); - -@@ -3230,8 +3204,8 @@ - - sdhci_init(host, 0); - -- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, -- mmc_hostname(mmc), host); -+ ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq, -+ IRQF_SHARED, mmc_hostname(mmc), host); - if (ret) { - pr_err("%s: Failed to request IRQ %d: %d\n", - mmc_hostname(mmc), host->irq, ret); -@@ -3273,12 +3247,12 @@ - - #ifdef SDHCI_USE_LEDS_CLASS - reset: -- sdhci_reset(host, SDHCI_RESET_ALL); -- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); -+ sdhci_do_reset(host, SDHCI_RESET_ALL); -+ sdhci_writel(host, 0, SDHCI_INT_ENABLE); -+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - free_irq(host->irq, host); - #endif - untasklet: -- tasklet_kill(&host->card_tasklet); - tasklet_kill(&host->finish_tasklet); - - return ret; -@@ -3315,14 +3289,14 @@ - #endif - - if (!dead) -- sdhci_reset(host, SDHCI_RESET_ALL); -+ sdhci_do_reset(host, SDHCI_RESET_ALL); - -- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); -+ sdhci_writel(host, 0, SDHCI_INT_ENABLE); -+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - free_irq(host->irq, host); - - del_timer_sync(&host->timer); - -- tasklet_kill(&host->card_tasklet); - tasklet_kill(&host->finish_tasklet); - - if (host->vmmc) { -@@ -3335,7 +3309,9 @@ - regulator_put(host->vqmmc); - } - -- kfree(host->adma_desc); -+ if (host->adma_desc) -+ dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, -+ host->adma_desc, host->adma_addr); - kfree(host->align_buffer); - - host->adma_desc = NULL; -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-cns3xxx.c linux-3.15-rc6/drivers/mmc/host/sdhci-cns3xxx.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-cns3xxx.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-cns3xxx.c 2014-05-23 11:26:48.304940032 +0200 -@@ -30,13 +30,12 @@ - u16 clk; - unsigned long timeout; - -- if (clock == host->clock) -- return; -+ host->mmc->actual_clock = 0; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) -- goto out; -+ return; - - while (host->max_clk / div > clock) { - /* -@@ -75,13 +74,14 @@ - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); --out: -- host->clock = clock; - } - - static const struct sdhci_ops sdhci_cns3xxx_ops = { - .get_max_clock = sdhci_cns3xxx_get_max_clk, - .set_clock = sdhci_cns3xxx_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { -@@ -90,8 +90,7 @@ - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | -- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | -- SDHCI_QUIRK_NONSTANDARD_CLOCK, -+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, - }; - - static int sdhci_cns3xxx_probe(struct platform_device *pdev) -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-dove.c linux-3.15-rc6/drivers/mmc/host/sdhci-dove.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-dove.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-dove.c 2014-05-23 11:26:48.304940032 +0200 -@@ -86,6 +86,10 @@ - static const struct sdhci_ops sdhci_dove_ops = { - .read_w = sdhci_dove_readw, - .read_l = sdhci_dove_readl, -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static const struct sdhci_pltfm_data sdhci_dove_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-esdhc.h linux-3.15-rc6/drivers/mmc/host/sdhci-esdhc.h ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-esdhc.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-esdhc.h 2014-05-23 11:26:48.304940032 +0200 -@@ -20,10 +20,8 @@ - - #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ - SDHCI_QUIRK_NO_BUSY_IRQ | \ -- SDHCI_QUIRK_NONSTANDARD_CLOCK | \ - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ -- SDHCI_QUIRK_PIO_NEEDS_DELAY | \ -- SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) -+ SDHCI_QUIRK_PIO_NEEDS_DELAY) - - #define ESDHC_SYSTEM_CONTROL 0x2c - #define ESDHC_CLOCK_MASK 0x0000fff0 -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-esdhc-imx.c linux-3.15-rc6/drivers/mmc/host/sdhci-esdhc-imx.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-esdhc-imx.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-esdhc-imx.c 2014-05-23 11:26:48.304940032 +0200 -@@ -160,7 +160,6 @@ - MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ - WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ - } multiblock_status; -- u32 uhs_mode; - u32 is_ddr; - }; - -@@ -382,7 +381,6 @@ - if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) - ret |= SDHCI_CTRL_TUNED_CLK; - -- ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); - ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; - - return ret; -@@ -429,7 +427,6 @@ - else - new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; - writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); -- imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; - if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { - new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); - if (val & SDHCI_CTRL_TUNED_CLK) -@@ -600,12 +597,14 @@ - u32 temp, val; - - if (clock == 0) { -+ host->mmc->actual_clock = 0; -+ - if (esdhc_is_usdhc(imx_data)) { - val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); - writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, - host->ioaddr + ESDHC_VENDOR_SPEC); - } -- goto out; -+ return; - } - - if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr) -@@ -645,8 +644,6 @@ - } - - mdelay(1); --out: -- host->clock = clock; - } - - static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) -@@ -668,7 +665,7 @@ - return -ENOSYS; - } - --static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) -+static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) - { - u32 ctrl; - -@@ -686,8 +683,6 @@ - - esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, - SDHCI_HOST_CONTROL); -- -- return 0; - } - - static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) -@@ -697,6 +692,7 @@ - /* FIXME: delay a bit for card to be ready for next tuning due to errors */ - mdelay(1); - -+ /* This is balanced by the runtime put in sdhci_tasklet_finish */ - pm_runtime_get_sync(host->mmc->parent); - reg = readl(host->ioaddr + ESDHC_MIX_CTRL); - reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | -@@ -713,13 +709,12 @@ - complete(&mrq->completion); - } - --static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode) -+static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode, -+ struct scatterlist *sg) - { - struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; - struct mmc_data data = {0}; -- struct scatterlist sg; -- char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN]; - - cmd.opcode = opcode; - cmd.arg = 0; -@@ -728,11 +723,9 @@ - data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN; - data.blocks = 1; - data.flags = MMC_DATA_READ; -- data.sg = &sg; -+ data.sg = sg; - data.sg_len = 1; - -- sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern)); -- - mrq.cmd = &cmd; - mrq.cmd->mrq = &mrq; - mrq.data = &data; -@@ -742,14 +735,12 @@ - mrq.done = esdhc_request_done; - init_completion(&(mrq.completion)); - -- disable_irq(host->irq); -- spin_lock(&host->lock); -+ spin_lock_irq(&host->lock); - host->mrq = &mrq; - - sdhci_send_command(host, mrq.cmd); - -- spin_unlock(&host->lock); -- enable_irq(host->irq); -+ spin_unlock_irq(&host->lock); - - wait_for_completion(&mrq.completion); - -@@ -772,13 +763,21 @@ - - static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) - { -+ struct scatterlist sg; -+ char *tuning_pattern; - int min, max, avg, ret; - -+ tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL); -+ if (!tuning_pattern) -+ return -ENOMEM; -+ -+ sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN); -+ - /* find the mininum delay first which can pass tuning */ - min = ESDHC_TUNE_CTRL_MIN; - while (min < ESDHC_TUNE_CTRL_MAX) { - esdhc_prepare_tuning(host, min); -- if (!esdhc_send_tuning_cmd(host, opcode)) -+ if (!esdhc_send_tuning_cmd(host, opcode, &sg)) - break; - min += ESDHC_TUNE_CTRL_STEP; - } -@@ -787,7 +786,7 @@ - max = min + ESDHC_TUNE_CTRL_STEP; - while (max < ESDHC_TUNE_CTRL_MAX) { - esdhc_prepare_tuning(host, max); -- if (esdhc_send_tuning_cmd(host, opcode)) { -+ if (esdhc_send_tuning_cmd(host, opcode, &sg)) { - max -= ESDHC_TUNE_CTRL_STEP; - break; - } -@@ -797,9 +796,11 @@ - /* use average delay to get the best timing */ - avg = (min + max) / 2; - esdhc_prepare_tuning(host, avg); -- ret = esdhc_send_tuning_cmd(host, opcode); -+ ret = esdhc_send_tuning_cmd(host, opcode, &sg); - esdhc_post_tuning(host); - -+ kfree(tuning_pattern); -+ - dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", - ret ? "failed" : "passed", avg, ret); - -@@ -837,28 +838,20 @@ - return pinctrl_select_state(imx_data->pinctrl, pinctrl); - } - --static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) -+static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) - { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - struct esdhc_platform_data *boarddata = &imx_data->boarddata; - -- switch (uhs) { -+ switch (timing) { - case MMC_TIMING_UHS_SDR12: -- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12; -- break; - case MMC_TIMING_UHS_SDR25: -- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25; -- break; - case MMC_TIMING_UHS_SDR50: -- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50; -- break; - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_MMC_HS200: -- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104; - break; - case MMC_TIMING_UHS_DDR50: -- imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50; - writel(readl(host->ioaddr + ESDHC_MIX_CTRL) | - ESDHC_MIX_CTRL_DDREN, - host->ioaddr + ESDHC_MIX_CTRL); -@@ -875,7 +868,15 @@ - break; - } - -- return esdhc_change_pinstate(host, uhs); -+ esdhc_change_pinstate(host, timing); -+} -+ -+static void esdhc_reset(struct sdhci_host *host, u8 mask) -+{ -+ sdhci_reset(host, mask); -+ -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - } - - static struct sdhci_ops sdhci_esdhc_ops = { -@@ -888,8 +889,9 @@ - .get_max_clock = esdhc_pltfm_get_max_clock, - .get_min_clock = esdhc_pltfm_get_min_clock, - .get_ro = esdhc_pltfm_get_ro, -- .platform_bus_width = esdhc_pltfm_bus_width, -+ .set_bus_width = esdhc_pltfm_set_bus_width, - .set_uhs_signaling = esdhc_set_uhs_signaling, -+ .reset = esdhc_reset, - }; - - static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { -@@ -1170,8 +1172,10 @@ - - ret = sdhci_runtime_suspend_host(host); - -- clk_disable_unprepare(imx_data->clk_per); -- clk_disable_unprepare(imx_data->clk_ipg); -+ if (!sdhci_sdio_irq_enabled(host)) { -+ clk_disable_unprepare(imx_data->clk_per); -+ clk_disable_unprepare(imx_data->clk_ipg); -+ } - clk_disable_unprepare(imx_data->clk_ahb); - - return ret; -@@ -1183,8 +1187,10 @@ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - -- clk_prepare_enable(imx_data->clk_per); -- clk_prepare_enable(imx_data->clk_ipg); -+ if (!sdhci_sdio_irq_enabled(host)) { -+ clk_prepare_enable(imx_data->clk_per); -+ clk_prepare_enable(imx_data->clk_ipg); -+ } - clk_prepare_enable(imx_data->clk_ahb); - - return sdhci_runtime_resume_host(host); -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci.h linux-3.15-rc6/drivers/mmc/host/sdhci.h ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci.h 2014-05-23 11:26:48.304940032 +0200 -@@ -281,18 +281,14 @@ - unsigned int (*get_max_clock)(struct sdhci_host *host); - unsigned int (*get_min_clock)(struct sdhci_host *host); - unsigned int (*get_timeout_clock)(struct sdhci_host *host); -- int (*platform_bus_width)(struct sdhci_host *host, -- int width); -+ void (*set_bus_width)(struct sdhci_host *host, int width); - void (*platform_send_init_74_clocks)(struct sdhci_host *host, - u8 power_mode); - unsigned int (*get_ro)(struct sdhci_host *host); -- void (*platform_reset_enter)(struct sdhci_host *host, u8 mask); -- void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); -+ void (*reset)(struct sdhci_host *host, u8 mask); - int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); -- int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); -+ void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); - void (*hw_reset)(struct sdhci_host *host); -- void (*platform_suspend)(struct sdhci_host *host); -- void (*platform_resume)(struct sdhci_host *host); - void (*adma_workaround)(struct sdhci_host *host, u32 intmask); - void (*platform_init)(struct sdhci_host *host); - void (*card_event)(struct sdhci_host *host); -@@ -397,6 +393,16 @@ - extern void sdhci_send_command(struct sdhci_host *host, - struct mmc_command *cmd); - -+static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host) -+{ -+ return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED); -+} -+ -+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); -+void sdhci_set_bus_width(struct sdhci_host *host, int width); -+void sdhci_reset(struct sdhci_host *host, u8 mask); -+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); -+ - #ifdef CONFIG_PM - extern int sdhci_suspend_host(struct sdhci_host *host); - extern int sdhci_resume_host(struct sdhci_host *host); -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-of-arasan.c linux-3.15-rc6/drivers/mmc/host/sdhci-of-arasan.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-of-arasan.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-of-arasan.c 2014-05-23 11:26:48.304940032 +0200 -@@ -52,8 +52,12 @@ - } - - static struct sdhci_ops sdhci_arasan_ops = { -+ .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .get_timeout_clock = sdhci_arasan_get_timeout_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static struct sdhci_pltfm_data sdhci_arasan_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-of-esdhc.c linux-3.15-rc6/drivers/mmc/host/sdhci-of-esdhc.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-of-esdhc.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-of-esdhc.c 2014-05-23 11:26:48.304940032 +0200 -@@ -199,13 +199,14 @@ - - static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) - { -- - int pre_div = 2; - int div = 1; - u32 temp; - -+ host->mmc->actual_clock = 0; -+ - if (clock == 0) -- goto out; -+ return; - - /* Workaround to reduce the clock frequency for p1010 esdhc */ - if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { -@@ -238,24 +239,8 @@ - | (pre_div << ESDHC_PREDIV_SHIFT)); - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(1); --out: -- host->clock = clock; - } - --#ifdef CONFIG_PM --static u32 esdhc_proctl; --static void esdhc_of_suspend(struct sdhci_host *host) --{ -- esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); --} -- --static void esdhc_of_resume(struct sdhci_host *host) --{ -- esdhc_of_enable_dma(host); -- sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); --} --#endif -- - static void esdhc_of_platform_init(struct sdhci_host *host) - { - u32 vvn; -@@ -269,7 +254,7 @@ - host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; - } - --static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) -+static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) - { - u32 ctrl; - -@@ -289,8 +274,6 @@ - - clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL, - ESDHC_CTRL_BUSWIDTH_MASK, ctrl); -- -- return 0; - } - - static const struct sdhci_ops sdhci_esdhc_ops = { -@@ -305,13 +288,46 @@ - .get_max_clock = esdhc_of_get_max_clock, - .get_min_clock = esdhc_of_get_min_clock, - .platform_init = esdhc_of_platform_init, --#ifdef CONFIG_PM -- .platform_suspend = esdhc_of_suspend, -- .platform_resume = esdhc_of_resume, --#endif - .adma_workaround = esdhci_of_adma_workaround, -- .platform_bus_width = esdhc_pltfm_bus_width, -+ .set_bus_width = esdhc_pltfm_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+}; -+ -+#ifdef CONFIG_PM -+ -+static u32 esdhc_proctl; -+static int esdhc_of_suspend(struct device *dev) -+{ -+ struct sdhci_host *host = dev_get_drvdata(dev); -+ -+ esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); -+ -+ return sdhci_suspend_host(host); -+} -+ -+static void esdhc_of_resume(device *dev) -+{ -+ struct sdhci_host *host = dev_get_drvdata(dev); -+ int ret = sdhci_resume_host(host); -+ -+ if (ret == 0) { -+ /* Isn't this already done by sdhci_resume_host() ? --rmk */ -+ esdhc_of_enable_dma(host); -+ sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); -+ } -+ -+ return ret; -+} -+ -+static const struct dev_pm_ops esdhc_pmops = { -+ .suspend = esdhci_of_suspend, -+ .resume = esdhci_of_resume, - }; -+#define ESDHC_PMOPS (&esdhc_pmops) -+#else -+#define ESDHC_PMOPS NULL -+#endif - - static const struct sdhci_pltfm_data sdhci_esdhc_pdata = { - /* -@@ -374,7 +390,7 @@ - .name = "sdhci-esdhc", - .owner = THIS_MODULE, - .of_match_table = sdhci_esdhc_of_match, -- .pm = SDHCI_PLTFM_PMOPS, -+ .pm = ESDHC_PMOPS, - }, - .probe = sdhci_esdhc_probe, - .remove = sdhci_esdhc_remove, -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-of-hlwd.c linux-3.15-rc6/drivers/mmc/host/sdhci-of-hlwd.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-of-hlwd.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-of-hlwd.c 2014-05-23 11:26:48.304940032 +0200 -@@ -58,6 +58,10 @@ - .write_l = sdhci_hlwd_writel, - .write_w = sdhci_hlwd_writew, - .write_b = sdhci_hlwd_writeb, -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static const struct sdhci_pltfm_data sdhci_hlwd_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pci.c linux-3.15-rc6/drivers/mmc/host/sdhci-pci.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pci.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-pci.c 2014-05-23 11:26:48.304940032 +0200 -@@ -1031,7 +1031,7 @@ - return 0; - } - --static int sdhci_pci_bus_width(struct sdhci_host *host, int width) -+static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width) - { - u8 ctrl; - -@@ -1052,8 +1052,6 @@ - } - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -- -- return 0; - } - - static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) -@@ -1080,8 +1078,11 @@ - } - - static const struct sdhci_ops sdhci_pci_ops = { -+ .set_clock = sdhci_set_clock, - .enable_dma = sdhci_pci_enable_dma, -- .platform_bus_width = sdhci_pci_bus_width, -+ .set_bus_width = sdhci_pci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - .hw_reset = sdhci_pci_hw_reset, - }; - -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pltfm.c linux-3.15-rc6/drivers/mmc/host/sdhci-pltfm.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pltfm.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-pltfm.c 2014-05-23 11:26:48.308940045 +0200 -@@ -45,6 +45,10 @@ - EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); - - static const struct sdhci_ops sdhci_pltfm_ops = { -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - #ifdef CONFIG_OF -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pxav2.c linux-3.15-rc6/drivers/mmc/host/sdhci-pxav2.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pxav2.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-pxav2.c 2014-05-23 11:26:48.308940045 +0200 -@@ -51,11 +51,13 @@ - #define MMC_CARD 0x1000 - #define MMC_WIDTH 0x0100 - --static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) -+static void pxav2_reset(struct sdhci_host *host, u8 mask) - { - struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; - -+ sdhci_reset(host, mask); -+ - if (mask == SDHCI_RESET_ALL) { - u16 tmp = 0; - -@@ -88,7 +90,7 @@ - } - } - --static int pxav2_mmc_set_width(struct sdhci_host *host, int width) -+static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width) - { - u8 ctrl; - u16 tmp; -@@ -107,14 +109,14 @@ - } - writew(tmp, host->ioaddr + SD_CE_ATA_2); - writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); -- -- return 0; - } - - static const struct sdhci_ops pxav2_sdhci_ops = { -+ .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, -- .platform_reset_exit = pxav2_set_private_registers, -- .platform_bus_width = pxav2_mmc_set_width, -+ .set_bus_width = pxav2_mmc_set_bus_width, -+ .reset = pxav2_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - #ifdef CONFIG_OF -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pxav3.c linux-3.15-rc6/drivers/mmc/host/sdhci-pxav3.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-pxav3.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-pxav3.c 2014-05-23 11:26:48.308940045 +0200 -@@ -112,11 +112,13 @@ - return 0; - } - --static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask) -+static void pxav3_reset(struct sdhci_host *host, u8 mask) - { - struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; - -+ sdhci_reset(host, mask); -+ - if (mask == SDHCI_RESET_ALL) { - /* - * tune timing of read data/command when crc error happen -@@ -184,7 +186,7 @@ - pxa->power_mode = power_mode; - } - --static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) -+static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) - { - u16 ctrl_2; - -@@ -218,15 +220,16 @@ - dev_dbg(mmc_dev(host->mmc), - "%s uhs = %d, ctrl_2 = %04X\n", - __func__, uhs, ctrl_2); -- -- return 0; - } - - static const struct sdhci_ops pxav3_sdhci_ops = { -- .platform_reset_exit = pxav3_set_private_registers, -+ .set_clock = sdhci_set_clock, - .set_uhs_signaling = pxav3_set_uhs_signaling, - .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = pxav3_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static struct sdhci_pltfm_data sdhci_pxav3_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-s3c.c linux-3.15-rc6/drivers/mmc/host/sdhci-s3c.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-s3c.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-s3c.c 2014-05-23 11:26:48.308940045 +0200 -@@ -58,6 +58,8 @@ - struct clk *clk_io; - struct clk *clk_bus[MAX_BUS_CLK]; - unsigned long clk_rates[MAX_BUS_CLK]; -+ -+ bool no_divider; - }; - - /** -@@ -70,6 +72,7 @@ - */ - struct sdhci_s3c_drv_data { - unsigned int sdhci_quirks; -+ bool no_divider; - }; - - static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) -@@ -119,7 +122,7 @@ - * If controller uses a non-standard clock division, find the best clock - * speed possible with selected clock source and skip the division. - */ -- if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { -+ if (ourhost->no_divider) { - rate = clk_round_rate(clksrc, wanted); - return wanted - rate; - } -@@ -161,9 +164,13 @@ - int src; - u32 ctrl; - -+ host->mmc->actual_clock = 0; -+ - /* don't bother if the clock is going off. */ -- if (clock == 0) -+ if (clock == 0) { -+ sdhci_set_clock(host, clock); - return; -+ } - - for (src = 0; src < MAX_BUS_CLK; src++) { - delta = sdhci_s3c_consider_clock(ourhost, src, clock); -@@ -215,6 +222,8 @@ - if (clock < 25 * 1000000) - ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); -+ -+ sdhci_set_clock(host, clock); - } - - /** -@@ -295,10 +304,11 @@ - unsigned long timeout; - u16 clk = 0; - -+ host->mmc->actual_clock = 0; -+ - /* If the clock is going off, set to 0 at clock control register */ - if (clock == 0) { - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); -- host->clock = clock; - return; - } - -@@ -306,8 +316,6 @@ - - clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); - -- host->clock = clock; -- - clk = SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - -@@ -329,14 +337,14 @@ - } - - /** -- * sdhci_s3c_platform_bus_width - support 8bit buswidth -+ * sdhci_s3c_set_bus_width - support 8bit buswidth - * @host: The SDHCI host being queried - * @width: MMC_BUS_WIDTH_ macro for the bus width being requested - * - * We have 8-bit width support but is not a v3 controller. - * So we add platform_bus_width() and support 8bit width. - */ --static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width) -+static void sdhci_s3c_set_bus_width(struct sdhci_host *host, int width) - { - u8 ctrl; - -@@ -358,15 +366,15 @@ - } - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -- -- return 0; - } - - static struct sdhci_ops sdhci_s3c_ops = { - .get_max_clock = sdhci_s3c_get_max_clk, - .set_clock = sdhci_s3c_set_clock, - .get_min_clock = sdhci_s3c_get_min_clock, -- .platform_bus_width = sdhci_s3c_platform_bus_width, -+ .set_bus_width = sdhci_s3c_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static void sdhci_s3c_notify_change(struct platform_device *dev, int state) -@@ -606,8 +614,10 @@ - /* Setup quirks for the controller */ - host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; - host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; -- if (drv_data) -+ if (drv_data) { - host->quirks |= drv_data->sdhci_quirks; -+ sc->no_divider = drv_data->no_divider; -+ } - - #ifndef CONFIG_MMC_SDHCI_S3C_DMA - -@@ -656,7 +666,7 @@ - * If controller does not have internal clock divider, - * we can use overriding functions instead of default. - */ -- if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { -+ if (sc->no_divider) { - sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; - sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; - sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; -@@ -797,7 +807,7 @@ - - #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) - static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { -- .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, -+ .no_divider = true, - }; - #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) - #else -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-sirf.c linux-3.15-rc6/drivers/mmc/host/sdhci-sirf.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-sirf.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-sirf.c 2014-05-23 11:26:48.308940045 +0200 -@@ -28,7 +28,11 @@ - } - - static struct sdhci_ops sdhci_sirf_ops = { -+ .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_sirf_get_max_clk, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static struct sdhci_pltfm_data sdhci_sirf_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-spear.c linux-3.15-rc6/drivers/mmc/host/sdhci-spear.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-spear.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-spear.c 2014-05-23 11:26:48.308940045 +0200 -@@ -38,7 +38,10 @@ - - /* sdhci ops */ - static const struct sdhci_ops sdhci_pltfm_ops = { -- /* Nothing to do for now. */ -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - #ifdef CONFIG_OF -diff -Nur linux-3.15-rc6.orig/drivers/mmc/host/sdhci-tegra.c linux-3.15-rc6/drivers/mmc/host/sdhci-tegra.c ---- linux-3.15-rc6.orig/drivers/mmc/host/sdhci-tegra.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/mmc/host/sdhci-tegra.c 2014-05-23 11:26:48.308940045 +0200 -@@ -48,19 +48,6 @@ - int power_gpio; - }; - --static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) --{ -- u32 val; -- -- if (unlikely(reg == SDHCI_PRESENT_STATE)) { -- /* Use wp_gpio here instead? */ -- val = readl(host->ioaddr + reg); -- return val | SDHCI_WRITE_PROTECT; -- } -- -- return readl(host->ioaddr + reg); --} -- - static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) - { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -@@ -108,12 +95,14 @@ - return mmc_gpio_get_ro(host->mmc); - } - --static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) -+static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) - { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - -+ sdhci_reset(host, mask); -+ - if (!(mask & SDHCI_RESET_ALL)) - return; - -@@ -127,7 +116,7 @@ - } - } - --static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) -+static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) - { - u32 ctrl; - -@@ -144,16 +133,16 @@ - ctrl &= ~SDHCI_CTRL_4BITBUS; - } - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -- return 0; - } - - static const struct sdhci_ops tegra_sdhci_ops = { - .get_ro = tegra_sdhci_get_ro, -- .read_l = tegra_sdhci_readl, - .read_w = tegra_sdhci_readw, - .write_l = tegra_sdhci_writel, -- .platform_bus_width = tegra_sdhci_buswidth, -- .platform_reset_exit = tegra_sdhci_reset_exit, -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = tegra_sdhci_set_bus_width, -+ .reset = tegra_sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, - }; - - static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { -diff -Nur linux-3.15-rc6.orig/drivers/net/ethernet/freescale/fec.h linux-3.15-rc6/drivers/net/ethernet/freescale/fec.h ---- linux-3.15-rc6.orig/drivers/net/ethernet/freescale/fec.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/net/ethernet/freescale/fec.h 2014-05-23 11:26:48.308940045 +0200 -@@ -14,6 +14,7 @@ - /****************************************************************************/ - - #include <linux/clocksource.h> -+#include <linux/mutex.h> - #include <linux/net_tstamp.h> - #include <linux/ptp_clock_kernel.h> - -@@ -170,6 +171,11 @@ - unsigned short res0[4]; - }; - -+union bufdesc_u { -+ struct bufdesc bd; -+ struct bufdesc_ex ebd; -+}; -+ - /* - * The following definitions courtesy of commproc.h, which where - * Copyright (c) 1997 Dan Malek (dmalek@jlc.net). -@@ -202,6 +208,7 @@ - #define BD_ENET_RX_OV ((ushort)0x0002) - #define BD_ENET_RX_CL ((ushort)0x0001) - #define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ -+#define BD_ENET_RX_ERROR ((ushort)0x003f) - - /* Enhanced buffer descriptor control/status used by Ethernet receive */ - #define BD_ENET_RX_VLAN 0x00000004 -@@ -224,10 +231,17 @@ - #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ - - /*enhanced buffer descriptor control/status used by Ethernet transmit*/ --#define BD_ENET_TX_INT 0x40000000 --#define BD_ENET_TX_TS 0x20000000 --#define BD_ENET_TX_PINS 0x10000000 --#define BD_ENET_TX_IINS 0x08000000 -+#define BD_ENET_TX_INT BIT(30) -+#define BD_ENET_TX_TS BIT(29) -+#define BD_ENET_TX_PINS BIT(28) -+#define BD_ENET_TX_IINS BIT(27) -+#define BD_ENET_TX_TXE BIT(15) -+#define BD_ENET_TX_UE BIT(13) -+#define BD_ENET_TX_EE BIT(12) -+#define BD_ENET_TX_FE BIT(11) -+#define BD_ENET_TX_LCE BIT(10) -+#define BD_ENET_TX_OE BIT(9) -+#define BD_ENET_TX_TSE BIT(8) - - - /* This device has up to three irqs on some platforms */ -@@ -240,28 +254,20 @@ - * the skbuffer directly. - */ - --#define FEC_ENET_RX_PAGES 8 -+#define FEC_ENET_RX_PAGES 64 - #define FEC_ENET_RX_FRSIZE 2048 - #define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) - #define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) - #define FEC_ENET_TX_FRSIZE 2048 - #define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) --#define TX_RING_SIZE 16 /* Must be power of two */ --#define TX_RING_MOD_MASK 15 /* for this to work */ -+#define TX_RING_SIZE 128 /* Must be power of two */ - - #define BD_ENET_RX_INT 0x00800000 - #define BD_ENET_RX_PTP ((ushort)0x0400) - #define BD_ENET_RX_ICE 0x00000020 - #define BD_ENET_RX_PCR 0x00000010 --#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) - #define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) - --struct fec_enet_delayed_work { -- struct delayed_work delay_work; -- bool timeout; -- bool trig_tx; --}; -- - /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and - * tx_bd_base always point to the base of the buffer descriptors. The - * cur_rx and cur_tx point to the currently available buffer. -@@ -281,27 +287,33 @@ - struct clk *clk_enet_out; - struct clk *clk_ptp; - -+ unsigned char tx_page_map[TX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - unsigned char *tx_bounce[TX_RING_SIZE]; - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - - /* CPM dual port RAM relative addresses */ -- dma_addr_t bd_dma; -+ dma_addr_t rx_bd_dma; -+ dma_addr_t tx_bd_dma; - /* Address of Rx and Tx buffers */ -- struct bufdesc *rx_bd_base; -- struct bufdesc *tx_bd_base; -+ union bufdesc_u *rx_bd_base; -+ union bufdesc_u *tx_bd_base; - /* The next free ring entry */ -- struct bufdesc *cur_rx, *cur_tx; -- /* The ring entries to be free()ed */ -- struct bufdesc *dirty_tx; -+ unsigned short tx_next; -+ unsigned short tx_dirty; -+ unsigned short tx_min; -+ unsigned short rx_next; - - unsigned short tx_ring_size; - unsigned short rx_ring_size; - -+ unsigned char flags; -+ -+ struct mutex mutex; -+ - struct platform_device *pdev; - -- int opened; - int dev_id; - - /* Phylib and MDIO interface */ -@@ -315,11 +327,12 @@ - int speed; - struct completion mdio_done; - int irq[FEC_IRQ_NUM]; -- int bufdesc_ex; -- int pause_flag; -+ unsigned short pause_flag; -+ unsigned short pause_mode; - - struct napi_struct napi; -- int csum_flags; -+ -+ struct work_struct tx_timeout_work; - - struct ptp_clock *ptp_clock; - struct ptp_clock_info ptp_caps; -@@ -333,8 +346,8 @@ - int hwts_rx_en; - int hwts_tx_en; - struct timer_list time_keep; -- struct fec_enet_delayed_work delay_work; - struct regulator *reg_phy; -+ unsigned long quirks; - }; - - void fec_ptp_init(struct platform_device *pdev); -diff -Nur linux-3.15-rc6.orig/drivers/net/ethernet/freescale/fec_main.c linux-3.15-rc6/drivers/net/ethernet/freescale/fec_main.c ---- linux-3.15-rc6.orig/drivers/net/ethernet/freescale/fec_main.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/net/ethernet/freescale/fec_main.c 2014-05-23 11:26:48.312940058 +0200 -@@ -33,12 +33,6 @@ - #include <linux/netdevice.h> - #include <linux/etherdevice.h> - #include <linux/skbuff.h> --#include <linux/in.h> --#include <linux/ip.h> --#include <net/ip.h> --#include <linux/tcp.h> --#include <linux/udp.h> --#include <linux/icmp.h> - #include <linux/spinlock.h> - #include <linux/workqueue.h> - #include <linux/bitops.h> -@@ -91,16 +85,8 @@ - #define FEC_QUIRK_HAS_CSUM (1 << 5) - /* Controller has hardware vlan support */ - #define FEC_QUIRK_HAS_VLAN (1 << 6) --/* ENET IP errata ERR006358 -- * -- * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously -- * detected as not set during a prior frame transmission, then the -- * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs -- * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in -- * frames not being transmitted until there is a 0-to-1 transition on -- * ENET_TDAR[TDAR]. -- */ --#define FEC_QUIRK_ERR006358 (1 << 7) -+/* Controller has ability to offset rx packets */ -+#define FEC_QUIRK_RX_SHIFT16 (1 << 8) - - static struct platform_device_id fec_devtype[] = { - { -@@ -120,7 +106,7 @@ - .name = "imx6q-fec", - .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | - FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | -- FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358, -+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_RX_SHIFT16, - }, { - .name = "mvf600-fec", - .driver_data = FEC_QUIRK_ENET_MAC, -@@ -172,9 +158,15 @@ - #endif - #endif /* CONFIG_M5272 */ - --#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE) --#error "FEC: descriptor ring size constants too large" -+#if RX_RING_SIZE * 32 > PAGE_SIZE -+#error "FEC: receive descriptor ring size too large" - #endif -+#if TX_RING_SIZE * 32 > PAGE_SIZE -+#error "FEC: transmit descriptor ring size too large" -+#endif -+ -+/* Minimum TX ring size when using NETIF_F_SG */ -+#define TX_RING_SIZE_MIN_SG (2 * (MAX_SKB_FRAGS + 1)) - - /* Interrupt events/masks. */ - #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ -@@ -200,6 +192,7 @@ - /* FEC receive acceleration */ - #define FEC_RACC_IPDIS (1 << 1) - #define FEC_RACC_PRODIS (1 << 2) -+#define FEC_RACC_SHIFT16 BIT(7) - #define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS) - - /* -@@ -228,62 +221,60 @@ - /* Transmitter timeout */ - #define TX_TIMEOUT (2 * HZ) - --#define FEC_PAUSE_FLAG_AUTONEG 0x1 --#define FEC_PAUSE_FLAG_ENABLE 0x2 -+/* pause mode/flag */ -+#define FEC_PAUSE_FLAG_AUTONEG BIT(0) -+#define FEC_PAUSE_FLAG_RX BIT(1) -+#define FEC_PAUSE_FLAG_TX BIT(2) -+ -+/* flags */ -+#define FEC_FLAG_BUFDESC_EX BIT(0) -+#define FEC_FLAG_RX_CSUM BIT(1) -+#define FEC_FLAG_RX_VLAN BIT(2) - - static int mii_cnt; - --static inline --struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep) -+static unsigned copybreak = 200; -+module_param(copybreak, uint, 0644); -+MODULE_PARM_DESC(copybreak, -+ "Maximum size of packet that is copied to a new buffer on receive"); -+ -+static bool fec_enet_rx_zerocopy(struct fec_enet_private *fep, unsigned pktlen) - { -- struct bufdesc *new_bd = bdp + 1; -- struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1; -- struct bufdesc_ex *ex_base; -- struct bufdesc *base; -- int ring_size; -- -- if (bdp >= fep->tx_bd_base) { -- base = fep->tx_bd_base; -- ring_size = fep->tx_ring_size; -- ex_base = (struct bufdesc_ex *)fep->tx_bd_base; -- } else { -- base = fep->rx_bd_base; -- ring_size = fep->rx_ring_size; -- ex_base = (struct bufdesc_ex *)fep->rx_bd_base; -- } -+#ifndef CONFIG_M5272 -+ if (fep->quirks & FEC_QUIRK_RX_SHIFT16 && pktlen >= copybreak) -+ return true; -+#endif -+ return false; -+} - -- if (fep->bufdesc_ex) -- return (struct bufdesc *)((ex_new_bd >= (ex_base + ring_size)) ? -- ex_base : ex_new_bd); -+static union bufdesc_u * -+fec_enet_tx_get(unsigned index, struct fec_enet_private *fep) -+{ -+ union bufdesc_u *base = fep->tx_bd_base; -+ union bufdesc_u *bdp; -+ -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) -+ bdp = (union bufdesc_u *)(&base->ebd + index); - else -- return (new_bd >= (base + ring_size)) ? -- base : new_bd; -+ bdp = (union bufdesc_u *)(&base->bd + index); -+ -+ return bdp; - } - --static inline --struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep) -+static union bufdesc_u * -+fec_enet_rx_get(unsigned index, struct fec_enet_private *fep) - { -- struct bufdesc *new_bd = bdp - 1; -- struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1; -- struct bufdesc_ex *ex_base; -- struct bufdesc *base; -- int ring_size; -- -- if (bdp >= fep->tx_bd_base) { -- base = fep->tx_bd_base; -- ring_size = fep->tx_ring_size; -- ex_base = (struct bufdesc_ex *)fep->tx_bd_base; -- } else { -- base = fep->rx_bd_base; -- ring_size = fep->rx_ring_size; -- ex_base = (struct bufdesc_ex *)fep->rx_bd_base; -- } -+ union bufdesc_u *base = fep->rx_bd_base; -+ union bufdesc_u *bdp; -+ -+ index &= fep->rx_ring_size - 1; - -- if (fep->bufdesc_ex) -- return (struct bufdesc *)((ex_new_bd < ex_base) ? -- (ex_new_bd + ring_size) : ex_new_bd); -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) -+ bdp = (union bufdesc_u *)(&base->ebd + index); - else -- return (new_bd < base) ? (new_bd + ring_size) : new_bd; -+ bdp = (union bufdesc_u *)(&base->bd + index); -+ -+ return bdp; - } - - static void *swap_buffer(void *bufaddr, int len) -@@ -297,13 +288,47 @@ - return bufaddr; - } - -+static void fec_dump(struct net_device *ndev) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ union bufdesc_u *bdp; -+ unsigned index = 0; -+ -+ netdev_info(ndev, "TX ring dump\n"); -+ pr_info("Nr SC addr len SKB\n"); -+ -+ for (index = 0; index < fep->tx_ring_size; index++) { -+ bdp = fec_enet_tx_get(index, fep); -+ -+ pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p", -+ index, -+ index == fep->tx_next ? 'S' : ' ', -+ index == fep->tx_dirty ? 'H' : ' ', -+ bdp->bd.cbd_sc, bdp->bd.cbd_bufaddr, -+ bdp->bd.cbd_datlen, -+ fep->tx_skbuff[index]); -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) -+ pr_cont(" %08lx", bdp->ebd.cbd_esc); -+ pr_cont("\n"); -+ } -+} -+ - static int - fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev) - { -+ int csum_start; -+ - /* Only run for packets requiring a checksum. */ - if (skb->ip_summed != CHECKSUM_PARTIAL) - return 0; - -+ csum_start = skb_checksum_start_offset(skb); -+ if (csum_start + skb->csum_offset > skb_headlen(skb)) { -+ netdev_err(ndev, "checksum outside skb head: headlen %u start %u offset %u\n", -+ skb_headlen(skb), csum_start, skb->csum_offset); -+ return -1; -+ } -+ - if (unlikely(skb_cow_head(skb, 0))) - return -1; - -@@ -312,23 +337,56 @@ - return 0; - } - -+static void -+fec_enet_tx_unmap(unsigned index, union bufdesc_u *bdp, struct fec_enet_private *fep) -+{ -+ dma_addr_t addr = bdp->bd.cbd_bufaddr; -+ unsigned length = bdp->bd.cbd_datlen; -+ -+ bdp->bd.cbd_bufaddr = 0; -+ -+ if (fep->tx_page_map[index]) -+ dma_unmap_page(&fep->pdev->dev, addr, length, DMA_TO_DEVICE); -+ else -+ dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE); -+} -+ -+static void -+fec_enet_tx_unmap_range(unsigned index, unsigned last, struct fec_enet_private *fep) -+{ -+ union bufdesc_u *bdp; -+ -+ do { -+ if (last == 0) -+ last = fep->tx_ring_size; -+ last--; -+ -+ bdp = fec_enet_tx_get(last, fep); -+ fec_enet_tx_unmap(last, bdp, fep); -+ } while (index != last); -+} -+ -+static unsigned ring_free(unsigned ins, unsigned rem, unsigned size) -+{ -+ int num = rem - ins; -+ return num < 0 ? num + size : num; -+} -+ - static netdev_tx_t - fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) - { - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); -- struct bufdesc *bdp, *bdp_pre; -+ union bufdesc_u *bdp; - void *bufaddr; - unsigned short status; -- unsigned int index; -+ unsigned index, last, length, cbd_esc; -+ int f, nr_frags = skb_shinfo(skb)->nr_frags; -+ dma_addr_t addr; - - /* Fill in a Tx ring entry */ -- bdp = fep->cur_tx; -- -- status = bdp->cbd_sc; -+ index = fep->tx_next; - -- if (status & BD_ENET_TX_READY) { -+ if (ring_free(index, fep->tx_dirty, fep->tx_ring_size) < 1 + nr_frags) { - /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since ndev->tbusy should be set. - */ -@@ -342,26 +400,17 @@ - return NETDEV_TX_OK; - } - -- /* Clear all of the status flags */ -- status &= ~BD_ENET_TX_STATS; -- - /* Set buffer length and buffer pointer */ - bufaddr = skb->data; -- bdp->cbd_datlen = skb->len; -+ length = skb_headlen(skb); - - /* - * On some FEC implementations data must be aligned on - * 4-byte boundaries. Use bounce buffers to copy data - * and get it aligned. Ugh. - */ -- if (fep->bufdesc_ex) -- index = (struct bufdesc_ex *)bdp - -- (struct bufdesc_ex *)fep->tx_bd_base; -- else -- index = bdp - fep->tx_bd_base; -- - if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { -- memcpy(fep->tx_bounce[index], skb->data, skb->len); -+ memcpy(fep->tx_bounce[index], skb->data, length); - bufaddr = fep->tx_bounce[index]; - } - -@@ -370,75 +419,127 @@ - * the system that it's running on. As the result, driver has to - * swap every frame going to and coming from the controller. - */ -- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) -- swap_buffer(bufaddr, skb->len); -+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME) -+ swap_buffer(bufaddr, length); - -- /* Save skb pointer */ -- fep->tx_skbuff[index] = skb; -+ /* Push the data cache so the CPM does not get stale memory data. */ -+ addr = dma_map_single(&fep->pdev->dev, bufaddr, length, DMA_TO_DEVICE); -+ if (dma_mapping_error(&fep->pdev->dev, addr)) -+ goto release; -+ -+ bdp = fec_enet_tx_get(index, fep); -+ bdp->bd.cbd_datlen = length; -+ bdp->bd.cbd_bufaddr = addr; - -- /* Push the data cache so the CPM does not get stale memory -- * data. -- */ -- bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, -- skb->len, DMA_TO_DEVICE); -- if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { -- bdp->cbd_bufaddr = 0; -- fep->tx_skbuff[index] = NULL; -- dev_kfree_skb_any(skb); -- if (net_ratelimit()) -- netdev_err(ndev, "Tx DMA memory map failed\n"); -- return NETDEV_TX_OK; -- } -+ fep->tx_page_map[index] = 0; - -- if (fep->bufdesc_ex) { -- -- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -- ebdp->cbd_bdu = 0; -+ cbd_esc = BD_ENET_TX_INT; -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && - fep->hwts_tx_en)) { -- ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT); -+ cbd_esc |= BD_ENET_TX_TS; - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - } else { -- ebdp->cbd_esc = BD_ENET_TX_INT; -- - /* Enable protocol checksum flags - * We do not bother with the IP Checksum bits as they - * are done by the kernel - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) -- ebdp->cbd_esc |= BD_ENET_TX_PINS; -+ cbd_esc |= BD_ENET_TX_PINS; -+ } -+ bdp->ebd.cbd_bdu = 0; -+ bdp->ebd.cbd_esc = cbd_esc; -+ } -+ -+ for (last = index, f = 0; f < nr_frags; f++) { -+ const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f]; -+ -+ if (++last >= fep->tx_ring_size) -+ last = 0; -+ -+ length = skb_frag_size(frag); -+ -+ /* If the alignment is unsuitable, we need to bounce. */ -+ if (frag->page_offset & FEC_ALIGNMENT) { -+ unsigned char *bounce = fep->tx_bounce[last]; -+ -+ /* FIXME: highdma? */ -+ memcpy(bounce, skb_frag_address(frag), length); -+ -+ addr = dma_map_single(&fep->pdev->dev, bounce, -+ length, DMA_TO_DEVICE); -+ fep->tx_page_map[last] = 0; -+ } else { -+ addr = skb_frag_dma_map(&fep->pdev->dev, frag, 0, -+ length, DMA_TO_DEVICE); -+ fep->tx_page_map[last] = 1; -+ } -+ -+ if (dma_mapping_error(&fep->pdev->dev, addr)) -+ goto release_frags; -+ -+ bdp = fec_enet_tx_get(last, fep); -+ bdp->bd.cbd_datlen = length; -+ bdp->bd.cbd_bufaddr = addr; -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { -+ bdp->ebd.cbd_esc = cbd_esc; -+ bdp->ebd.cbd_bdu = 0; - } - } - -+ /* Save skb pointer */ -+ fep->tx_skbuff[last] = skb; -+ -+ /* -+ * We need the preceding stores to the descriptor to complete -+ * before updating the status field, which hands it over to the -+ * hardware. The corresponding rmb() is "in the hardware". -+ */ -+ wmb(); -+ - /* Send it on its way. Tell FEC it's ready, interrupt when done, - * it's the last BD of the frame, and to put the CRC on the end. - */ -- status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR -- | BD_ENET_TX_LAST | BD_ENET_TX_TC); -- bdp->cbd_sc = status; -- -- bdp_pre = fec_enet_get_prevdesc(bdp, fep); -- if ((id_entry->driver_data & FEC_QUIRK_ERR006358) && -- !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) { -- fep->delay_work.trig_tx = true; -- schedule_delayed_work(&(fep->delay_work.delay_work), -- msecs_to_jiffies(1)); -+ status = bdp->bd.cbd_sc & BD_ENET_TX_WRAP; -+ bdp->bd.cbd_sc = status | BD_ENET_TX_READY | BD_ENET_TX_INTR | -+ BD_ENET_TX_LAST | BD_ENET_TX_TC; -+ -+ /* Now walk backwards setting the TX_READY on each fragment */ -+ for (f = nr_frags - 1; f >= 0; f--) { -+ unsigned i = index + f; -+ -+ if (i >= fep->tx_ring_size) -+ i -= fep->tx_ring_size; -+ -+ bdp = fec_enet_tx_get(i, fep); -+ status = bdp->bd.cbd_sc & BD_ENET_TX_WRAP; -+ bdp->bd.cbd_sc = status | BD_ENET_TX_READY | BD_ENET_TX_INTR; - } - -- /* If this was the last BD in the ring, start at the beginning again. */ -- bdp = fec_enet_get_nextdesc(bdp, fep); -- - skb_tx_timestamp(skb); -+ netdev_sent_queue(ndev, skb->len); -+ -+ if (++last >= fep->tx_ring_size) -+ last = 0; - -- fep->cur_tx = bdp; -+ fep->tx_next = last; - -- if (fep->cur_tx == fep->dirty_tx) -+ if (ring_free(last, fep->tx_dirty, fep->tx_ring_size) < fep->tx_min) - netif_stop_queue(ndev); - - /* Trigger transmission start */ -- writel(0, fep->hwp + FEC_X_DES_ACTIVE); -+ if (readl(fep->hwp + FEC_X_DES_ACTIVE) == 0) -+ writel(0, fep->hwp + FEC_X_DES_ACTIVE); - - return NETDEV_TX_OK; -+ -+ release_frags: -+ fec_enet_tx_unmap_range(index, last, fep); -+ release: -+ dev_kfree_skb_any(skb); -+ if (net_ratelimit()) -+ netdev_err(ndev, "Tx DMA memory map failed\n"); -+ return NETDEV_TX_OK; - } - - /* Init RX & TX buffer descriptors -@@ -446,71 +547,60 @@ - static void fec_enet_bd_init(struct net_device *dev) - { - struct fec_enet_private *fep = netdev_priv(dev); -- struct bufdesc *bdp; -+ union bufdesc_u *bdp; - unsigned int i; - - /* Initialize the receive buffer descriptors. */ -- bdp = fep->rx_bd_base; - for (i = 0; i < fep->rx_ring_size; i++) { -+ bdp = fec_enet_rx_get(i, fep); - - /* Initialize the BD for every fragment in the page. */ -- if (bdp->cbd_bufaddr) -- bdp->cbd_sc = BD_ENET_RX_EMPTY; -+ if (bdp->bd.cbd_bufaddr) -+ bdp->bd.cbd_sc = BD_ENET_RX_EMPTY; - else -- bdp->cbd_sc = 0; -- bdp = fec_enet_get_nextdesc(bdp, fep); -- } -+ bdp->bd.cbd_sc = 0; - -- /* Set the last buffer to wrap */ -- bdp = fec_enet_get_prevdesc(bdp, fep); -- bdp->cbd_sc |= BD_SC_WRAP; -+ if (i == fep->rx_ring_size - 1) -+ bdp->bd.cbd_sc |= BD_SC_WRAP; -+ } - -- fep->cur_rx = fep->rx_bd_base; -+ fep->rx_next = 0; - - /* ...and the same for transmit */ -- bdp = fep->tx_bd_base; -- fep->cur_tx = bdp; - for (i = 0; i < fep->tx_ring_size; i++) { -+ bdp = fec_enet_tx_get(i, fep); - - /* Initialize the BD for every fragment in the page. */ -- bdp->cbd_sc = 0; -- if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) { -+ if (i == fep->tx_ring_size - 1) -+ bdp->bd.cbd_sc = BD_SC_WRAP; -+ else -+ bdp->bd.cbd_sc = 0; -+ if (bdp->bd.cbd_bufaddr) -+ fec_enet_tx_unmap(i, bdp, fep); -+ if (fep->tx_skbuff[i]) { - dev_kfree_skb_any(fep->tx_skbuff[i]); - fep->tx_skbuff[i] = NULL; - } -- bdp->cbd_bufaddr = 0; -- bdp = fec_enet_get_nextdesc(bdp, fep); - } - -- /* Set the last buffer to wrap */ -- bdp = fec_enet_get_prevdesc(bdp, fep); -- bdp->cbd_sc |= BD_SC_WRAP; -- fep->dirty_tx = bdp; -+ fep->tx_next = 0; -+ fep->tx_dirty = fep->tx_ring_size - 1; - } - --/* This function is called to start or restart the FEC during a link -- * change. This only happens when switching between half and full -- * duplex. -+/* -+ * This function is called to start or restart the FEC during a link -+ * change, transmit timeout, or to reconfigure the FEC. The network -+ * packet processing for this device must be stopped before this call. - */ - static void --fec_restart(struct net_device *ndev, int duplex) -+fec_restart(struct net_device *ndev) - { - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); -- int i; - u32 val; - u32 temp_mac[2]; - u32 rcntl = OPT_FRAME_SIZE | 0x04; - u32 ecntl = 0x2; /* ETHEREN */ - -- if (netif_running(ndev)) { -- netif_device_detach(ndev); -- napi_disable(&fep->napi); -- netif_stop_queue(ndev); -- netif_tx_lock_bh(ndev); -- } -- - /* Whack a reset. We should wait for this. */ - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); -@@ -519,7 +609,7 @@ - * enet-mac reset will reset mac address registers too, - * so need to reconfigure it. - */ -- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { -+ if (fep->quirks & FEC_QUIRK_ENET_MAC) { - memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); - writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); - writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); -@@ -531,27 +621,16 @@ - /* Set maximum receive buffer size. */ - writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); - -- fec_enet_bd_init(ndev); -+ if (fep->rx_bd_base) -+ fec_enet_bd_init(ndev); -+ netdev_reset_queue(ndev); - - /* Set receive and transmit descriptor base. */ -- writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); -- if (fep->bufdesc_ex) -- writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex) -- * fep->rx_ring_size, fep->hwp + FEC_X_DES_START); -- else -- writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) -- * fep->rx_ring_size, fep->hwp + FEC_X_DES_START); -- -- -- for (i = 0; i <= TX_RING_MOD_MASK; i++) { -- if (fep->tx_skbuff[i]) { -- dev_kfree_skb_any(fep->tx_skbuff[i]); -- fep->tx_skbuff[i] = NULL; -- } -- } -+ writel(fep->rx_bd_dma, fep->hwp + FEC_R_DES_START); -+ writel(fep->tx_bd_dma, fep->hwp + FEC_X_DES_START); - - /* Enable MII mode */ -- if (duplex) { -+ if (fep->full_duplex == DUPLEX_FULL) { - /* FD enable */ - writel(0x04, fep->hwp + FEC_X_CNTRL); - } else { -@@ -560,15 +639,15 @@ - writel(0x0, fep->hwp + FEC_X_CNTRL); - } - -- fep->full_duplex = duplex; -- - /* Set MII speed */ - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - - #if !defined(CONFIG_M5272) - /* set RX checksum */ - val = readl(fep->hwp + FEC_RACC); -- if (fep->csum_flags & FLAG_RX_CSUM_ENABLED) -+ if (fep->quirks & FEC_QUIRK_RX_SHIFT16) -+ val |= FEC_RACC_SHIFT16; -+ if (fep->flags & FEC_FLAG_RX_CSUM) - val |= FEC_RACC_OPTIONS; - else - val &= ~FEC_RACC_OPTIONS; -@@ -579,9 +658,9 @@ - * The phy interface and speed need to get configured - * differently on enet-mac. - */ -- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { -+ if (fep->quirks & FEC_QUIRK_ENET_MAC) { - /* Enable flow control and length check */ -- rcntl |= 0x40000000 | 0x00000020; -+ rcntl |= 0x40000000; - - /* RGMII, RMII or MII */ - if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII) -@@ -602,7 +681,7 @@ - } - } else { - #ifdef FEC_MIIGSK_ENR -- if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) { -+ if (fep->quirks & FEC_QUIRK_USE_GASKET) { - u32 cfgr; - /* disable the gasket and wait */ - writel(0, fep->hwp + FEC_MIIGSK_ENR); -@@ -627,22 +706,24 @@ - } - - #if !defined(CONFIG_M5272) -- /* enable pause frame*/ -- if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) || -- ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) && -- fep->phy_dev && fep->phy_dev->pause)) { -- rcntl |= FEC_ENET_FCE; -- -- /* set FIFO threshold parameter to reduce overrun */ -- writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM); -- writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL); -- writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM); -- writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL); -+ if (fep->full_duplex == DUPLEX_FULL) { -+ /* -+ * Configure pause modes according to the current status. -+ * Must only be enabled for full duplex links. -+ */ -+ if (fep->pause_mode & FEC_PAUSE_FLAG_RX) -+ rcntl |= FEC_ENET_FCE; - -- /* OPD */ -- writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD); -- } else { -- rcntl &= ~FEC_ENET_FCE; -+ if (fep->pause_mode & FEC_PAUSE_FLAG_TX) { -+ /* set FIFO threshold parameter to reduce overrun */ -+ writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM); -+ writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL); -+ writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM); -+ writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL); -+ -+ /* OPD */ -+ writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD); -+ } - } - #endif /* !defined(CONFIG_M5272) */ - -@@ -655,14 +736,14 @@ - writel(0, fep->hwp + FEC_HASH_TABLE_LOW); - #endif - -- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { -+ if (fep->quirks & FEC_QUIRK_ENET_MAC) { - /* enable ENET endian swap */ - ecntl |= (1 << 8); - /* enable ENET store and forward mode */ - writel(1 << 8, fep->hwp + FEC_X_WMRK); - } - -- if (fep->bufdesc_ex) -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) - ecntl |= (1 << 4); - - #ifndef CONFIG_M5272 -@@ -674,26 +755,17 @@ - writel(ecntl, fep->hwp + FEC_ECNTRL); - writel(0, fep->hwp + FEC_R_DES_ACTIVE); - -- if (fep->bufdesc_ex) -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) - fec_ptp_start_cyclecounter(ndev); - - /* Enable interrupts we wish to service */ - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); -- -- if (netif_running(ndev)) { -- netif_tx_unlock_bh(ndev); -- netif_wake_queue(ndev); -- napi_enable(&fep->napi); -- netif_device_attach(ndev); -- } - } - - static void - fec_stop(struct net_device *ndev) - { - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); - u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); - - /* We cannot expect a graceful transmit stop without link !!! */ -@@ -711,7 +783,7 @@ - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); - - /* We have to keep ENET enabled to have MII interrupt stay working */ -- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { -+ if (fep->quirks & FEC_QUIRK_ENET_MAC) { - writel(2, fep->hwp + FEC_ECNTRL); - writel(rmii_mode, fep->hwp + FEC_R_CNTRL); - } -@@ -723,127 +795,312 @@ - { - struct fec_enet_private *fep = netdev_priv(ndev); - -+ fec_dump(ndev); -+ - ndev->stats.tx_errors++; - -- fep->delay_work.timeout = true; -- schedule_delayed_work(&(fep->delay_work.delay_work), 0); -+ schedule_work(&fep->tx_timeout_work); - } - --static void fec_enet_work(struct work_struct *work) -+static void fec_enet_timeout_work(struct work_struct *work) - { - struct fec_enet_private *fep = -- container_of(work, -- struct fec_enet_private, -- delay_work.delay_work.work); -- -- if (fep->delay_work.timeout) { -- fep->delay_work.timeout = false; -- fec_restart(fep->netdev, fep->full_duplex); -- netif_wake_queue(fep->netdev); -- } -+ container_of(work, struct fec_enet_private, tx_timeout_work); -+ struct net_device *ndev = fep->netdev; - -- if (fep->delay_work.trig_tx) { -- fep->delay_work.trig_tx = false; -- writel(0, fep->hwp + FEC_X_DES_ACTIVE); -+ rtnl_lock(); -+ if (netif_device_present(ndev) || netif_running(ndev)) { -+ mutex_lock(&fep->mutex); -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(ndev); -+ fec_restart(ndev); -+ netif_wake_queue(ndev); -+ netif_tx_unlock_bh(ndev); -+ napi_enable(&fep->napi); -+ mutex_unlock(&fep->mutex); - } -+ rtnl_unlock(); - } - - static void -+fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts, -+ struct skb_shared_hwtstamps *hwtstamps) -+{ -+ unsigned long flags; -+ u64 ns; -+ -+ spin_lock_irqsave(&fep->tmreg_lock, flags); -+ ns = timecounter_cyc2time(&fep->tc, ts); -+ spin_unlock_irqrestore(&fep->tmreg_lock, flags); -+ -+ memset(hwtstamps, 0, sizeof(*hwtstamps)); -+ hwtstamps->hwtstamp = ns_to_ktime(ns); -+} -+ -+static void noinline - fec_enet_tx(struct net_device *ndev) - { -- struct fec_enet_private *fep; -- struct bufdesc *bdp; -- unsigned short status; -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ union bufdesc_u *bdp; - struct sk_buff *skb; -- int index = 0; -- -- fep = netdev_priv(ndev); -- bdp = fep->dirty_tx; -+ unsigned index = fep->tx_dirty; -+ unsigned pkts_compl, bytes_compl; - -- /* get next bdp of dirty_tx */ -- bdp = fec_enet_get_nextdesc(bdp, fep); -+ pkts_compl = bytes_compl = 0; -+ do { -+ unsigned status, cbd_esc; - -- while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { -+ if (++index >= fep->tx_ring_size) -+ index = 0; - - /* current queue is empty */ -- if (bdp == fep->cur_tx) -+ if (index == fep->tx_next) - break; - -- if (fep->bufdesc_ex) -- index = (struct bufdesc_ex *)bdp - -- (struct bufdesc_ex *)fep->tx_bd_base; -- else -- index = bdp - fep->tx_bd_base; -+ bdp = fec_enet_tx_get(index, fep); -+ -+ status = bdp->bd.cbd_sc; -+ if (status & BD_ENET_TX_READY) -+ break; -+ -+ fec_enet_tx_unmap(index, bdp, fep); - - skb = fep->tx_skbuff[index]; -- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, skb->len, -- DMA_TO_DEVICE); -- bdp->cbd_bufaddr = 0; -+ fep->tx_skbuff[index] = NULL; - - /* Check for errors. */ -- if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | -- BD_ENET_TX_RL | BD_ENET_TX_UN | -- BD_ENET_TX_CSL)) { -- ndev->stats.tx_errors++; -- if (status & BD_ENET_TX_HB) /* No heartbeat */ -- ndev->stats.tx_heartbeat_errors++; -- if (status & BD_ENET_TX_LC) /* Late collision */ -- ndev->stats.tx_window_errors++; -- if (status & BD_ENET_TX_RL) /* Retrans limit */ -- ndev->stats.tx_aborted_errors++; -- if (status & BD_ENET_TX_UN) /* Underrun */ -- ndev->stats.tx_fifo_errors++; -- if (status & BD_ENET_TX_CSL) /* Carrier lost */ -- ndev->stats.tx_carrier_errors++; -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { -+ cbd_esc = bdp->ebd.cbd_esc; -+ if (cbd_esc & BD_ENET_TX_TXE) { -+ ndev->stats.tx_errors++; -+ if (cbd_esc & BD_ENET_TX_EE) { /* excess collision */ -+ ndev->stats.collisions += 16; -+ ndev->stats.tx_aborted_errors++; -+ } -+ if (cbd_esc & BD_ENET_TX_LCE) /* late collision error */ -+ ndev->stats.tx_window_errors++; -+ if (cbd_esc & (BD_ENET_TX_UE | BD_ENET_TX_FE | BD_ENET_TX_OE)) -+ ndev->stats.tx_fifo_errors++; -+ goto next; -+ } - } else { -- ndev->stats.tx_packets++; -- ndev->stats.tx_bytes += bdp->cbd_datlen; -+ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | -+ BD_ENET_TX_RL | BD_ENET_TX_UN | -+ BD_ENET_TX_CSL)) { -+ ndev->stats.tx_errors++; -+ if (status & BD_ENET_TX_HB) /* No heartbeat */ -+ ndev->stats.tx_heartbeat_errors++; -+ if (status & BD_ENET_TX_LC) /* Late collision */ -+ ndev->stats.tx_window_errors++; -+ if (status & BD_ENET_TX_RL) /* Retrans limit */ -+ ndev->stats.tx_aborted_errors++; -+ if (status & BD_ENET_TX_UN) /* Underrun */ -+ ndev->stats.tx_fifo_errors++; -+ if (status & BD_ENET_TX_CSL) /* Carrier lost */ -+ ndev->stats.tx_carrier_errors++; -+ goto next; -+ } - } - -- if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) && -- fep->bufdesc_ex) { -- struct skb_shared_hwtstamps shhwtstamps; -- unsigned long flags; -- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -- -- memset(&shhwtstamps, 0, sizeof(shhwtstamps)); -- spin_lock_irqsave(&fep->tmreg_lock, flags); -- shhwtstamps.hwtstamp = ns_to_ktime( -- timecounter_cyc2time(&fep->tc, ebdp->ts)); -- spin_unlock_irqrestore(&fep->tmreg_lock, flags); -- skb_tstamp_tx(skb, &shhwtstamps); -+ if (skb) { -+ ndev->stats.tx_packets++; -+ ndev->stats.tx_bytes += skb->len; - } - -- if (status & BD_ENET_TX_READY) -- netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n"); -- - /* Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (status & BD_ENET_TX_DEF) - ndev->stats.collisions++; -+ next: -+ if (skb) { -+ if (fep->flags & FEC_FLAG_BUFDESC_EX && -+ unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { -+ struct skb_shared_hwtstamps shhwtstamps; - -- /* Free the sk buffer associated with this last transmit */ -- dev_kfree_skb_any(skb); -- fep->tx_skbuff[index] = NULL; -+ fec_enet_hwtstamp(fep, bdp->ebd.ts, &shhwtstamps); -+ skb_tstamp_tx(skb, &shhwtstamps); -+ } - -- fep->dirty_tx = bdp; -+ pkts_compl++; -+ bytes_compl += skb->len; - -- /* Update pointer to next buffer descriptor to be transmitted */ -- bdp = fec_enet_get_nextdesc(bdp, fep); -+ /* Free the sk buffer associated with this last transmit */ -+ dev_kfree_skb_any(skb); -+ } - -- /* Since we have freed up a buffer, the ring is no longer full -- */ -- if (fep->dirty_tx != fep->cur_tx) { -- if (netif_queue_stopped(ndev)) -- netif_wake_queue(ndev); -+ fep->tx_dirty = index; -+ } while (1); -+ -+ netdev_completed_queue(ndev, pkts_compl, bytes_compl); -+ -+ /* ERR006538: Keep the transmitter going */ -+ if (index != fep->tx_next && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0) -+ writel(0, fep->hwp + FEC_X_DES_ACTIVE); -+ -+ if (netif_queue_stopped(ndev) && -+ ring_free(fep->tx_next, fep->tx_dirty, fep->tx_ring_size) >= -+ fep->tx_min) -+ netif_wake_queue(ndev); -+} -+ -+ -+static void -+fec_enet_receive(struct sk_buff *skb, union bufdesc_u *bdp, struct net_device *ndev) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ -+ skb->protocol = eth_type_trans(skb, ndev); -+ -+ /* Get receive timestamp from the skb */ -+ if (fep->hwts_rx_en && fep->flags & FEC_FLAG_BUFDESC_EX) -+ fec_enet_hwtstamp(fep, bdp->ebd.ts, skb_hwtstamps(skb)); -+ -+ if (fep->flags & FEC_FLAG_RX_CSUM) { -+ if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) { -+ /* don't check it */ -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ } else { -+ skb_checksum_none_assert(skb); - } - } -- return; -+ -+ napi_gro_receive(&fep->napi, skb); -+} -+ -+static void -+fec_enet_receive_copy(unsigned pkt_len, unsigned index, union bufdesc_u *bdp, struct net_device *ndev) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ struct sk_buff *skb; -+ unsigned char *data; -+ bool vlan_packet_rcvd = false; -+ -+ /* -+ * Detect the presence of the VLAN tag, and adjust -+ * the packet length appropriately. -+ */ -+ if (fep->flags & FEC_FLAG_RX_VLAN && -+ bdp->ebd.cbd_esc & BD_ENET_RX_VLAN) { -+ pkt_len -= VLAN_HLEN; -+ vlan_packet_rcvd = true; -+ } -+ -+ /* This does 16 byte alignment, exactly what we need. */ -+ skb = netdev_alloc_skb(ndev, pkt_len + NET_IP_ALIGN); -+ if (unlikely(!skb)) { -+ ndev->stats.rx_dropped++; -+ return; -+ } -+ -+ dma_sync_single_for_cpu(&fep->pdev->dev, bdp->bd.cbd_bufaddr, -+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -+ -+ data = fep->rx_skbuff[index]->data; -+ -+#ifndef CONFIG_M5272 -+ /* -+ * If we have enabled this feature, we need to discard -+ * the two bytes at the beginning of the packet before -+ * copying it. -+ */ -+ if (fep->quirks & FEC_QUIRK_RX_SHIFT16) { -+ pkt_len -= 2; -+ data += 2; -+ } -+#endif -+ -+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME) -+ swap_buffer(data, pkt_len); -+ -+ skb_reserve(skb, NET_IP_ALIGN); -+ skb_put(skb, pkt_len); /* Make room */ -+ -+ /* If this is a VLAN packet remove the VLAN Tag */ -+ if (vlan_packet_rcvd) { -+ struct vlan_hdr *vlan = (struct vlan_hdr *)(data + ETH_HLEN); -+ -+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), -+ ntohs(vlan->h_vlan_TCI)); -+ -+ /* Extract the frame data without the VLAN header. */ -+ skb_copy_to_linear_data(skb, data, 2 * ETH_ALEN); -+ skb_copy_to_linear_data_offset(skb, 2 * ETH_ALEN, -+ data + 2 * ETH_ALEN + VLAN_HLEN, -+ pkt_len - 2 * ETH_ALEN); -+ } else { -+ skb_copy_to_linear_data(skb, data, pkt_len); -+ } -+ -+ dma_sync_single_for_device(&fep->pdev->dev, bdp->bd.cbd_bufaddr, -+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -+ -+ fec_enet_receive(skb, bdp, ndev); - } - -+static void -+fec_enet_receive_nocopy(unsigned pkt_len, unsigned index, union bufdesc_u *bdp, -+ struct net_device *ndev) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ struct sk_buff *skb, *skb_new; -+ unsigned char *data; -+ dma_addr_t addr; -+ -+ skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); -+ if (!skb_new) { -+ ndev->stats.rx_dropped++; -+ return; -+ } -+ -+ addr = dma_map_single(&fep->pdev->dev, skb_new->data, -+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -+ if (dma_mapping_error(&fep->pdev->dev, addr)) { -+ dev_kfree_skb(skb_new); -+ ndev->stats.rx_dropped++; -+ return; -+ } - --/* During a receive, the cur_rx points to the current incoming buffer. -+ /* We have the new skb, so proceed to deal with the received data. */ -+ dma_unmap_single(&fep->pdev->dev, bdp->bd.cbd_bufaddr, -+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -+ -+ skb = fep->rx_skbuff[index]; -+ -+ /* Now subsitute in the new skb */ -+ fep->rx_skbuff[index] = skb_new; -+ bdp->bd.cbd_bufaddr = addr; -+ -+ /* -+ * Update the skb length according to the raw packet length. -+ * Then remove the two bytes of additional padding. -+ */ -+ skb_put(skb, pkt_len); -+ data = skb_pull_inline(skb, 2); -+ -+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME) -+ swap_buffer(data, skb->len); -+ -+ /* -+ * Now juggle things for the VLAN tag - if the hardware -+ * flags this as present, we need to read the tag, and -+ * then shuffle the ethernet addresses up. -+ */ -+ if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX && -+ bdp->ebd.cbd_esc & BD_ENET_RX_VLAN) { -+ struct vlan_hdr *vlan = (struct vlan_hdr *)(data + ETH_HLEN); -+ -+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), -+ ntohs(vlan->h_vlan_TCI)); -+ -+ memmove(data + VLAN_HLEN, data, 2 * ETH_ALEN); -+ skb_pull_inline(skb, VLAN_HLEN); -+ } -+ -+ fec_enet_receive(skb, bdp, ndev); -+} -+ -+/* During a receive, the rx_next points to the current incoming buffer. - * When we update through the ring, if the next incoming buffer has - * not been given to the system, we just set the empty indicator, - * effectively tossing the packet. -@@ -852,18 +1109,9 @@ - fec_enet_rx(struct net_device *ndev, int budget) - { - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); -- struct bufdesc *bdp; -- unsigned short status; -- struct sk_buff *skb; - ushort pkt_len; -- __u8 *data; - int pkt_received = 0; -- struct bufdesc_ex *ebdp = NULL; -- bool vlan_packet_rcvd = false; -- u16 vlan_tag; -- int index = 0; -+ unsigned index = fep->rx_next; - - #ifdef CONFIG_M532x - flush_cache_all(); -@@ -872,12 +1120,17 @@ - /* First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ -- bdp = fep->cur_rx; -+ do { -+ union bufdesc_u *bdp = fec_enet_rx_get(index, fep); -+ unsigned status; - -- while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { -+ status = bdp->bd.cbd_sc; -+ if (status & BD_ENET_RX_EMPTY) -+ break; - - if (pkt_received >= budget) - break; -+ - pkt_received++; - - /* Since we have allocated space to hold a complete frame, -@@ -886,155 +1139,81 @@ - if ((status & BD_ENET_RX_LAST) == 0) - netdev_err(ndev, "rcv is not +last\n"); - -- if (!fep->opened) -- goto rx_processing_done; -+ writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); - - /* Check for errors. */ -- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | -- BD_ENET_RX_CR | BD_ENET_RX_OV)) { -+ if (status & BD_ENET_RX_ERROR) { - ndev->stats.rx_errors++; -- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { -- /* Frame too long or too short. */ -- ndev->stats.rx_length_errors++; -- } -- if (status & BD_ENET_RX_NO) /* Frame alignment */ -- ndev->stats.rx_frame_errors++; -- if (status & BD_ENET_RX_CR) /* CRC Error */ -- ndev->stats.rx_crc_errors++; -- if (status & BD_ENET_RX_OV) /* FIFO overrun */ -- ndev->stats.rx_fifo_errors++; -- } - -- /* Report late collisions as a frame error. -- * On this error, the BD is closed, but we don't know what we -- * have in the buffer. So, just drop this frame on the floor. -- */ -- if (status & BD_ENET_RX_CL) { -- ndev->stats.rx_errors++; -- ndev->stats.rx_frame_errors++; -+ /* -+ * Report late collisions as a frame error. On this -+ * error, the BD is closed, but we don't know what we -+ * have in the buffer. So, just drop this frame on -+ * the floor. -+ */ -+ if (status & BD_ENET_RX_CL) { -+ ndev->stats.rx_frame_errors++; -+ } else { -+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) -+ /* Frame too long or too short. */ -+ ndev->stats.rx_length_errors++; -+ if (status & BD_ENET_RX_NO) /* Frame alignment */ -+ ndev->stats.rx_frame_errors++; -+ if (status & BD_ENET_RX_CR) /* CRC Error */ -+ ndev->stats.rx_crc_errors++; -+ if (status & BD_ENET_RX_OV) /* FIFO overrun */ -+ ndev->stats.rx_fifo_errors++; -+ } - goto rx_processing_done; - } - - /* Process the incoming frame. */ - ndev->stats.rx_packets++; -- pkt_len = bdp->cbd_datlen; -- ndev->stats.rx_bytes += pkt_len; -- -- if (fep->bufdesc_ex) -- index = (struct bufdesc_ex *)bdp - -- (struct bufdesc_ex *)fep->rx_bd_base; -- else -- index = bdp - fep->rx_bd_base; -- data = fep->rx_skbuff[index]->data; -- dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr, -- FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -- -- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) -- swap_buffer(data, pkt_len); - -- /* Extract the enhanced buffer descriptor */ -- ebdp = NULL; -- if (fep->bufdesc_ex) -- ebdp = (struct bufdesc_ex *)bdp; -- -- /* If this is a VLAN packet remove the VLAN Tag */ -- vlan_packet_rcvd = false; -- if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) && -- fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) { -- /* Push and remove the vlan tag */ -- struct vlan_hdr *vlan_header = -- (struct vlan_hdr *) (data + ETH_HLEN); -- vlan_tag = ntohs(vlan_header->h_vlan_TCI); -- pkt_len -= VLAN_HLEN; -- -- vlan_packet_rcvd = true; -- } -- -- /* This does 16 byte alignment, exactly what we need. -- * The packet length includes FCS, but we don't want to -- * include that when passing upstream as it messes up -- * bridging applications. -+ /* -+ * The packet length includes FCS, but we don't want -+ * to include that when passing upstream as it messes -+ * up bridging applications. - */ -- skb = netdev_alloc_skb(ndev, pkt_len - 4 + NET_IP_ALIGN); -+ pkt_len = bdp->bd.cbd_datlen - 4; -+ ndev->stats.rx_bytes += pkt_len; - -- if (unlikely(!skb)) { -- ndev->stats.rx_dropped++; -+ if (fec_enet_rx_zerocopy(fep, pkt_len)) { -+ fec_enet_receive_nocopy(pkt_len, index, bdp, ndev); - } else { -- int payload_offset = (2 * ETH_ALEN); -- skb_reserve(skb, NET_IP_ALIGN); -- skb_put(skb, pkt_len - 4); /* Make room */ -- -- /* Extract the frame data without the VLAN header. */ -- skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN)); -- if (vlan_packet_rcvd) -- payload_offset = (2 * ETH_ALEN) + VLAN_HLEN; -- skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN), -- data + payload_offset, -- pkt_len - 4 - (2 * ETH_ALEN)); -- -- skb->protocol = eth_type_trans(skb, ndev); -- -- /* Get receive timestamp from the skb */ -- if (fep->hwts_rx_en && fep->bufdesc_ex) { -- struct skb_shared_hwtstamps *shhwtstamps = -- skb_hwtstamps(skb); -- unsigned long flags; -- -- memset(shhwtstamps, 0, sizeof(*shhwtstamps)); -- -- spin_lock_irqsave(&fep->tmreg_lock, flags); -- shhwtstamps->hwtstamp = ns_to_ktime( -- timecounter_cyc2time(&fep->tc, ebdp->ts)); -- spin_unlock_irqrestore(&fep->tmreg_lock, flags); -- } -- -- if (fep->bufdesc_ex && -- (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { -- if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { -- /* don't check it */ -- skb->ip_summed = CHECKSUM_UNNECESSARY; -- } else { -- skb_checksum_none_assert(skb); -- } -- } -- -- /* Handle received VLAN packets */ -- if (vlan_packet_rcvd) -- __vlan_hwaccel_put_tag(skb, -- htons(ETH_P_8021Q), -- vlan_tag); -- -- napi_gro_receive(&fep->napi, skb); -+ fec_enet_receive_copy(pkt_len, index, bdp, ndev); - } - -- dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr, -- FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); - rx_processing_done: -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { -+ bdp->ebd.cbd_esc = BD_ENET_RX_INT; -+ bdp->ebd.cbd_prot = 0; -+ bdp->ebd.cbd_bdu = 0; -+ } -+ -+ /* -+ * Ensure that the previous writes have completed before -+ * the status update becomes visible. -+ */ -+ wmb(); -+ - /* Clear the status flags for this buffer */ - status &= ~BD_ENET_RX_STATS; - - /* Mark the buffer empty */ - status |= BD_ENET_RX_EMPTY; -- bdp->cbd_sc = status; -- -- if (fep->bufdesc_ex) { -- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -- -- ebdp->cbd_esc = BD_ENET_RX_INT; -- ebdp->cbd_prot = 0; -- ebdp->cbd_bdu = 0; -- } -- -- /* Update BD pointer to next entry */ -- bdp = fec_enet_get_nextdesc(bdp, fep); -+ bdp->bd.cbd_sc = status; - - /* Doing this here will keep the FEC running while we process - * incoming frames. On a heavily loaded network, we should be - * able to keep up at the expense of system resources. - */ - writel(0, fep->hwp + FEC_R_DES_ACTIVE); -- } -- fep->cur_rx = bdp; -+ -+ if (++index >= fep->rx_ring_size) -+ index = 0; -+ } while (1); -+ fep->rx_next = index; - - return pkt_received; - } -@@ -1044,29 +1223,25 @@ - { - struct net_device *ndev = dev_id; - struct fec_enet_private *fep = netdev_priv(ndev); -+ const unsigned napi_mask = FEC_ENET_RXF | FEC_ENET_TXF; - uint int_events; - irqreturn_t ret = IRQ_NONE; - -- do { -- int_events = readl(fep->hwp + FEC_IEVENT); -- writel(int_events, fep->hwp + FEC_IEVENT); -+ int_events = readl(fep->hwp + FEC_IEVENT); -+ writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT); - -- if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) { -- ret = IRQ_HANDLED; -+ if (int_events & napi_mask) { -+ ret = IRQ_HANDLED; - -- /* Disable the RX interrupt */ -- if (napi_schedule_prep(&fep->napi)) { -- writel(FEC_RX_DISABLED_IMASK, -- fep->hwp + FEC_IMASK); -- __napi_schedule(&fep->napi); -- } -- } -+ /* Disable the NAPI interrupts */ -+ writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); -+ napi_schedule(&fep->napi); -+ } - -- if (int_events & FEC_ENET_MII) { -- ret = IRQ_HANDLED; -- complete(&fep->mdio_done); -- } -- } while (int_events); -+ if (int_events & FEC_ENET_MII) { -+ ret = IRQ_HANDLED; -+ complete(&fep->mdio_done); -+ } - - return ret; - } -@@ -1074,8 +1249,16 @@ - static int fec_enet_rx_napi(struct napi_struct *napi, int budget) - { - struct net_device *ndev = napi->dev; -- int pkts = fec_enet_rx(ndev, budget); - struct fec_enet_private *fep = netdev_priv(ndev); -+ int pkts; -+ -+ /* -+ * Clear any pending transmit or receive interrupts before -+ * processing the rings to avoid racing with the hardware. -+ */ -+ writel(FEC_ENET_RXF | FEC_ENET_TXF, fep->hwp + FEC_IEVENT); -+ -+ pkts = fec_enet_rx(ndev, budget); - - fec_enet_tx(ndev); - -@@ -1173,26 +1356,78 @@ - return; - } - -- if (phy_dev->link) { -+ /* -+ * If the netdev is down, or is going down, we're not interested -+ * in link state events, so just mark our idea of the link as down -+ * and ignore the event. -+ */ -+ if (!netif_running(ndev) || !netif_device_present(ndev)) { -+ fep->link = 0; -+ } else if (phy_dev->link) { - if (!fep->link) { - fep->link = phy_dev->link; - status_change = 1; - } - -- if (fep->full_duplex != phy_dev->duplex) -+ if (fep->full_duplex != phy_dev->duplex) { -+ fep->full_duplex = phy_dev->duplex; - status_change = 1; -+ } - - if (phy_dev->speed != fep->speed) { - fep->speed = phy_dev->speed; - status_change = 1; - } - -+ if (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) { -+ u32 lcl_adv = phy_dev->advertising; -+ u32 rmt_adv = phy_dev->lp_advertising; -+ unsigned mode = 0; -+ -+ if (lcl_adv & rmt_adv & ADVERTISED_Pause) { -+ /* -+ * Local Device Link Partner -+ * Pause AsymDir Pause AsymDir Result -+ * 1 X 1 X TX+RX -+ */ -+ mode = FEC_PAUSE_FLAG_TX | FEC_PAUSE_FLAG_RX; -+ } else if (lcl_adv & rmt_adv & ADVERTISED_Asym_Pause) { -+ /* -+ * 0 1 1 1 RX -+ * 1 1 0 1 TX -+ */ -+ if (rmt_adv & ADVERTISED_Pause) -+ mode = FEC_PAUSE_FLAG_RX; -+ else -+ mode = FEC_PAUSE_FLAG_TX; -+ } -+ -+ if (mode != fep->pause_mode) { -+ fep->pause_mode = mode; -+ status_change = 1; -+ } -+ } -+ - /* if any of the above changed restart the FEC */ -- if (status_change) -- fec_restart(ndev, phy_dev->duplex); -+ if (status_change) { -+ mutex_lock(&fep->mutex); -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(ndev); -+ fec_restart(ndev); -+ netif_wake_queue(ndev); -+ netif_tx_unlock_bh(ndev); -+ napi_enable(&fep->napi); -+ mutex_unlock(&fep->mutex); -+ } - } else { - if (fep->link) { -+ mutex_lock(&fep->mutex); -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(ndev); - fec_stop(ndev); -+ netif_tx_unlock_bh(ndev); -+ napi_enable(&fep->napi); -+ mutex_unlock(&fep->mutex); - fep->link = phy_dev->link; - status_change = 1; - } -@@ -1202,23 +1437,35 @@ - phy_print_status(phy_dev); - } - --static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -+static unsigned long fec_enet_mdio_op(struct fec_enet_private *fep, -+ unsigned data) - { -- struct fec_enet_private *fep = bus->priv; - unsigned long time_left; - - fep->mii_timeout = 0; - init_completion(&fep->mdio_done); - -- /* start a read op */ -- writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | -- FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | -- FEC_MMFR_TA, fep->hwp + FEC_MII_DATA); -+ mutex_lock(&fep->mutex); -+ -+ /* start operation */ -+ writel(data, fep->hwp + FEC_MII_DATA); - - /* wait for end of transfer */ - time_left = wait_for_completion_timeout(&fep->mdio_done, - usecs_to_jiffies(FEC_MII_TIMEOUT)); -- if (time_left == 0) { -+ -+ mutex_unlock(&fep->mutex); -+ -+ return time_left; -+} -+ -+static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -+{ -+ struct fec_enet_private *fep = bus->priv; -+ -+ if (fec_enet_mdio_op(fep, FEC_MMFR_ST | FEC_MMFR_OP_READ | -+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | -+ FEC_MMFR_TA) == 0) { - fep->mii_timeout = 1; - netdev_err(fep->netdev, "MDIO read timeout\n"); - return -ETIMEDOUT; -@@ -1232,21 +1479,10 @@ - u16 value) - { - struct fec_enet_private *fep = bus->priv; -- unsigned long time_left; -- -- fep->mii_timeout = 0; -- init_completion(&fep->mdio_done); -- -- /* start a write op */ -- writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE | -- FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | -- FEC_MMFR_TA | FEC_MMFR_DATA(value), -- fep->hwp + FEC_MII_DATA); - -- /* wait for end of transfer */ -- time_left = wait_for_completion_timeout(&fep->mdio_done, -- usecs_to_jiffies(FEC_MII_TIMEOUT)); -- if (time_left == 0) { -+ if (fec_enet_mdio_op(fep, FEC_MMFR_ST | FEC_MMFR_OP_WRITE | -+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | -+ FEC_MMFR_TA | FEC_MMFR_DATA(value)) == 0) { - fep->mii_timeout = 1; - netdev_err(fep->netdev, "MDIO write timeout\n"); - return -ETIMEDOUT; -@@ -1255,11 +1491,37 @@ - return 0; - } - -+static void fec_enet_phy_config(struct net_device *ndev) -+{ -+#ifndef CONFIG_M5272 -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ struct phy_device *phy = fep->phy_dev; -+ unsigned pause = 0; -+ -+ /* -+ * Pause advertisment logic is weird. We don't advertise the raw -+ * "can tx" and "can rx" modes, but instead it is whether we support -+ * symmetric flow or asymmetric flow. -+ * -+ * Symmetric flow means we can only support both transmit and receive -+ * flow control frames together. Asymmetric flow means we can -+ * independently control each. Note that there is no bit encoding -+ * for "I can only receive flow control frames." -+ */ -+ if (fep->pause_flag & FEC_PAUSE_FLAG_RX) -+ pause |= ADVERTISED_Asym_Pause | ADVERTISED_Pause; -+ if (fep->pause_flag & FEC_PAUSE_FLAG_TX) -+ pause |= ADVERTISED_Asym_Pause; -+ -+ pause &= phy->supported; -+ pause |= phy->advertising & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); -+ phy->advertising = pause; -+#endif -+} -+ - static int fec_enet_mii_probe(struct net_device *ndev) - { - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); - struct phy_device *phy_dev = NULL; - char mdio_bus_id[MII_BUS_ID_SIZE]; - char phy_name[MII_BUS_ID_SIZE + 3]; -@@ -1297,10 +1559,11 @@ - } - - /* mask with MAC supported features */ -- if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) { -+ if (fep->quirks & FEC_QUIRK_HAS_GBIT) { - phy_dev->supported &= PHY_GBIT_FEATURES; -+ phy_dev->supported &= ~SUPPORTED_1000baseT_Half; - #if !defined(CONFIG_M5272) -- phy_dev->supported |= SUPPORTED_Pause; -+ phy_dev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - #endif - } - else -@@ -1312,6 +1575,8 @@ - fep->link = 0; - fep->full_duplex = 0; - -+ fec_enet_phy_config(ndev); -+ - netdev_info(ndev, "Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), - fep->phy_dev->irq); -@@ -1324,8 +1589,6 @@ - static struct mii_bus *fec0_mii_bus; - struct net_device *ndev = platform_get_drvdata(pdev); - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); - int err = -ENXIO, i; - - /* -@@ -1344,7 +1607,7 @@ - * mdio interface in board design, and need to be configured by - * fec0 mii_bus. - */ -- if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { -+ if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { - /* fec1 uses fec0 mii_bus */ - if (mii_cnt && fec0_mii_bus) { - fep->mii_bus = fec0_mii_bus; -@@ -1365,7 +1628,7 @@ - * document. - */ - fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ahb), 5000000); -- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) -+ if (fep->quirks & FEC_QUIRK_ENET_MAC) - fep->phy_speed--; - fep->phy_speed <<= 1; - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); -@@ -1399,7 +1662,7 @@ - mii_cnt++; - - /* save fec0 mii_bus */ -- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) -+ if (fep->quirks & FEC_QUIRK_ENET_MAC) - fec0_mii_bus = fep->mii_bus; - - return 0; -@@ -1461,7 +1724,7 @@ - { - struct fec_enet_private *fep = netdev_priv(ndev); - -- if (fep->bufdesc_ex) { -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { - - info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | -@@ -1485,6 +1748,51 @@ - } - } - -+static void fec_enet_get_ringparam(struct net_device *ndev, -+ struct ethtool_ringparam *ring) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ -+ ring->rx_max_pending = RX_RING_SIZE; -+ ring->tx_max_pending = TX_RING_SIZE; -+ ring->rx_pending = fep->rx_ring_size; -+ ring->tx_pending = fep->tx_ring_size; -+} -+ -+static int fec_enet_set_ringparam(struct net_device *ndev, -+ struct ethtool_ringparam *ring) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ unsigned rx, tx, tx_min; -+ -+ tx_min = ndev->features & NETIF_F_SG ? TX_RING_SIZE_MIN_SG : 16; -+ -+ rx = clamp_t(u32, ring->rx_pending, 16, RX_RING_SIZE); -+ tx = clamp_t(u32, ring->tx_pending, tx_min, TX_RING_SIZE); -+ -+ if (tx == fep->tx_ring_size && rx == fep->rx_ring_size) -+ return 0; -+ -+ /* Setting the ring size while the interface is down is easy */ -+ if (!netif_running(ndev)) { -+ fep->tx_ring_size = tx; -+ fep->rx_ring_size = rx; -+ } else { -+ return -EINVAL; -+ -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(ndev); -+ fec_stop(ndev); -+ /* reallocate ring */ -+ fec_restart(ndev); -+ netif_wake_queue(ndev); -+ netif_tx_unlock_bh(ndev); -+ napi_enable(&fep->napi); -+ } -+ -+ return 0; -+} -+ - #if !defined(CONFIG_M5272) - - static void fec_enet_get_pauseparam(struct net_device *ndev, -@@ -1493,42 +1801,81 @@ - struct fec_enet_private *fep = netdev_priv(ndev); - - pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0; -- pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0; -- pause->rx_pause = pause->tx_pause; -+ pause->rx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_RX) != 0; -+ pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_TX) != 0; - } - - static int fec_enet_set_pauseparam(struct net_device *ndev, - struct ethtool_pauseparam *pause) - { - struct fec_enet_private *fep = netdev_priv(ndev); -+ unsigned pause_flag, changed; -+ struct phy_device *phy = fep->phy_dev; - -- if (pause->tx_pause != pause->rx_pause) { -- netdev_info(ndev, -- "hardware only support enable/disable both tx and rx"); -+ if (!phy) -+ return -ENODEV; -+ if (!(phy->supported & SUPPORTED_Pause)) -+ return -EINVAL; -+ if (!(phy->supported & SUPPORTED_Asym_Pause) && -+ pause->rx_pause != pause->tx_pause) - return -EINVAL; -- } - -- fep->pause_flag = 0; -+ pause_flag = 0; -+ if (pause->autoneg) -+ pause_flag |= FEC_PAUSE_FLAG_AUTONEG; -+ if (pause->rx_pause) -+ pause_flag |= FEC_PAUSE_FLAG_RX; -+ if (pause->tx_pause) -+ pause_flag |= FEC_PAUSE_FLAG_TX; -+ -+ changed = fep->pause_flag ^ pause_flag; -+ fep->pause_flag = pause_flag; -+ -+ /* configure the phy advertisment according to our new options */ -+ fec_enet_phy_config(ndev); -+ -+ if (changed) { -+ if (pause_flag & FEC_PAUSE_FLAG_AUTONEG) { -+ if (netif_running(ndev)) -+ phy_start_aneg(fep->phy_dev); -+ } else { -+ int adv, old_adv; - -- /* tx pause must be same as rx pause */ -- fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0; -- fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0; -- -- if (pause->rx_pause || pause->autoneg) { -- fep->phy_dev->supported |= ADVERTISED_Pause; -- fep->phy_dev->advertising |= ADVERTISED_Pause; -- } else { -- fep->phy_dev->supported &= ~ADVERTISED_Pause; -- fep->phy_dev->advertising &= ~ADVERTISED_Pause; -- } -+ /* -+ * Even if we are not in autonegotiate mode, we -+ * still update the phy with our capabilities so -+ * our link parter can make the appropriate -+ * decision. PHYLIB provides no way to do this. -+ */ -+ adv = phy_read(phy, MII_ADVERTISE); -+ if (adv >= 0) { -+ old_adv = adv; -+ adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); -+ if (phy->advertising & ADVERTISED_Pause) -+ adv |= ADVERTISE_PAUSE_CAP; -+ if (phy->advertising & ADVERTISED_Asym_Pause) -+ adv |= ADVERTISE_PAUSE_ASYM; - -- if (pause->autoneg) { -- if (netif_running(ndev)) -- fec_stop(ndev); -- phy_start_aneg(fep->phy_dev); -+ if (old_adv != adv) -+ phy_write(phy, MII_ADVERTISE, adv); -+ } -+ -+ /* Forced pause mode */ -+ fep->pause_mode = fep->pause_flag; -+ -+ if (netif_running(ndev)) { -+ mutex_lock(&fep->mutex); -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(ndev); -+ fec_stop(ndev); -+ fec_restart(ndev); -+ netif_wake_queue(ndev); -+ netif_tx_unlock_bh(ndev); -+ napi_enable(&fep->napi); -+ mutex_unlock(&fep->mutex); -+ } -+ } - } -- if (netif_running(ndev)) -- fec_restart(ndev, 0); - - return 0; - } -@@ -1645,21 +1992,21 @@ - } - - static const struct ethtool_ops fec_enet_ethtool_ops = { --#if !defined(CONFIG_M5272) -- .get_pauseparam = fec_enet_get_pauseparam, -- .set_pauseparam = fec_enet_set_pauseparam, --#endif - .get_settings = fec_enet_get_settings, - .set_settings = fec_enet_set_settings, - .get_drvinfo = fec_enet_get_drvinfo, -- .get_link = ethtool_op_get_link, -- .get_ts_info = fec_enet_get_ts_info, - .nway_reset = fec_enet_nway_reset, -+ .get_link = ethtool_op_get_link, -+ .get_ringparam = fec_enet_get_ringparam, -+ .set_ringparam = fec_enet_set_ringparam, - #ifndef CONFIG_M5272 -- .get_ethtool_stats = fec_enet_get_ethtool_stats, -+ .get_pauseparam = fec_enet_get_pauseparam, -+ .set_pauseparam = fec_enet_set_pauseparam, - .get_strings = fec_enet_get_strings, -+ .get_ethtool_stats = fec_enet_get_ethtool_stats, - .get_sset_count = fec_enet_get_sset_count, - #endif -+ .get_ts_info = fec_enet_get_ts_info, - }; - - static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -@@ -1673,7 +2020,7 @@ - if (!phydev) - return -ENODEV; - -- if (fep->bufdesc_ex) { -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { - if (cmd == SIOCSHWTSTAMP) - return fec_ptp_set(ndev, rq); - if (cmd == SIOCGHWTSTAMP) -@@ -1688,23 +2035,33 @@ - struct fec_enet_private *fep = netdev_priv(ndev); - unsigned int i; - struct sk_buff *skb; -- struct bufdesc *bdp; -+ union bufdesc_u *bdp; - -- bdp = fep->rx_bd_base; - for (i = 0; i < fep->rx_ring_size; i++) { -- skb = fep->rx_skbuff[i]; -+ bdp = fec_enet_rx_get(i, fep); - -- if (bdp->cbd_bufaddr) -- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, -+ skb = fep->rx_skbuff[i]; -+ fep->rx_skbuff[i] = NULL; -+ if (skb) { -+ dma_unmap_single(&fep->pdev->dev, bdp->bd.cbd_bufaddr, - FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -- if (skb) - dev_kfree_skb(skb); -- bdp = fec_enet_get_nextdesc(bdp, fep); -+ } - } - -- bdp = fep->tx_bd_base; -- for (i = 0; i < fep->tx_ring_size; i++) -+ for (i = 0; i < fep->tx_ring_size; i++) { -+ bdp = fec_enet_tx_get(i, fep); -+ if (bdp->bd.cbd_bufaddr) -+ fec_enet_tx_unmap(i, bdp, fep); - kfree(fep->tx_bounce[i]); -+ fep->tx_bounce[i] = NULL; -+ skb = fep->tx_skbuff[i]; -+ fep->tx_skbuff[i] = NULL; -+ if (skb) -+ dev_kfree_skb(skb); -+ } -+ -+ dma_free_coherent(NULL, PAGE_SIZE, fep->rx_bd_base, fep->rx_bd_dma); - } - - static int fec_enet_alloc_buffers(struct net_device *ndev) -@@ -1712,59 +2069,82 @@ - struct fec_enet_private *fep = netdev_priv(ndev); - unsigned int i; - struct sk_buff *skb; -- struct bufdesc *bdp; -+ union bufdesc_u *bdp; -+ union bufdesc_u *rx_cbd_cpu, *tx_cbd_cpu; -+ dma_addr_t rx_cbd_dma, tx_cbd_dma; -+ -+ /* Allocate memory for buffer descriptors. */ -+ rx_cbd_cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &rx_cbd_dma, -+ GFP_KERNEL); -+ tx_cbd_cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &tx_cbd_dma, -+ GFP_KERNEL); -+ if (!rx_cbd_cpu || !tx_cbd_cpu) { -+ if (rx_cbd_cpu) -+ dma_free_coherent(NULL, PAGE_SIZE, rx_cbd_cpu, rx_cbd_dma); -+ if (tx_cbd_cpu) -+ dma_free_coherent(NULL, PAGE_SIZE, tx_cbd_cpu, tx_cbd_dma); -+ return -ENOMEM; -+ } -+ -+ memset(rx_cbd_cpu, 0, PAGE_SIZE); -+ memset(tx_cbd_cpu, 0, PAGE_SIZE); -+ -+ /* Set receive and transmit descriptor base. */ -+ fep->rx_bd_base = rx_cbd_cpu; -+ fep->rx_bd_dma = rx_cbd_dma; -+ fep->tx_bd_base = tx_cbd_cpu; -+ fep->tx_bd_dma = tx_cbd_dma; - -- bdp = fep->rx_bd_base; - for (i = 0; i < fep->rx_ring_size; i++) { -+ dma_addr_t addr; -+ - skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); -- if (!skb) { -- fec_enet_free_buffers(ndev); -- return -ENOMEM; -- } -- fep->rx_skbuff[i] = skb; -+ if (!skb) -+ goto err_alloc; - -- bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, -+ addr = dma_map_single(&fep->pdev->dev, skb->data, - FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); -- if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { -- fec_enet_free_buffers(ndev); -+ if (dma_mapping_error(&fep->pdev->dev, addr)) { -+ dev_kfree_skb(skb); - if (net_ratelimit()) - netdev_err(ndev, "Rx DMA memory map failed\n"); -- return -ENOMEM; -+ goto err_alloc; - } -- bdp->cbd_sc = BD_ENET_RX_EMPTY; - -- if (fep->bufdesc_ex) { -- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -- ebdp->cbd_esc = BD_ENET_RX_INT; -- } -+ fep->rx_skbuff[i] = skb; -+ bdp = fec_enet_rx_get(i, fep); -+ bdp->bd.cbd_bufaddr = addr; -+ bdp->bd.cbd_sc = BD_ENET_RX_EMPTY; -+ /* Set the last buffer to wrap. */ -+ if (i == fep->rx_ring_size - 1) -+ bdp->bd.cbd_sc |= BD_SC_WRAP; - -- bdp = fec_enet_get_nextdesc(bdp, fep); -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) -+ bdp->ebd.cbd_esc = BD_ENET_RX_INT; - } - -- /* Set the last buffer to wrap. */ -- bdp = fec_enet_get_prevdesc(bdp, fep); -- bdp->cbd_sc |= BD_SC_WRAP; -- -- bdp = fep->tx_bd_base; - for (i = 0; i < fep->tx_ring_size; i++) { -+ bdp = fec_enet_tx_get(i, fep); - fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); -+ if (!fep->tx_bounce[i]) -+ goto err_alloc; - -- bdp->cbd_sc = 0; -- bdp->cbd_bufaddr = 0; -- -- if (fep->bufdesc_ex) { -- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -- ebdp->cbd_esc = BD_ENET_TX_INT; -- } -+ /* Set the last buffer to wrap. */ -+ if (i == fep->tx_ring_size - 1) -+ bdp->bd.cbd_sc = BD_SC_WRAP; -+ else -+ bdp->bd.cbd_sc = 0; -+ bdp->bd.cbd_bufaddr = 0; - -- bdp = fec_enet_get_nextdesc(bdp, fep); -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) -+ bdp->ebd.cbd_esc = BD_ENET_TX_INT; - } - -- /* Set the last buffer to wrap. */ -- bdp = fec_enet_get_prevdesc(bdp, fep); -- bdp->cbd_sc |= BD_SC_WRAP; -- - return 0; -+ -+ err_alloc: -+ fec_enet_free_buffers(ndev); -+ return -ENOMEM; - } - - static int -@@ -1788,10 +2168,12 @@ - return ret; - } - -+ mutex_lock(&fep->mutex); -+ fec_restart(ndev); -+ mutex_unlock(&fep->mutex); - napi_enable(&fep->napi); - phy_start(fep->phy_dev); - netif_start_queue(ndev); -- fep->opened = 1; - return 0; - } - -@@ -1800,17 +2182,19 @@ - { - struct fec_enet_private *fep = netdev_priv(ndev); - -- /* Don't know what to do yet. */ -- napi_disable(&fep->napi); -- fep->opened = 0; -- netif_stop_queue(ndev); -- fec_stop(ndev); -+ phy_stop(fep->phy_dev); - -- if (fep->phy_dev) { -- phy_stop(fep->phy_dev); -- phy_disconnect(fep->phy_dev); -+ if (netif_device_present(ndev)) { -+ napi_disable(&fep->napi); -+ netif_tx_disable(ndev); -+ mutex_lock(&fep->mutex); -+ fec_stop(ndev); -+ mutex_unlock(&fep->mutex); - } - -+ phy_disconnect(fep->phy_dev); -+ fep->phy_dev = NULL; -+ - fec_enet_free_buffers(ndev); - - return 0; -@@ -1935,28 +2319,67 @@ - } - #endif - -+static netdev_features_t fec_fix_features(struct net_device *ndev, -+ netdev_features_t features) -+{ -+ struct fec_enet_private *fep = netdev_priv(ndev); -+ -+ /* -+ * NETIF_F_SG requires a minimum transmit ring size. If we -+ * have less than this size, we can't support this feature. -+ */ -+ if (fep->tx_ring_size < TX_RING_SIZE_MIN_SG) -+ features &= ~NETIF_F_SG; -+ -+ return features; -+} -+ -+#define FEATURES_NEED_QUIESCE (NETIF_F_RXCSUM | NETIF_F_SG) -+ - static int fec_set_features(struct net_device *netdev, - netdev_features_t features) - { - struct fec_enet_private *fep = netdev_priv(netdev); - netdev_features_t changed = features ^ netdev->features; - -+ /* Quiesce the device if necessary */ -+ if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) { -+ mutex_lock(&fep->mutex); -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(netdev); -+ fec_stop(netdev); -+ } -+ - netdev->features = features; - - /* Receive checksum has been changed */ - if (changed & NETIF_F_RXCSUM) { - if (features & NETIF_F_RXCSUM) -- fep->csum_flags |= FLAG_RX_CSUM_ENABLED; -+ fep->flags |= FEC_FLAG_RX_CSUM; - else -- fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED; -+ fep->flags &= ~FEC_FLAG_RX_CSUM; -+ } - -- if (netif_running(netdev)) { -- fec_stop(netdev); -- fec_restart(netdev, fep->phy_dev->duplex); -- netif_wake_queue(netdev); -- } else { -- fec_restart(netdev, fep->phy_dev->duplex); -- } -+ if (changed & NETIF_F_HW_VLAN_CTAG_RX) { -+ if (features & NETIF_F_HW_VLAN_CTAG_RX) -+ fep->flags |= FEC_FLAG_RX_VLAN; -+ else -+ fep->flags &= ~FEC_FLAG_RX_VLAN; -+ } -+ -+ /* Set the appropriate minimum transmit ring free threshold */ -+ if (features & NETIF_F_SG) -+ fep->tx_min = MAX_SKB_FRAGS + 1; -+ else -+ fep->tx_min = 1; -+ -+ /* Resume the device after updates */ -+ if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) { -+ fec_restart(netdev); -+ netif_wake_queue(netdev); -+ netif_tx_unlock_bh(netdev); -+ napi_enable(&fep->napi); -+ mutex_unlock(&fep->mutex); - } - - return 0; -@@ -1975,27 +2398,13 @@ - #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = fec_poll_controller, - #endif -+ .ndo_fix_features = fec_fix_features, - .ndo_set_features = fec_set_features, - }; - -- /* -- * XXX: We need to clean up on failure exits here. -- * -- */ --static int fec_enet_init(struct net_device *ndev) -+static void fec_enet_init(struct net_device *ndev) - { - struct fec_enet_private *fep = netdev_priv(ndev); -- const struct platform_device_id *id_entry = -- platform_get_device_id(fep->pdev); -- struct bufdesc *cbd_base; -- -- /* Allocate memory for buffer descriptors. */ -- cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, -- GFP_KERNEL); -- if (!cbd_base) -- return -ENOMEM; -- -- memset(cbd_base, 0, PAGE_SIZE); - - fep->netdev = ndev; - -@@ -2008,13 +2417,8 @@ - fep->tx_ring_size = TX_RING_SIZE; - fep->rx_ring_size = RX_RING_SIZE; - -- /* Set receive and transmit descriptor base. */ -- fep->rx_bd_base = cbd_base; -- if (fep->bufdesc_ex) -- fep->tx_bd_base = (struct bufdesc *) -- (((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size); -- else -- fep->tx_bd_base = cbd_base + fep->rx_ring_size; -+ fep->rx_bd_base = fep->tx_bd_base = NULL; -+ fep->rx_bd_dma = fep->tx_bd_dma = 0; - - /* The FEC Ethernet specific entries in the device structure */ - ndev->watchdog_timeo = TX_TIMEOUT; -@@ -2024,24 +2428,37 @@ - writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); - netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT); - -- if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) { -- /* enable hw VLAN support */ -- ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; -- ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; -- } -- -- if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) { -- /* enable hw accelerator */ -- ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM -- | NETIF_F_RXCSUM); -- ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM -- | NETIF_F_RXCSUM); -- fep->csum_flags |= FLAG_RX_CSUM_ENABLED; -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) { -+ /* Features which require the enhanced buffer descriptors */ -+ if (fep->quirks & FEC_QUIRK_HAS_VLAN) { -+ /* enable hw VLAN support */ -+ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; -+ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; -+ fep->flags |= FEC_FLAG_RX_VLAN; -+ } -+ -+ if (fep->quirks & FEC_QUIRK_HAS_CSUM) { -+ /* enable hw accelerator */ -+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM -+ | NETIF_F_RXCSUM); -+ ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM -+ | NETIF_F_RXCSUM); -+ fep->flags |= FEC_FLAG_RX_CSUM; -+ } - } - -- fec_restart(ndev, 0); -+ if (!(fep->quirks & FEC_QUIRK_SWAP_FRAME)) { -+ /* don't enable SG if we need to swap frames */ -+ ndev->features |= NETIF_F_SG; -+ ndev->hw_features |= NETIF_F_SG; -+ } - -- return 0; -+ if (ndev->features & NETIF_F_SG) -+ fep->tx_min = MAX_SKB_FRAGS + 1; -+ else -+ fep->tx_min = 1; -+ -+ fec_restart(ndev); - } - - #ifdef CONFIG_OF -@@ -2107,11 +2524,16 @@ - /* setup board info structure */ - fep = netdev_priv(ndev); - -+ mutex_init(&fep->mutex); -+ -+ if (pdev->id_entry) -+ fep->quirks = pdev->id_entry->driver_data; - #if !defined(CONFIG_M5272) - /* default enable pause frame auto negotiation */ -- if (pdev->id_entry && -- (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT)) -- fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG; -+ if (fep->quirks & FEC_QUIRK_HAS_GBIT) -+ fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG | -+ FEC_PAUSE_FLAG_TX | -+ FEC_PAUSE_FLAG_RX; - #endif - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -2124,7 +2546,9 @@ - fep->pdev = pdev; - fep->dev_id = dev_id++; - -- fep->bufdesc_ex = 0; -+ fep->flags = 0; -+ if (pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX) -+ fep->flags |= FEC_FLAG_BUFDESC_EX; - - platform_set_drvdata(pdev, ndev); - -@@ -2157,11 +2581,9 @@ - fep->clk_enet_out = NULL; - - fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); -- fep->bufdesc_ex = -- pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; - if (IS_ERR(fep->clk_ptp)) { - fep->clk_ptp = NULL; -- fep->bufdesc_ex = 0; -+ fep->flags &= ~FEC_FLAG_BUFDESC_EX; - } - - ret = clk_prepare_enable(fep->clk_ahb); -@@ -2198,12 +2620,10 @@ - - fec_reset_phy(pdev); - -- if (fep->bufdesc_ex) -+ if (fep->flags & FEC_FLAG_BUFDESC_EX) - fec_ptp_init(pdev); - -- ret = fec_enet_init(ndev); -- if (ret) -- goto failed_init; -+ fec_enet_init(ndev); - - for (i = 0; i < FEC_IRQ_NUM; i++) { - irq = platform_get_irq(pdev, i); -@@ -2230,17 +2650,16 @@ - if (ret) - goto failed_register; - -- if (fep->bufdesc_ex && fep->ptp_clock) -+ if (fep->flags & FEC_FLAG_BUFDESC_EX && fep->ptp_clock) - netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); - -- INIT_DELAYED_WORK(&(fep->delay_work.delay_work), fec_enet_work); -+ INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work); - return 0; - - failed_register: - fec_enet_mii_remove(fep); - failed_mii_init: - failed_irq: --failed_init: - if (fep->reg_phy) - regulator_disable(fep->reg_phy); - failed_regulator: -@@ -2266,7 +2685,7 @@ - struct net_device *ndev = platform_get_drvdata(pdev); - struct fec_enet_private *fep = netdev_priv(ndev); - -- cancel_delayed_work_sync(&(fep->delay_work.delay_work)); -+ cancel_work_sync(&fep->tx_timeout_work); - unregister_netdev(ndev); - fec_enet_mii_remove(fep); - del_timer_sync(&fep->time_keep); -@@ -2292,10 +2711,19 @@ - struct net_device *ndev = dev_get_drvdata(dev); - struct fec_enet_private *fep = netdev_priv(ndev); - -+ rtnl_lock(); - if (netif_running(ndev)) { -- fec_stop(ndev); -+ phy_stop(fep->phy_dev); -+ napi_disable(&fep->napi); -+ netif_tx_lock_bh(ndev); - netif_device_detach(ndev); -+ netif_tx_unlock_bh(ndev); -+ mutex_lock(&fep->mutex); -+ fec_stop(ndev); -+ mutex_unlock(&fep->mutex); - } -+ rtnl_unlock(); -+ - if (fep->clk_ptp) - clk_disable_unprepare(fep->clk_ptp); - if (fep->clk_enet_out) -@@ -2342,10 +2770,18 @@ - goto failed_clk_ptp; - } - -+ rtnl_lock(); - if (netif_running(ndev)) { -- fec_restart(ndev, fep->full_duplex); -+ mutex_lock(&fep->mutex); -+ fec_restart(ndev); -+ mutex_unlock(&fep->mutex); -+ netif_tx_lock_bh(ndev); - netif_device_attach(ndev); -+ netif_tx_unlock_bh(ndev); -+ napi_enable(&fep->napi); -+ phy_start(fep->phy_dev); - } -+ rtnl_unlock(); - - return 0; - -diff -Nur linux-3.15-rc6.orig/drivers/regulator/anatop-regulator.c linux-3.15-rc6/drivers/regulator/anatop-regulator.c ---- linux-3.15-rc6.orig/drivers/regulator/anatop-regulator.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/regulator/anatop-regulator.c 2014-05-23 11:26:48.312940058 +0200 -@@ -267,6 +267,7 @@ - config.driver_data = sreg; - config.of_node = pdev->dev.of_node; - config.regmap = sreg->anatop; -+ config.ena_gpio = -EINVAL; - - /* Only core regulators have the ramp up delay configuration. */ - if (sreg->control_reg && sreg->delay_bit_width) { -diff -Nur linux-3.15-rc6.orig/drivers/regulator/core.c linux-3.15-rc6/drivers/regulator/core.c ---- linux-3.15-rc6.orig/drivers/regulator/core.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/regulator/core.c 2014-05-23 11:26:48.312940058 +0200 -@@ -3459,7 +3459,7 @@ - - dev_set_drvdata(&rdev->dev, rdev); - -- if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) { -+ if (gpio_is_valid(config->ena_gpio)) { - ret = regulator_ena_gpio_request(rdev, config); - if (ret != 0) { - rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", -diff -Nur linux-3.15-rc6.orig/drivers/regulator/dummy.c linux-3.15-rc6/drivers/regulator/dummy.c ---- linux-3.15-rc6.orig/drivers/regulator/dummy.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/regulator/dummy.c 2014-05-23 11:26:48.312940058 +0200 -@@ -48,6 +48,7 @@ - - config.dev = &pdev->dev; - config.init_data = &dummy_initdata; -+ config.ena_gpio = -EINVAL; - - dummy_regulator_rdev = regulator_register(&dummy_desc, &config); - if (IS_ERR(dummy_regulator_rdev)) { -diff -Nur linux-3.15-rc6.orig/drivers/regulator/fixed.c linux-3.15-rc6/drivers/regulator/fixed.c ---- linux-3.15-rc6.orig/drivers/regulator/fixed.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/regulator/fixed.c 2014-05-23 11:26:48.312940058 +0200 -@@ -161,9 +161,7 @@ - drvdata->desc.n_voltages = 1; - - drvdata->desc.fixed_uV = config->microvolts; -- -- if (config->gpio >= 0) -- cfg.ena_gpio = config->gpio; -+ cfg.ena_gpio = config->gpio; - cfg.ena_gpio_invert = !config->enable_high; - if (config->enabled_at_boot) { - if (config->enable_high) -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/drm-ddc-connector.c linux-3.15-rc6/drivers/staging/imx-drm/drm-ddc-connector.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/drm-ddc-connector.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/staging/imx-drm/drm-ddc-connector.c 2014-05-23 11:26:48.312940058 +0200 -@@ -0,0 +1,92 @@ -+#include <linux/i2c.h> -+#include <linux/module.h> -+#include <drm/drmP.h> -+#include <drm/drm_crtc_helper.h> -+#include <drm/drm_edid.h> -+ -+#include "drm-ddc-connector.h" -+ -+static enum drm_connector_status -+drm_ddc_connector_detect(struct drm_connector *connector, bool force) -+{ -+ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); -+ -+ return ddc_conn->detect ? ddc_conn->detect(connector, force) : -+ connector_status_connected; -+} -+ -+int drm_ddc_connector_get_modes(struct drm_connector *connector) -+{ -+ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); -+ struct edid *edid; -+ int ret = 0; -+ -+ if (!ddc_conn->ddc) -+ return 0; -+ -+ edid = drm_get_edid(connector, ddc_conn->ddc); -+ if (edid) { -+ drm_mode_connector_update_edid_property(connector, edid); -+ ret = drm_add_edid_modes(connector, edid); -+ /* Store the ELD */ -+ drm_edid_to_eld(connector, edid); -+ kfree(edid); -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(drm_ddc_connector_get_modes); -+ -+static void drm_ddc_connector_destroy(struct drm_connector *connector) -+{ -+ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); -+ -+ drm_sysfs_connector_remove(connector); -+ drm_connector_cleanup(connector); -+ if (ddc_conn->ddc) -+ i2c_put_adapter(ddc_conn->ddc); -+} -+ -+static const struct drm_connector_funcs drm_ddc_connector_funcs = { -+ .dpms = drm_helper_connector_dpms, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .detect = drm_ddc_connector_detect, -+ .destroy = drm_ddc_connector_destroy, -+}; -+ -+int drm_ddc_connector_add(struct drm_device *drm, -+ struct drm_ddc_connector *ddc_conn, int connector_type) -+{ -+ drm_connector_init(drm, &ddc_conn->connector, &drm_ddc_connector_funcs, -+ connector_type); -+ return 0; -+} -+EXPORT_SYMBOL_GPL(drm_ddc_connector_add); -+ -+struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm, -+ struct device_node *np, void *private) -+{ -+ struct drm_ddc_connector *ddc_conn; -+ struct device_node *ddc_node; -+ -+ ddc_conn = devm_kzalloc(drm->dev, sizeof(*ddc_conn), GFP_KERNEL); -+ if (!ddc_conn) -+ return ERR_PTR(-ENOMEM); -+ -+ ddc_conn->private = private; -+ -+ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); -+ if (ddc_node) { -+ ddc_conn->ddc = of_find_i2c_adapter_by_node(ddc_node); -+ of_node_put(ddc_node); -+ if (!ddc_conn->ddc) -+ return ERR_PTR(-EPROBE_DEFER); -+ } -+ -+ return ddc_conn; -+} -+EXPORT_SYMBOL_GPL(drm_ddc_connector_create); -+ -+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); -+MODULE_DESCRIPTION("Generic DRM DDC connector module"); -+MODULE_LICENSE("GPL v2"); -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/drm-ddc-connector.h linux-3.15-rc6/drivers/staging/imx-drm/drm-ddc-connector.h ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/drm-ddc-connector.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/staging/imx-drm/drm-ddc-connector.h 2014-05-23 11:26:48.312940058 +0200 -@@ -0,0 +1,26 @@ -+#ifndef DRM_DDC_CONNECTOR_H -+#define DRM_DDC_CONNECTOR_H -+ -+struct drm_ddc_connector { -+ struct i2c_adapter *ddc; -+ struct drm_connector connector; -+ enum drm_connector_status (*detect)(struct drm_connector *, bool); -+ void *private; -+}; -+ -+#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector) -+ -+int drm_ddc_connector_get_modes(struct drm_connector *connector); -+int drm_ddc_connector_add(struct drm_device *drm, -+ struct drm_ddc_connector *ddc_conn, int connector_type); -+struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm, -+ struct device_node *np, void *private); -+ -+static inline void *drm_ddc_private(struct drm_connector *connector) -+{ -+ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); -+ -+ return ddc_conn->private; -+} -+ -+#endif -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-audio.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-audio.c 2014-05-23 11:26:48.316940071 +0200 -@@ -0,0 +1,654 @@ -+/* -+ * DesignWare HDMI audio driver -+ * -+ * 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. -+ * -+ * Written and tested against the (alleged) DW HDMI Tx found in iMX6S. -+ */ -+#include <linux/delay.h> -+#include <linux/io.h> -+#include <linux/interrupt.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+ -+#include <sound/asoundef.h> -+#include <sound/core.h> -+#include <sound/initval.h> -+#include <sound/pcm.h> -+ -+#include "dw-hdmi-audio.h" -+ -+#define DRIVER_NAME "dw-hdmi-audio" -+ -+/* Provide some bits rather than bit offsets */ -+enum { -+ HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7), -+ HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3), -+ HDMI_AHB_DMA_START_START = BIT(0), -+ HDMI_AHB_DMA_STOP_STOP = BIT(0), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL = -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR | -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST | -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY | -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE | -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL | -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY, -+ HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5), -+ HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4), -+ HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3), -+ HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2), -+ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), -+ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), -+ HDMI_IH_AHBDMAAUD_STAT0_ALL = -+ HDMI_IH_AHBDMAAUD_STAT0_ERROR | -+ HDMI_IH_AHBDMAAUD_STAT0_LOST | -+ HDMI_IH_AHBDMAAUD_STAT0_RETRY | -+ HDMI_IH_AHBDMAAUD_STAT0_DONE | -+ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL | -+ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY, -+ HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1, -+ HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1, -+ HDMI_AHB_DMA_CONF0_INCR4 = 0, -+ HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0), -+ HDMI_AHB_DMA_MASK_DONE = BIT(7), -+ HDMI_REVISION_ID = 0x0001, -+ HDMI_IH_AHBDMAAUD_STAT0 = 0x0109, -+ HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189, -+ HDMI_AUD_N1 = 0x3200, -+ HDMI_AUD_CTS1 = 0x3203, -+ HDMI_AHB_DMA_CONF0 = 0x3600, -+ HDMI_AHB_DMA_START = 0x3601, -+ HDMI_AHB_DMA_STOP = 0x3602, -+ HDMI_AHB_DMA_THRSLD = 0x3603, -+ HDMI_AHB_DMA_STRADDR0 = 0x3604, -+ HDMI_AHB_DMA_STPADDR0 = 0x3608, -+ HDMI_AHB_DMA_STAT = 0x3612, -+ HDMI_AHB_DMA_STAT_FULL = BIT(1), -+ HDMI_AHB_DMA_MASK = 0x3614, -+ HDMI_AHB_DMA_POL = 0x3615, -+ HDMI_AHB_DMA_CONF1 = 0x3616, -+ HDMI_AHB_DMA_BUFFPOL = 0x361a, -+}; -+ -+struct snd_dw_hdmi { -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ struct dw_hdmi_audio_data data; -+ struct snd_pcm_substream *substream; -+ void (*reformat)(struct snd_dw_hdmi *, size_t, size_t); -+ void *buf_src; -+ void *buf_dst; -+ dma_addr_t buf_addr; -+ unsigned buf_offset; -+ unsigned buf_period; -+ unsigned buf_size; -+ unsigned channels; -+ uint8_t revision; -+ uint8_t iec_offset; -+ uint8_t cs[192][8]; -+}; -+ -+static void dw_hdmi_writel(unsigned long val, void __iomem *ptr) -+{ -+ writeb_relaxed(val, ptr); -+ writeb_relaxed(val >> 8, ptr + 1); -+ writeb_relaxed(val >> 16, ptr + 2); -+ writeb_relaxed(val >> 24, ptr + 3); -+} -+ -+/* -+ * Convert to hardware format: The userspace buffer contains IEC958 samples, -+ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We -+ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio -+ * samples in 23..0. -+ * -+ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd -+ * -+ * Ideally, we could do with having the data properly formatted in userspace. -+ */ -+static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw, -+ size_t offset, size_t bytes) -+{ -+ uint32_t *src = dw->buf_src + offset; -+ uint32_t *dst = dw->buf_dst + offset; -+ uint32_t *end = dw->buf_src + offset + bytes; -+ -+ do { -+ uint32_t b, sample = *src++; -+ -+ b = (sample & 8) << (28 - 3); -+ -+ sample >>= 4; -+ -+ *dst++ = sample | b; -+ } while (src < end); -+} -+ -+static uint32_t parity(uint32_t sample) -+{ -+ sample ^= sample >> 16; -+ sample ^= sample >> 8; -+ sample ^= sample >> 4; -+ sample ^= sample >> 2; -+ sample ^= sample >> 1; -+ return (sample & 1) << 27; -+} -+ -+static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw, -+ size_t offset, size_t bytes) -+{ -+ uint32_t *src = dw->buf_src + offset; -+ uint32_t *dst = dw->buf_dst + offset; -+ uint32_t *end = dw->buf_src + offset + bytes; -+ -+ do { -+ unsigned i; -+ uint8_t *cs; -+ -+ cs = dw->cs[dw->iec_offset++]; -+ if (dw->iec_offset >= 192) -+ dw->iec_offset = 0; -+ -+ i = dw->channels; -+ do { -+ uint32_t sample = *src++; -+ -+ sample &= ~0xff000000; -+ sample |= *cs++ << 24; -+ sample |= parity(sample & ~0xf8000000); -+ -+ *dst++ = sample; -+ } while (--i); -+ } while (src < end); -+} -+ -+static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw, -+ struct snd_pcm_runtime *runtime) -+{ -+ uint8_t cs[4]; -+ unsigned ch, i, j; -+ -+ cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; -+ cs[1] = IEC958_AES1_CON_GENERAL; -+ cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC; -+ cs[3] = IEC958_AES3_CON_CLOCK_1000PPM; -+ -+ switch (runtime->rate) { -+ case 32000: -+ cs[3] |= IEC958_AES3_CON_FS_32000; -+ break; -+ case 44100: -+ cs[3] |= IEC958_AES3_CON_FS_44100; -+ break; -+ case 48000: -+ cs[3] |= IEC958_AES3_CON_FS_48000; -+ break; -+ case 88200: -+ cs[3] |= IEC958_AES3_CON_FS_88200; -+ break; -+ case 96000: -+ cs[3] |= IEC958_AES3_CON_FS_96000; -+ break; -+ case 176400: -+ cs[3] |= IEC958_AES3_CON_FS_176400; -+ break; -+ case 192000: -+ cs[3] |= IEC958_AES3_CON_FS_192000; -+ break; -+ } -+ -+ memset(dw->cs, 0, sizeof(dw->cs)); -+ -+ for (ch = 0; ch < 8; ch++) { -+ cs[2] &= ~IEC958_AES2_CON_CHANNEL; -+ cs[2] |= (ch + 1) << 4; -+ -+ for (i = 0; i < ARRAY_SIZE(cs); i++) { -+ unsigned c = cs[i]; -+ -+ for (j = 0; j < 8; j++, c >>= 1) -+ dw->cs[i * 8 + j][ch] = (c & 1) << 2; -+ } -+ } -+ dw->cs[0][0] |= BIT(4); -+} -+ -+static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw) -+{ -+ void __iomem *base = dw->data.base; -+ unsigned offset = dw->buf_offset; -+ unsigned period = dw->buf_period; -+ u32 start, stop; -+ -+ dw->reformat(dw, offset, period); -+ -+ /* Clear all irqs before enabling irqs and starting DMA */ -+ writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL, -+ base + HDMI_IH_AHBDMAAUD_STAT0); -+ -+ start = dw->buf_addr + offset; -+ stop = start + period - 1; -+ -+ /* Setup the hardware start/stop addresses */ -+ dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0); -+ dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0); -+ -+ writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK); -+ writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START); -+ -+ offset += period; -+ if (offset >= dw->buf_size) -+ offset = 0; -+ dw->buf_offset = offset; -+} -+ -+static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw) -+{ -+ dw->substream = NULL; -+ -+ /* Disable interrupts before disabling DMA */ -+ writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK); -+ writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP); -+} -+ -+static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) -+{ -+ struct snd_dw_hdmi *dw = data; -+ struct snd_pcm_substream *substream; -+ unsigned stat; -+ -+ stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0); -+ if (!stat) -+ return IRQ_NONE; -+ -+ writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0); -+ -+ substream = dw->substream; -+ if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) { -+ snd_pcm_period_elapsed(substream); -+ if (dw->substream) -+ dw_hdmi_start_dma(dw); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static struct snd_pcm_hardware dw_hdmi_hw = { -+ .info = SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID, -+ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | -+ SNDRV_PCM_FMTBIT_S24_LE, -+ .rates = SNDRV_PCM_RATE_32000 | -+ SNDRV_PCM_RATE_44100 | -+ SNDRV_PCM_RATE_48000 | -+ SNDRV_PCM_RATE_88200 | -+ SNDRV_PCM_RATE_96000 | -+ SNDRV_PCM_RATE_176400 | -+ SNDRV_PCM_RATE_192000, -+ .channels_min = 2, -+ .channels_max = 8, -+ .buffer_bytes_max = 64 * 1024, -+ .period_bytes_min = 256, -+ .period_bytes_max = 8192, /* ERR004323: must limit to 8k */ -+ .periods_min = 2, -+ .periods_max = 16, -+ .fifo_size = 0, -+}; -+ -+static unsigned rates_mask[] = { -+ SNDRV_PCM_RATE_32000, -+ SNDRV_PCM_RATE_44100, -+ SNDRV_PCM_RATE_48000, -+ SNDRV_PCM_RATE_88200, -+ SNDRV_PCM_RATE_96000, -+ SNDRV_PCM_RATE_176400, -+ SNDRV_PCM_RATE_192000, -+}; -+ -+static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw, -+ struct snd_pcm_runtime *runtime) -+{ -+ u8 *sad, *eld = dw->data.eld; -+ unsigned eld_ver, mnl, sad_count, rates, rate_mask, i; -+ unsigned max_channels; -+ -+ eld_ver = eld[0] >> 3; -+ if (eld_ver != 2 && eld_ver != 31) -+ return; -+ -+ mnl = eld[4] & 0x1f; -+ if (mnl > 16) -+ return; -+ -+ sad_count = eld[5] >> 4; -+ sad = eld + 20 + mnl; -+ -+ /* Start from the basic audio settings */ -+ max_channels = 2; -+ rates = 7; -+ while (sad_count > 0) { -+ switch (sad[0] & 0x78) { -+ case 0x08: /* PCM */ -+ max_channels = max(max_channels, (sad[0] & 7) + 1u); -+ rates |= sad[1]; -+ break; -+ } -+ sad += 3; -+ sad_count -= 1; -+ } -+ -+ for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++) -+ if (rates & 1 << i) -+ rate_mask |= rates_mask[i]; -+ -+ runtime->hw.rates &= rate_mask; -+ runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels); -+} -+ -+static int dw_hdmi_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_dw_hdmi *dw = substream->private_data; -+ void __iomem *base = dw->data.base; -+ int ret; -+ -+ /* Clear FIFO */ -+ writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST, -+ base + HDMI_AHB_DMA_CONF0); -+ -+ /* Configure interrupt polarities */ -+ writeb_relaxed(~0, base + HDMI_AHB_DMA_POL); -+ writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL); -+ -+ /* Keep interrupts masked, and clear any pending */ -+ writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK); -+ writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0); -+ -+ ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED, -+ "dw-hdmi-audio", dw); -+ if (ret) -+ return ret; -+ -+ /* Un-mute done interrupt */ -+ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL & -+ ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE, -+ base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); -+ -+ runtime->hw = dw_hdmi_hw; -+ dw_hdmi_parse_eld(dw, runtime); -+ snd_pcm_limit_hw_rates(runtime); -+ -+ return 0; -+} -+ -+static int dw_hdmi_close(struct snd_pcm_substream *substream) -+{ -+ struct snd_dw_hdmi *dw = substream->private_data; -+ -+ /* Mute all interrupts */ -+ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, -+ dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); -+ -+ free_irq(dw->data.irq, dw); -+ -+ return 0; -+} -+ -+static int dw_hdmi_hw_free(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_lib_free_vmalloc_buffer(substream); -+} -+ -+static int dw_hdmi_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ return snd_pcm_lib_alloc_vmalloc_buffer(substream, -+ params_buffer_bytes(params)); -+} -+ -+static int dw_hdmi_prepare(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_dw_hdmi *dw = substream->private_data; -+ uint8_t threshold, conf0, conf1; -+ -+ /* Setup as per 3.0.5 FSL 4.1.0 BSP */ -+ switch (dw->revision) { -+ case 0x0a: -+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | -+ HDMI_AHB_DMA_CONF0_INCR4; -+ if (runtime->channels == 2) -+ threshold = 126; -+ else -+ threshold = 124; -+ break; -+ case 0x1a: -+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | -+ HDMI_AHB_DMA_CONF0_INCR8; -+ threshold = 128; -+ break; -+ default: -+ /* NOTREACHED */ -+ return -EINVAL; -+ } -+ -+ dw->data.set_sample_rate(dw->data.hdmi, runtime->rate); -+ -+ /* Minimum number of bytes in the fifo. */ -+ runtime->hw.fifo_size = threshold * 32; -+ -+ conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK; -+ conf1 = (1 << runtime->channels) - 1; -+ -+ writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD); -+ writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0); -+ writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1); -+ -+ switch (runtime->format) { -+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: -+ dw->reformat = dw_hdmi_reformat_iec958; -+ break; -+ case SNDRV_PCM_FORMAT_S24_LE: -+ dw_hdmi_create_cs(dw, runtime); -+ dw->reformat = dw_hdmi_reformat_s24; -+ break; -+ } -+ dw->iec_offset = 0; -+ dw->channels = runtime->channels; -+ dw->buf_src = runtime->dma_area; -+ dw->buf_dst = substream->dma_buffer.area; -+ dw->buf_addr = substream->dma_buffer.addr; -+ dw->buf_period = snd_pcm_lib_period_bytes(substream); -+ dw->buf_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ return 0; -+} -+ -+static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct snd_dw_hdmi *dw = substream->private_data; -+ void __iomem *base = dw->data.base; -+ unsigned n[3], cts[3]; -+ int ret = 0, i; -+ bool err005174; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ err005174 = dw->revision == 0x0a; -+ if (err005174) { -+ for (i = 2; i >= 1; i--) { -+ n[i] = readb_relaxed(base + HDMI_AUD_N1 + i); -+ cts[i] = readb_relaxed(base + HDMI_AUD_CTS1 + i); -+ writeb_relaxed(0, base + HDMI_AUD_N1 + i); -+ writeb_relaxed(0, base + HDMI_AUD_CTS1 + i); -+ } -+ } -+ -+ dw->buf_offset = 0; -+ dw->substream = substream; -+ dw_hdmi_start_dma(dw); -+ -+ if (err005174) { -+ for (i = 2; i >= 1; i--) -+ writeb_relaxed(cts[i], base + HDMI_AUD_CTS1 + i); -+ for (i = 2; i >= 1; i--) -+ writeb_relaxed(n[i], base + HDMI_AUD_N1 + i); -+ } -+ -+ substream->runtime->delay = substream->runtime->period_size; -+ break; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ dw_hdmi_stop_dma(dw); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_dw_hdmi *dw = substream->private_data; -+ -+ return bytes_to_frames(runtime, dw->buf_offset); -+} -+ -+static struct snd_pcm_ops snd_dw_hdmi_ops = { -+ .open = dw_hdmi_open, -+ .close = dw_hdmi_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = dw_hdmi_hw_params, -+ .hw_free = dw_hdmi_hw_free, -+ .prepare = dw_hdmi_prepare, -+ .trigger = dw_hdmi_trigger, -+ .pointer = dw_hdmi_pointer, -+ .page = snd_pcm_lib_get_vmalloc_page, -+}; -+ -+static int snd_dw_hdmi_probe(struct platform_device *pdev) -+{ -+ const struct dw_hdmi_audio_data *data = pdev->dev.platform_data; -+ struct device *dev = pdev->dev.parent; -+ struct snd_dw_hdmi *dw; -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ unsigned revision; -+ int ret; -+ -+ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, -+ data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); -+ revision = readb_relaxed(data->base + HDMI_REVISION_ID); -+ if (revision != 0x0a && revision != 0x1a) { -+ dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n", -+ revision); -+ return -ENXIO; -+ } -+ -+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, -+ THIS_MODULE, sizeof(struct snd_dw_hdmi), &card); -+ if (ret < 0) -+ return ret; -+ -+ snd_card_set_dev(card, dev); -+ -+ strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); -+ strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname)); -+ snprintf(card->longname, sizeof(card->longname), -+ "%s rev 0x%02x, irq %d", card->shortname, revision, -+ data->irq); -+ -+ dw = card->private_data; -+ dw->card = card; -+ dw->data = *data; -+ dw->revision = revision; -+ -+ ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm); -+ if (ret < 0) -+ goto err; -+ -+ dw->pcm = pcm; -+ pcm->private_data = dw; -+ strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops); -+ -+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, -+ dev, 64 * 1024, 64 * 1024); -+ -+ ret = snd_card_register(card); -+ if (ret < 0) -+ goto err; -+ -+ platform_set_drvdata(pdev, dw); -+ -+ return 0; -+ -+err: -+ snd_card_free(card); -+ return ret; -+} -+ -+static int snd_dw_hdmi_remove(struct platform_device *pdev) -+{ -+ struct snd_dw_hdmi *dw = platform_get_drvdata(pdev); -+ -+ snd_card_free(dw->card); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int snd_dw_hdmi_suspend(struct device *dev) -+{ -+ struct snd_dw_hdmi *dw = dev_get_drvdata(dev); -+ -+ snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold); -+ snd_pcm_suspend_all(dw->pcm); -+ -+ return 0; -+} -+ -+static int snd_dw_hdmi_resume(struct device *dev) -+{ -+ struct snd_dw_hdmi *dw = dev_get_drvdata(dev); -+ -+ snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend, -+ snd_dw_hdmi_resume); -+#define PM_OPS &snd_dw_hdmi_pm -+#else -+#define PM_OPS NULL -+#endif -+ -+static struct platform_driver snd_dw_hdmi_driver = { -+ .probe = snd_dw_hdmi_probe, -+ .remove = snd_dw_hdmi_remove, -+ .driver = { -+ .name = "dw-hdmi-audio", -+ .owner = THIS_MODULE, -+ .pm = PM_OPS, -+ }, -+}; -+ -+module_platform_driver(snd_dw_hdmi_driver); -+ -+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); -+MODULE_LICENSE("GPL"); -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-audio.h ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-audio.h 2014-05-23 11:26:48.316940071 +0200 -@@ -0,0 +1,15 @@ -+#ifndef DW_HDMI_AUDIO_H -+#define DW_HDMI_AUDIO_H -+ -+struct imx_hdmi; -+ -+struct dw_hdmi_audio_data { -+ phys_addr_t phys; -+ void __iomem *base; -+ int irq; -+ struct imx_hdmi *hdmi; -+ u8 *eld; -+ void (*set_sample_rate)(struct imx_hdmi *, unsigned); -+}; -+ -+#endif -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-cec.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-cec.c 2014-05-23 11:26:48.316940071 +0200 -@@ -0,0 +1,205 @@ -+/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */ -+#include <linux/cec-dev.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+ -+#include "imx-hdmi.h" -+#include "dw-hdmi-cec.h" -+ -+#define DEV_NAME "mxc_hdmi_cec" -+ -+enum { -+ CEC_STAT_DONE = BIT(0), -+ CEC_STAT_EOM = BIT(1), -+ CEC_STAT_NACK = BIT(2), -+ CEC_STAT_ARBLOST = BIT(3), -+ CEC_STAT_ERROR_INIT = BIT(4), -+ CEC_STAT_ERROR_FOLL = BIT(5), -+ CEC_STAT_WAKEUP = BIT(6), -+ -+ CEC_CTRL_START = BIT(0), -+ CEC_CTRL_NORMAL = 1 << 1, -+}; -+ -+struct dw_hdmi_cec { -+ struct cec_dev cec; -+ -+ struct device *dev; -+ void __iomem *base; -+ const struct dw_hdmi_cec_ops *ops; -+ void *ops_data; -+ int irq; -+}; -+ -+static void dw_hdmi_set_address(struct cec_dev *cec_dev, unsigned addresses) -+{ -+ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); -+ -+ writeb(addresses & 255, cec->base + HDMI_CEC_ADDR_L); -+ writeb(addresses >> 8, cec->base + HDMI_CEC_ADDR_H); -+} -+ -+static void dw_hdmi_send_message(struct cec_dev *cec_dev, u8 *msg, -+ size_t count) -+{ -+ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); -+ unsigned i; -+ -+ for (i = 0; i < count; i++) -+ writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i); -+ -+ writeb(count, cec->base + HDMI_CEC_TX_CNT); -+ writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); -+} -+ -+static irqreturn_t dw_hdmi_cec_irq(int irq, void *data) -+{ -+ struct dw_hdmi_cec *cec = data; -+ struct cec_dev *cec_dev = &cec->cec; -+ unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0); -+ -+ if (stat == 0) -+ return IRQ_NONE; -+ -+ writeb(stat, cec->base + HDMI_IH_CEC_STAT0); -+ -+ if (stat & CEC_STAT_ERROR_INIT) { -+ if (cec->cec.retries) { -+ unsigned v = readb(cec->base + HDMI_CEC_CTRL); -+ writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); -+ cec->cec.retries -= 1; -+ } else { -+ cec->cec.write_busy = 0; -+ cec_dev_event(cec_dev, MESSAGE_TYPE_SEND_ERROR, NULL, 0); -+ } -+ } else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK)) -+ cec_dev_send_complete(cec_dev, stat & CEC_STAT_DONE); -+ -+ if (stat & CEC_STAT_EOM) { -+ unsigned len, i; -+ u8 msg[MAX_MESSAGE_LEN]; -+ -+ len = readb(cec->base + HDMI_CEC_RX_CNT); -+ if (len > sizeof(msg)) -+ len = sizeof(msg); -+ -+ for (i = 0; i < len; i++) -+ msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i); -+ -+ writeb(0, cec->base + HDMI_CEC_LOCK); -+ -+ cec_dev_receive(cec_dev, msg, len); -+ } -+ -+ return IRQ_HANDLED; -+} -+EXPORT_SYMBOL(dw_hdmi_cec_irq); -+ -+static void dw_hdmi_cec_release(struct cec_dev *cec_dev) -+{ -+ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); -+ -+ writeb(~0, cec->base + HDMI_CEC_MASK); -+ writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); -+ writeb(0, cec->base + HDMI_CEC_POLARITY); -+ -+ free_irq(cec->irq, cec); -+ -+ cec->ops->disable(cec->ops_data); -+} -+ -+static int dw_hdmi_cec_open(struct cec_dev *cec_dev) -+{ -+ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); -+ unsigned irqs; -+ int ret; -+ -+ writeb(0, cec->base + HDMI_CEC_CTRL); -+ writeb(~0, cec->base + HDMI_IH_CEC_STAT0); -+ writeb(0, cec->base + HDMI_CEC_LOCK); -+ -+ ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED, -+ DEV_NAME, cec); -+ if (ret < 0) -+ return ret; -+ -+ dw_hdmi_set_address(cec_dev, cec_dev->addresses); -+ -+ cec->ops->enable(cec->ops_data); -+ -+ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | -+ CEC_STAT_DONE; -+ writeb(irqs, cec->base + HDMI_CEC_POLARITY); -+ writeb(~irqs, cec->base + HDMI_CEC_MASK); -+ writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0); -+ -+ return 0; -+} -+ -+static int dw_hdmi_cec_probe(struct platform_device *pdev) -+{ -+ struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev); -+ struct dw_hdmi_cec *cec; -+ -+ if (!data) -+ return -ENXIO; -+ -+ cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); -+ if (!cec) -+ return -ENOMEM; -+ -+ cec->dev = &pdev->dev; -+ cec->base = data->base; -+ cec->irq = data->irq; -+ cec->ops = data->ops; -+ cec->ops_data = data->ops_data; -+ cec->cec.open = dw_hdmi_cec_open; -+ cec->cec.release = dw_hdmi_cec_release; -+ cec->cec.send_message = dw_hdmi_send_message; -+ cec->cec.set_address = dw_hdmi_set_address; -+ -+ cec_dev_init(&cec->cec, THIS_MODULE); -+ -+ /* FIXME: soft-reset the CEC interface */ -+ -+ dw_hdmi_set_address(&cec->cec, cec->cec.addresses); -+ writeb(0, cec->base + HDMI_CEC_TX_CNT); -+ writeb(~0, cec->base + HDMI_CEC_MASK); -+ writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); -+ writeb(0, cec->base + HDMI_CEC_POLARITY); -+ -+ /* -+ * Our device is just a convenience - we want to link to the real -+ * hardware device here, so that userspace can see the association -+ * between the HDMI hardware and its associated CEC chardev. -+ */ -+ return cec_dev_add(&cec->cec, cec->dev->parent, DEV_NAME); -+} -+ -+static int dw_hdmi_cec_remove(struct platform_device *pdev) -+{ -+ struct dw_hdmi_cec *cec = platform_get_drvdata(pdev); -+ -+ cec_dev_remove(&cec->cec); -+ -+ return 0; -+} -+ -+static struct platform_driver dw_hdmi_cec_driver = { -+ .probe = dw_hdmi_cec_probe, -+ .remove = dw_hdmi_cec_remove, -+ .driver = { -+ .name = "dw-hdmi-cec", -+ .owner = THIS_MODULE, -+ }, -+}; -+module_platform_driver(dw_hdmi_cec_driver); -+ -+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); -+MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec"); -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-cec.h ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/drivers/staging/imx-drm/dw-hdmi-cec.h 2014-05-23 11:26:48.316940071 +0200 -@@ -0,0 +1,16 @@ -+#ifndef DW_HDMI_CEC_H -+#define DW_HDMI_CEC_H -+ -+struct dw_hdmi_cec_ops { -+ void (*enable)(void *); -+ void (*disable)(void *); -+}; -+ -+struct dw_hdmi_cec_data { -+ void __iomem *base; -+ int irq; -+ const struct dw_hdmi_cec_ops *ops; -+ void *ops_data; -+}; -+ -+#endif -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/imx-hdmi.c linux-3.15-rc6/drivers/staging/imx-drm/imx-hdmi.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/imx-hdmi.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/imx-hdmi.c 2014-05-23 11:26:48.316940071 +0200 -@@ -28,6 +28,9 @@ - #include <drm/drm_edid.h> - #include <drm/drm_encoder_slave.h> - -+#include "drm-ddc-connector.h" -+#include "dw-hdmi-audio.h" -+#include "dw-hdmi-cec.h" - #include "ipu-v3/imx-ipu-v3.h" - #include "imx-hdmi.h" - #include "imx-drm.h" -@@ -112,27 +115,27 @@ - }; - - struct imx_hdmi { -- struct drm_connector connector; -+ struct drm_ddc_connector *ddc_conn; - struct drm_encoder encoder; - -+ struct platform_device *audio; -+ struct platform_device *cec; - enum imx_hdmi_devtype dev_type; - struct device *dev; - struct clk *isfr_clk; - struct clk *iahb_clk; - -- enum drm_connector_status connector_status; -- - struct hdmi_data_info hdmi_data; - int vic; - - u8 edid[HDMI_EDID_LEN]; -+ u8 mc_clkdis; - bool cable_plugin; - - bool phy_enabled; - struct drm_display_mode previous_mode; - - struct regmap *regmap; -- struct i2c_adapter *ddc; - void __iomem *regs; - - unsigned int sample_rate; -@@ -362,6 +365,12 @@ - hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); - } - -+static void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned rate) -+{ -+ hdmi->sample_rate = rate; -+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); -+} -+ - /* - * this submodule is responsible for the video data synchronization. - * for example, for RGB 4:4:4 input, the data map is defined as -@@ -1148,8 +1157,6 @@ - /* HDMI Initialization Step B.4 */ - static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) - { -- u8 clkdis; -- - /* control period minimum duration */ - hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR); - hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR); -@@ -1161,23 +1168,28 @@ - hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); - - /* Enable pixel clock and tmds data path */ -- clkdis = 0x7F; -- clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; -- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); -+ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE | -+ HDMI_MC_CLKDIS_CSCCLK_DISABLE | -+ HDMI_MC_CLKDIS_AUDCLK_DISABLE | -+ HDMI_MC_CLKDIS_PREPCLK_DISABLE | -+ HDMI_MC_CLKDIS_TMDSCLK_DISABLE; -+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; -+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - -- clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; -- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); -+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; -+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - - /* Enable csc path */ - if (is_color_space_conversion(hdmi)) { -- clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; -- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); -+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; -+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - } - } - - static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) - { -- hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); -+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; -+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - } - - /* Workaround to clear the overflow condition */ -@@ -1380,41 +1392,16 @@ - static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector - *connector, bool force) - { -- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, -- connector); -- return hdmi->connector_status; --} -- --static int imx_hdmi_connector_get_modes(struct drm_connector *connector) --{ -- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, -- connector); -- struct edid *edid; -- int ret; -+ struct imx_hdmi *hdmi = drm_ddc_private(connector); - -- if (!hdmi->ddc) -- return 0; -- -- edid = drm_get_edid(connector, hdmi->ddc); -- if (edid) { -- dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", -- edid->width_cm, edid->height_cm); -- -- drm_mode_connector_update_edid_property(connector, edid); -- ret = drm_add_edid_modes(connector, edid); -- kfree(edid); -- } else { -- dev_dbg(hdmi->dev, "failed to get edid\n"); -- } -- -- return 0; -+ return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? -+ connector_status_connected : connector_status_disconnected; - } - - static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector - *connector) - { -- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, -- connector); -+ struct imx_hdmi *hdmi = drm_ddc_private(connector); - - return &hdmi->encoder; - } -@@ -1483,15 +1470,8 @@ - .disable = imx_hdmi_encoder_disable, - }; - --static struct drm_connector_funcs imx_hdmi_connector_funcs = { -- .dpms = drm_helper_connector_dpms, -- .fill_modes = drm_helper_probe_single_connector_modes, -- .detect = imx_hdmi_connector_detect, -- .destroy = imx_drm_connector_destroy, --}; -- - static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { -- .get_modes = imx_hdmi_connector_get_modes, -+ .get_modes = drm_ddc_connector_get_modes, - .mode_valid = imx_drm_connector_mode_valid, - .best_encoder = imx_hdmi_connector_best_encoder, - }; -@@ -1524,7 +1504,6 @@ - - hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); - -- hdmi->connector_status = connector_status_connected; - imx_hdmi_poweron(hdmi); - } else { - dev_dbg(hdmi->dev, "EVENT=plugout\n"); -@@ -1532,10 +1511,9 @@ - hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, - HDMI_PHY_POL0); - -- hdmi->connector_status = connector_status_disconnected; - imx_hdmi_poweroff(hdmi); - } -- drm_helper_hpd_irq_event(hdmi->connector.dev); -+ drm_helper_hpd_irq_event(hdmi->ddc_conn->connector.dev); - } - - hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); -@@ -1553,24 +1531,42 @@ - if (ret) - return ret; - -- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; -+ hdmi->ddc_conn->connector.polled = DRM_CONNECTOR_POLL_HPD; - - drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); - drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, - DRM_MODE_ENCODER_TMDS); - -- drm_connector_helper_add(&hdmi->connector, -+ drm_connector_helper_add(&hdmi->ddc_conn->connector, - &imx_hdmi_connector_helper_funcs); -- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, -- DRM_MODE_CONNECTOR_HDMIA); -- -- hdmi->connector.encoder = &hdmi->encoder; -+ drm_ddc_connector_add(drm, hdmi->ddc_conn, DRM_MODE_CONNECTOR_HDMIA); - -- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); -+ drm_mode_connector_attach_encoder(&hdmi->ddc_conn->connector, &hdmi->encoder); - - return 0; - } - -+static void imx_hdmi_cec_enable(void *data) -+{ -+ struct imx_hdmi *hdmi = data; -+ -+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; -+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); -+} -+ -+static void imx_hdmi_cec_disable(void *data) -+{ -+ struct imx_hdmi *hdmi = data; -+ -+ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE; -+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); -+} -+ -+static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = { -+ .enable = imx_hdmi_cec_enable, -+ .disable = imx_hdmi_cec_disable, -+}; -+ - static struct platform_device_id imx_hdmi_devtype[] = { - { - .name = "imx6q-hdmi", -@@ -1592,11 +1588,13 @@ - static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) - { - struct platform_device *pdev = to_platform_device(dev); -+ struct platform_device_info pdevinfo; - const struct of_device_id *of_id = - of_match_device(imx_hdmi_dt_ids, dev); - struct drm_device *drm = data; - struct device_node *np = dev->of_node; -- struct device_node *ddc_node; -+ struct dw_hdmi_audio_data audio; -+ struct dw_hdmi_cec_data cec; - struct imx_hdmi *hdmi; - struct resource *iores; - int ret, irq; -@@ -1605,27 +1603,22 @@ - if (!hdmi) - return -ENOMEM; - -+ hdmi->ddc_conn = drm_ddc_connector_create(drm, np, hdmi); -+ if (IS_ERR(hdmi->ddc_conn)) -+ return PTR_ERR(hdmi->ddc_conn); -+ -+ hdmi->ddc_conn->detect = imx_hdmi_connector_detect; -+ - hdmi->dev = dev; -- hdmi->connector_status = connector_status_disconnected; - hdmi->sample_rate = 48000; - hdmi->ratio = 100; -+ hdmi->mc_clkdis = 0x7f; - - if (of_id) { - const struct platform_device_id *device_id = of_id->data; - hdmi->dev_type = device_id->driver_data; - } - -- ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); -- if (ddc_node) { -- hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); -- if (!hdmi->ddc) -- dev_dbg(hdmi->dev, "failed to read ddc node\n"); -- -- of_node_put(ddc_node); -- } else { -- dev_dbg(hdmi->dev, "no ddc property found\n"); -- } -- - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -EINVAL; -@@ -1711,6 +1704,35 @@ - /* Unmute interrupts */ - hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); - -+ memset(&pdevinfo, 0, sizeof(pdevinfo)); -+ pdevinfo.parent = dev; -+ pdevinfo.id = PLATFORM_DEVID_AUTO; -+ -+ audio.phys = iores->start; -+ audio.base = hdmi->regs; -+ audio.irq = irq; -+ audio.hdmi = hdmi; -+ audio.eld = hdmi->ddc_conn->connector.eld; -+ audio.set_sample_rate = imx_hdmi_set_sample_rate; -+ -+ pdevinfo.name = "dw-hdmi-audio"; -+ pdevinfo.data = &audio; -+ pdevinfo.size_data = sizeof(audio); -+ pdevinfo.dma_mask = DMA_BIT_MASK(32); -+ hdmi->audio = platform_device_register_full(&pdevinfo); -+ -+ cec.base = hdmi->regs; -+ cec.irq = irq; -+ cec.ops = &imx_hdmi_cec_ops; -+ cec.ops_data = hdmi; -+ -+ pdevinfo.name = "dw-hdmi-cec"; -+ pdevinfo.data = &cec; -+ pdevinfo.size_data = sizeof(cec); -+ pdevinfo.dma_mask = 0; -+ -+ hdmi->cec = platform_device_register_full(&pdevinfo); -+ - dev_set_drvdata(dev, hdmi); - - return 0; -@@ -1728,15 +1750,19 @@ - { - struct imx_hdmi *hdmi = dev_get_drvdata(dev); - -+ if (!IS_ERR(hdmi->audio)) -+ platform_device_unregister(hdmi->audio); -+ if (!IS_ERR(hdmi->cec)) -+ platform_device_unregister(hdmi->cec); -+ - /* Disable all interrupts */ - hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); - -- hdmi->connector.funcs->destroy(&hdmi->connector); -+ hdmi->ddc_conn->connector.funcs->destroy(&hdmi->ddc_conn->connector); - hdmi->encoder.funcs->destroy(&hdmi->encoder); - - clk_disable_unprepare(hdmi->iahb_clk); - clk_disable_unprepare(hdmi->isfr_clk); -- i2c_put_adapter(hdmi->ddc); - } - - static const struct component_ops hdmi_ops = { -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/imx-ldb.c linux-3.15-rc6/drivers/staging/imx-drm/imx-ldb.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/imx-ldb.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/imx-ldb.c 2014-05-23 11:26:48.316940071 +0200 -@@ -24,6 +24,7 @@ - #include <drm/drmP.h> - #include <drm/drm_fb_helper.h> - #include <drm/drm_crtc_helper.h> -+#include <drm/drm_panel.h> - #include <linux/mfd/syscon.h> - #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> - #include <linux/of_address.h> -@@ -60,6 +61,7 @@ - struct imx_ldb *ldb; - struct drm_connector connector; - struct drm_encoder encoder; -+ struct drm_panel *panel; - struct device_node *child; - int chno; - void *edid; -@@ -96,6 +98,13 @@ - struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); - int num_modes = 0; - -+ if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && -+ imx_ldb_ch->panel->funcs->get_modes) { -+ num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); -+ if (num_modes > 0) -+ return num_modes; -+ } -+ - if (imx_ldb_ch->edid) { - drm_mode_connector_update_edid_property(connector, - imx_ldb_ch->edid); -@@ -243,6 +252,8 @@ - } - - regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); -+ -+ drm_panel_enable(imx_ldb_ch->panel); - } - - static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, -@@ -294,6 +305,8 @@ - (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) - return; - -+ drm_panel_disable(imx_ldb_ch->panel); -+ - if (imx_ldb_ch == &ldb->channel[0]) - ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; - else if (imx_ldb_ch == &ldb->channel[1]) -@@ -379,6 +392,9 @@ - drm_connector_init(drm, &imx_ldb_ch->connector, - &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - -+ if (imx_ldb_ch->panel) -+ drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); -+ - drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, - &imx_ldb_ch->encoder); - -@@ -493,6 +509,7 @@ - - for_each_child_of_node(np, child) { - struct imx_ldb_channel *channel; -+ struct device_node *panel_node; - - ret = of_property_read_u32(child, "reg", &i); - if (ret || i < 0 || i > 1) -@@ -556,6 +573,10 @@ - return -EINVAL; - } - -+ panel_node = of_parse_phandle(child, "fsl,panel", 0); -+ if (panel_node) -+ channel->panel = of_drm_find_panel(panel_node); -+ - ret = imx_ldb_register(drm, channel); - if (ret) - return ret; -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/imx-tve.c linux-3.15-rc6/drivers/staging/imx-drm/imx-tve.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/imx-tve.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/imx-tve.c 2014-05-23 11:28:50.689342803 +0200 -@@ -22,7 +22,6 @@ - #include <linux/clk-provider.h> - #include <linux/component.h> - #include <linux/module.h> --#include <linux/i2c.h> - #include <linux/regmap.h> - #include <linux/regulator/consumer.h> - #include <linux/spinlock.h> -@@ -31,6 +30,7 @@ - #include <drm/drm_fb_helper.h> - #include <drm/drm_crtc_helper.h> - -+#include "drm-ddc-connector.h" - #include "ipu-v3/imx-ipu-v3.h" - #include "imx-drm.h" - -@@ -111,7 +111,7 @@ - }; - - struct imx_tve { -- struct drm_connector connector; -+ struct drm_ddc_connector *ddc_conn; - struct drm_encoder encoder; - struct device *dev; - spinlock_t lock; /* register lock */ -@@ -120,7 +120,6 @@ - - struct regmap *regmap; - struct regulator *dac_reg; -- struct i2c_adapter *ddc; - struct clk *clk; - struct clk *di_sel_clk; - struct clk_hw clk_hw_di; -@@ -219,35 +218,10 @@ - return 0; - } - --static enum drm_connector_status imx_tve_connector_detect( -- struct drm_connector *connector, bool force) --{ -- return connector_status_connected; --} -- --static int imx_tve_connector_get_modes(struct drm_connector *connector) --{ -- struct imx_tve *tve = con_to_tve(connector); -- struct edid *edid; -- int ret = 0; -- -- if (!tve->ddc) -- return 0; -- -- edid = drm_get_edid(connector, tve->ddc); -- if (edid) { -- drm_mode_connector_update_edid_property(connector, edid); -- ret = drm_add_edid_modes(connector, edid); -- kfree(edid); -- } -- -- return ret; --} -- - static int imx_tve_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) - { -- struct imx_tve *tve = con_to_tve(connector); -+ struct imx_tve *tve = to_ddc_conn(connector)->private; - unsigned long rate; - int ret; - -@@ -274,7 +248,7 @@ - static struct drm_encoder *imx_tve_connector_best_encoder( - struct drm_connector *connector) - { -- struct imx_tve *tve = con_to_tve(connector); -+ struct imx_tve *tve = drm_ddc_private(connector); - - return &tve->encoder; - } -@@ -362,15 +336,8 @@ - tve_disable(tve); - } - --static struct drm_connector_funcs imx_tve_connector_funcs = { -- .dpms = drm_helper_connector_dpms, -- .fill_modes = drm_helper_probe_single_connector_modes, -- .detect = imx_tve_connector_detect, -- .destroy = imx_drm_connector_destroy, --}; -- - static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { -- .get_modes = imx_tve_connector_get_modes, -+ .get_modes = drm_ddc_connector_get_modes, - .best_encoder = imx_tve_connector_best_encoder, - .mode_valid = imx_tve_connector_mode_valid, - }; -@@ -513,12 +480,11 @@ - drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs, - encoder_type); - -- drm_connector_helper_add(&tve->connector, -+ drm_connector_helper_add(&tve->ddc_conn->connector, - &imx_tve_connector_helper_funcs); -- drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, -- DRM_MODE_CONNECTOR_VGA); -+ drm_ddc_connector_add(drm, tve->ddc_conn, DRM_MODE_CONNECTOR_VGA); - -- drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); -+ drm_mode_connector_attach_encoder(&tve->ddc_conn->connector, &tve->encoder); - - return 0; - } -@@ -567,7 +533,6 @@ - struct platform_device *pdev = to_platform_device(dev); - struct drm_device *drm = data; - struct device_node *np = dev->of_node; -- struct device_node *ddc_node; - struct imx_tve *tve; - struct resource *res; - void __iomem *base; -@@ -579,15 +544,13 @@ - if (!tve) - return -ENOMEM; - -+ tve->ddc_conn = drm_ddc_connector_create(drm, np, tve); -+ if (IS_ERR(tve->ddc_conn)) -+ return PTR_ERR(tve->ddc_conn); -+ - tve->dev = dev; - spin_lock_init(&tve->lock); - -- ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); -- if (ddc_node) { -- tve->ddc = of_find_i2c_adapter_by_node(ddc_node); -- of_node_put(ddc_node); -- } -- - tve->mode = of_get_tve_mode(np); - if (tve->mode != TVE_MODE_VGA) { - dev_err(dev, "only VGA mode supported, currently\n"); -@@ -694,7 +657,7 @@ - { - struct imx_tve *tve = dev_get_drvdata(dev); - -- tve->connector.funcs->destroy(&tve->connector); -+ tve->ddc_conn->connector.funcs->destroy(&tve->ddc_conn->connector); - tve->encoder.funcs->destroy(&tve->encoder); - - if (!IS_ERR(tve->dac_reg)) -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h 2014-05-23 11:26:48.316940071 +0200 -@@ -76,6 +76,7 @@ - IPU_IRQ_EOS = 192, - }; - -+int ipu_map_irq(struct ipu_soc *ipu, int irq); - int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, - enum ipu_channel_irq irq); - -@@ -114,8 +115,10 @@ - void ipu_dc_put(struct ipu_dc *dc); - int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, - u32 pixel_fmt, u32 width); -+void ipu_dc_enable(struct ipu_soc *ipu); - void ipu_dc_enable_channel(struct ipu_dc *dc); - void ipu_dc_disable_channel(struct ipu_dc *dc); -+void ipu_dc_disable(struct ipu_soc *ipu); - - /* - * IPU Display Interface (di) functions -@@ -152,8 +155,10 @@ - - struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow); - void ipu_dp_put(struct ipu_dp *); -+int ipu_dp_enable(struct ipu_soc *ipu); - int ipu_dp_enable_channel(struct ipu_dp *dp); - void ipu_dp_disable_channel(struct ipu_dp *dp); -+void ipu_dp_disable(struct ipu_soc *ipu); - int ipu_dp_setup_channel(struct ipu_dp *dp, - enum ipu_color_space in, enum ipu_color_space out); - int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos); -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-common.c linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-common.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-common.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-common.c 2014-05-23 11:26:48.352940189 +0200 -@@ -697,6 +697,12 @@ - } - EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); - -+bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno) -+{ -+ return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno)); -+} -+EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy); -+ - int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) - { - struct ipu_soc *ipu = channel->ipu; -@@ -714,6 +720,22 @@ - } - EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy); - -+int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms) -+{ -+ unsigned long timeout; -+ -+ timeout = jiffies + msecs_to_jiffies(ms); -+ ipu_cm_write(ipu, BIT(irq % 32), IPU_INT_STAT(irq / 32)); -+ while (!(ipu_cm_read(ipu, IPU_INT_STAT(irq / 32) & BIT(irq % 32)))) { -+ if (time_after(jiffies, timeout)) -+ return -ETIMEDOUT; -+ cpu_relax(); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(ipu_wait_interrupt); -+ - int ipu_idmac_disable_channel(struct ipuv3_channel *channel) - { - struct ipu_soc *ipu = channel->ipu; -@@ -933,15 +955,22 @@ - chained_irq_exit(chip, desc); - } - --int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, -- enum ipu_channel_irq irq_type) -+int ipu_map_irq(struct ipu_soc *ipu, int irq) - { -- int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num); -+ int virq; - -- if (!irq) -- irq = irq_create_mapping(ipu->domain, irq_type + channel->num); -+ virq = irq_linear_revmap(ipu->domain, irq); -+ if (!virq) -+ virq = irq_create_mapping(ipu->domain, irq); - -- return irq; -+ return virq; -+} -+EXPORT_SYMBOL_GPL(ipu_map_irq); -+ -+int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, -+ enum ipu_channel_irq irq_type) -+{ -+ return ipu_map_irq(ipu, irq_type + channel->num); - } - EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq); - -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-dc.c linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-dc.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-dc.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-dc.c 2014-05-23 11:26:48.360940215 +0200 -@@ -18,6 +18,7 @@ - #include <linux/types.h> - #include <linux/errno.h> - #include <linux/delay.h> -+#include <linux/interrupt.h> - #include <linux/io.h> - - #include "../imx-drm.h" -@@ -92,6 +93,7 @@ - IPU_DC_MAP_GBR24, /* TVEv2 */ - IPU_DC_MAP_BGR666, - IPU_DC_MAP_BGR24, -+ IPU_DC_MAP_RGB666, - }; - - struct ipu_dc { -@@ -110,6 +112,9 @@ - struct device *dev; - struct ipu_dc channels[IPU_DC_NUM_CHANNELS]; - struct mutex mutex; -+ struct completion comp; -+ int dc_irq; -+ int dp_irq; - }; - - static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) -@@ -155,6 +160,8 @@ - return IPU_DC_MAP_BGR666; - case V4L2_PIX_FMT_BGR24: - return IPU_DC_MAP_BGR24; -+ case V4L2_PIX_FMT_RGB666: -+ return IPU_DC_MAP_RGB666; - default: - return -EINVAL; - } -@@ -220,12 +227,16 @@ - writel(0x0, dc->base + DC_WR_CH_ADDR); - writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di)); - -- ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); -- - return 0; - } - EXPORT_SYMBOL_GPL(ipu_dc_init_sync); - -+void ipu_dc_enable(struct ipu_soc *ipu) -+{ -+ ipu_module_enable(ipu, IPU_CONF_DC_EN); -+} -+EXPORT_SYMBOL_GPL(ipu_dc_enable); -+ - void ipu_dc_enable_channel(struct ipu_dc *dc) - { - int di; -@@ -239,41 +250,55 @@ - } - EXPORT_SYMBOL_GPL(ipu_dc_enable_channel); - -+static irqreturn_t dc_irq_handler(int irq, void *dev_id) -+{ -+ struct ipu_dc *dc = dev_id; -+ u32 reg; -+ -+ reg = readl(dc->base + DC_WR_CH_CONF); -+ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; -+ writel(reg, dc->base + DC_WR_CH_CONF); -+ -+ /* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */ -+ -+ complete(&dc->priv->comp); -+ return IRQ_HANDLED; -+} -+ - void ipu_dc_disable_channel(struct ipu_dc *dc) - { - struct ipu_dc_priv *priv = dc->priv; -+ int irq, ret; - u32 val; -- int irq = 0, timeout = 50; - -+ /* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */ - if (dc->chno == 1) -- irq = IPU_IRQ_DC_FC_1; -+ irq = priv->dc_irq; - else if (dc->chno == 5) -- irq = IPU_IRQ_DP_SF_END; -+ irq = priv->dp_irq; - else - return; - -- /* should wait for the interrupt here */ -- mdelay(50); -- -- if (dc->di == 0) -- val = 0x00000002; -- else -- val = 0x00000020; -- -- /* Wait for DC triple buffer to empty */ -- while ((readl(priv->dc_reg + DC_STAT) & val) != val) { -- usleep_range(2000, 20000); -- timeout -= 2; -- if (timeout <= 0) -- break; -+ init_completion(&priv->comp); -+ enable_irq(irq); -+ ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50)); -+ disable_irq(irq); -+ if (ret <= 0) { -+ dev_warn(priv->dev, "DC stop timeout after 50 ms\n"); -+ -+ val = readl(dc->base + DC_WR_CH_CONF); -+ val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; -+ writel(val, dc->base + DC_WR_CH_CONF); - } -- -- val = readl(dc->base + DC_WR_CH_CONF); -- val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; -- writel(val, dc->base + DC_WR_CH_CONF); - } - EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); - -+void ipu_dc_disable(struct ipu_soc *ipu) -+{ -+ ipu_module_disable(ipu, IPU_CONF_DC_EN); -+} -+EXPORT_SYMBOL_GPL(ipu_dc_disable); -+ - static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map, - int byte_num, int offset, int mask) - { -@@ -340,7 +365,7 @@ - struct ipu_dc_priv *priv; - static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, - 0x78, 0, 0x94, 0xb4}; -- int i; -+ int i, ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) -@@ -361,6 +386,23 @@ - priv->channels[i].base = priv->dc_reg + channel_offsets[i]; - } - -+ priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1); -+ if (!priv->dc_irq) -+ return -EINVAL; -+ ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL, -+ &priv->channels[1]); -+ if (ret < 0) -+ return ret; -+ disable_irq(priv->dc_irq); -+ priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END); -+ if (!priv->dp_irq) -+ return -EINVAL; -+ ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL, -+ &priv->channels[5]); -+ if (ret < 0) -+ return ret; -+ disable_irq(priv->dp_irq); -+ - writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) | - DC_WR_CH_CONF_PROG_DI_ID, - priv->channels[1].base + DC_WR_CH_CONF); -@@ -404,6 +446,12 @@ - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */ - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */ - -+ /* rgb666 */ -+ ipu_dc_map_clear(priv, IPU_DC_MAP_RGB666); -+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 0, 5, 0xfc); /* blue */ -+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 1, 11, 0xfc); /* green */ -+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 2, 17, 0xfc); /* red */ -+ - return 0; - } - -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-di.c linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-di.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-di.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-di.c 2014-05-23 11:26:48.372940255 +0200 -@@ -595,7 +595,7 @@ - } - } - -- if (!sig->clk_pol) -+ if (sig->clk_pol) - di_gen |= DI_GEN_POLARITY_DISP_CLK; - - ipu_di_write(di, di_gen, DI_GENERAL); -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c 2014-05-23 11:26:48.380940281 +0200 -@@ -28,7 +28,12 @@ - #define DMFC_GENERAL1 0x0014 - #define DMFC_GENERAL2 0x0018 - #define DMFC_IC_CTRL 0x001c --#define DMFC_STAT 0x0020 -+#define DMFC_WR_CHAN_ALT 0x0020 -+#define DMFC_WR_CHAN_DEF_ALT 0x0024 -+#define DMFC_DP_CHAN_ALT 0x0028 -+#define DMFC_DP_CHAN_DEF_ALT 0x002c -+#define DMFC_GENERAL1_ALT 0x0030 -+#define DMFC_STAT 0x0034 - - #define DMFC_WR_CHAN_1_28 0 - #define DMFC_WR_CHAN_2_41 8 -@@ -133,6 +138,20 @@ - } - EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); - -+static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv) -+{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(1000); -+ -+ while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) { -+ if (time_after(jiffies, timeout)) { -+ dev_warn(priv->dev, -+ "Timeout waiting for DMFC FIFOs to clear\n"); -+ break; -+ } -+ cpu_relax(); -+ } -+} -+ - void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) - { - struct ipu_dmfc_priv *priv = dmfc->priv; -@@ -141,8 +160,10 @@ - - priv->use_count--; - -- if (!priv->use_count) -+ if (!priv->use_count) { -+ ipu_dmfc_wait_fifos(priv); - ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); -+ } - - if (priv->use_count < 0) - priv->use_count = 0; -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-dp.c linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-dp.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-dp.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-dp.c 2014-05-23 11:26:48.388940307 +0200 -@@ -215,10 +215,9 @@ - } - EXPORT_SYMBOL_GPL(ipu_dp_setup_channel); - --int ipu_dp_enable_channel(struct ipu_dp *dp) -+int ipu_dp_enable(struct ipu_soc *ipu) - { -- struct ipu_flow *flow = to_flow(dp); -- struct ipu_dp_priv *priv = flow->priv; -+ struct ipu_dp_priv *priv = ipu->dp_priv; - - mutex_lock(&priv->mutex); - -@@ -227,15 +226,28 @@ - - priv->use_count++; - -- if (dp->foreground) { -- u32 reg; -+ mutex_unlock(&priv->mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(ipu_dp_enable); -+ -+int ipu_dp_enable_channel(struct ipu_dp *dp) -+{ -+ struct ipu_flow *flow = to_flow(dp); -+ struct ipu_dp_priv *priv = flow->priv; -+ u32 reg; -+ -+ if (!dp->foreground) -+ return 0; -+ -+ mutex_lock(&priv->mutex); - -- reg = readl(flow->base + DP_COM_CONF); -- reg |= DP_COM_CONF_FG_EN; -- writel(reg, flow->base + DP_COM_CONF); -+ reg = readl(flow->base + DP_COM_CONF); -+ reg |= DP_COM_CONF_FG_EN; -+ writel(reg, flow->base + DP_COM_CONF); - -- ipu_srm_dp_sync_update(priv->ipu); -- } -+ ipu_srm_dp_sync_update(priv->ipu); - - mutex_unlock(&priv->mutex); - -@@ -247,25 +259,38 @@ - { - struct ipu_flow *flow = to_flow(dp); - struct ipu_dp_priv *priv = flow->priv; -+ u32 reg, csc; -+ -+ if (!dp->foreground) -+ return; - - mutex_lock(&priv->mutex); - -- priv->use_count--; -+ reg = readl(flow->base + DP_COM_CONF); -+ csc = reg & DP_COM_CONF_CSC_DEF_MASK; -+ if (csc == DP_COM_CONF_CSC_DEF_FG) -+ reg &= ~DP_COM_CONF_CSC_DEF_MASK; -+ -+ reg &= ~DP_COM_CONF_FG_EN; -+ writel(reg, flow->base + DP_COM_CONF); -+ -+ writel(0, flow->base + DP_FG_POS); -+ ipu_srm_dp_sync_update(priv->ipu); -+ -+ if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC)) -+ ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50); -+ -+ mutex_unlock(&priv->mutex); -+} -+EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); - -- if (dp->foreground) { -- u32 reg, csc; -+void ipu_dp_disable(struct ipu_soc *ipu) -+{ -+ struct ipu_dp_priv *priv = ipu->dp_priv; - -- reg = readl(flow->base + DP_COM_CONF); -- csc = reg & DP_COM_CONF_CSC_DEF_MASK; -- if (csc == DP_COM_CONF_CSC_DEF_FG) -- reg &= ~DP_COM_CONF_CSC_DEF_MASK; -- -- reg &= ~DP_COM_CONF_FG_EN; -- writel(reg, flow->base + DP_COM_CONF); -- -- writel(0, flow->base + DP_FG_POS); -- ipu_srm_dp_sync_update(priv->ipu); -- } -+ mutex_lock(&priv->mutex); -+ -+ priv->use_count--; - - if (!priv->use_count) - ipu_module_disable(priv->ipu, IPU_CONF_DP_EN); -@@ -275,7 +300,7 @@ - - mutex_unlock(&priv->mutex); - } --EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); -+EXPORT_SYMBOL_GPL(ipu_dp_disable); - - struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow) - { -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-prv.h linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-prv.h ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipu-v3/ipu-prv.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipu-v3/ipu-prv.h 2014-05-23 11:26:48.396940333 +0200 -@@ -185,6 +185,9 @@ - int ipu_module_enable(struct ipu_soc *ipu, u32 mask); - int ipu_module_disable(struct ipu_soc *ipu, u32 mask); - -+bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); -+int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); -+ - int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, - unsigned long base, u32 module, struct clk *ipu_clk); - void ipu_di_exit(struct ipu_soc *ipu, int id); -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipuv3-crtc.c linux-3.15-rc6/drivers/staging/imx-drm/ipuv3-crtc.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipuv3-crtc.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipuv3-crtc.c 2014-05-23 11:26:48.396940333 +0200 -@@ -60,24 +60,32 @@ - - static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) - { -+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); -+ - if (ipu_crtc->enabled) - return; - -- ipu_di_enable(ipu_crtc->di); -- ipu_dc_enable_channel(ipu_crtc->dc); -+ ipu_dc_enable(ipu); - ipu_plane_enable(ipu_crtc->plane[0]); -+ /* Start DC channel and DI after IDMAC */ -+ ipu_dc_enable_channel(ipu_crtc->dc); -+ ipu_di_enable(ipu_crtc->di); - - ipu_crtc->enabled = 1; - } - - static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) - { -+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); -+ - if (!ipu_crtc->enabled) - return; - -- ipu_plane_disable(ipu_crtc->plane[0]); -+ /* Stop DC channel and DI before IDMAC */ - ipu_dc_disable_channel(ipu_crtc->dc); - ipu_di_disable(ipu_crtc->di); -+ ipu_plane_disable(ipu_crtc->plane[0]); -+ ipu_dc_disable(ipu); - - ipu_crtc->enabled = 0; - } -@@ -158,7 +166,7 @@ - sig_cfg.Vsync_pol = 1; - - sig_cfg.enable_pol = 1; -- sig_cfg.clk_pol = 1; -+ sig_cfg.clk_pol = 0; - sig_cfg.width = mode->hdisplay; - sig_cfg.height = mode->vdisplay; - sig_cfg.pixel_fmt = out_pixel_fmt; -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/ipuv3-plane.c linux-3.15-rc6/drivers/staging/imx-drm/ipuv3-plane.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/ipuv3-plane.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/ipuv3-plane.c 2014-05-23 11:26:48.396940333 +0200 -@@ -239,6 +239,8 @@ - - void ipu_plane_enable(struct ipu_plane *ipu_plane) - { -+ if (ipu_plane->dp) -+ ipu_dp_enable(ipu_plane->ipu); - ipu_dmfc_enable_channel(ipu_plane->dmfc); - ipu_idmac_enable_channel(ipu_plane->ipu_ch); - if (ipu_plane->dp) -@@ -257,6 +259,8 @@ - ipu_dp_disable_channel(ipu_plane->dp); - ipu_idmac_disable_channel(ipu_plane->ipu_ch); - ipu_dmfc_disable_channel(ipu_plane->dmfc); -+ if (ipu_plane->dp) -+ ipu_dp_disable(ipu_plane->ipu); - } - - static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode) -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/Kconfig linux-3.15-rc6/drivers/staging/imx-drm/Kconfig ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/Kconfig 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/Kconfig 2014-05-23 11:26:48.396940333 +0200 -@@ -35,6 +35,7 @@ - config DRM_IMX_LDB - tristate "Support for LVDS displays" - depends on DRM_IMX && MFD_SYSCON -+ select DRM_PANEL - help - Choose this to enable the internal LVDS Display Bridge (LDB) - found on i.MX53 and i.MX6 processors. -@@ -60,3 +61,20 @@ - depends on DRM_IMX - help - Choose this if you want to use HDMI on i.MX6. -+ -+config DRM_DW_HDMI_AUDIO -+ tristate "Synopsis Designware Audio interface" -+ depends on DRM_IMX_HDMI != n -+ help -+ Support the Audio interface which is part of the Synopsis -+ Designware HDMI block. This is used in conjunction with -+ the i.MX HDMI driver. -+ -+config DRM_DW_HDMI_CEC -+ tristate "Synopsis Designware CEC interface" -+ depends on DRM_IMX_HDMI != n -+ select HDMI_CEC_CORE -+ help -+ Support the CEC interface which is part of the Synposis -+ Designware HDMI block. This is used in conjunction with -+ the i.MX HDMI driver. -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/Makefile linux-3.15-rc6/drivers/staging/imx-drm/Makefile ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/Makefile 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/Makefile 2014-05-23 11:26:48.396940333 +0200 -@@ -3,6 +3,7 @@ - - obj-$(CONFIG_DRM_IMX) += imxdrm.o - -+obj-$(CONFIG_DRM_IMX) += drm-ddc-connector.o - obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o - obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o - obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o -@@ -11,3 +12,5 @@ - imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o - obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o - obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o -+obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o -+obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o -diff -Nur linux-3.15-rc6.orig/drivers/staging/imx-drm/parallel-display.c linux-3.15-rc6/drivers/staging/imx-drm/parallel-display.c ---- linux-3.15-rc6.orig/drivers/staging/imx-drm/parallel-display.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/drivers/staging/imx-drm/parallel-display.c 2014-05-23 11:26:48.396940333 +0200 -@@ -219,6 +219,8 @@ - imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; - else if (!strcmp(fmt, "bgr666")) - imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; -+ else if (!strcmp(fmt, "rgb666")) -+ imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB666; - } - - panel_node = of_parse_phandle(np, "fsl,panel", 0); -diff -Nur linux-3.15-rc6.orig/include/linux/cec-dev.h linux-3.15-rc6/include/linux/cec-dev.h ---- linux-3.15-rc6.orig/include/linux/cec-dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/include/linux/cec-dev.h 2014-05-23 11:26:48.396940333 +0200 -@@ -0,0 +1,69 @@ -+#ifndef _LINUX_CEC_DEV_H -+#define _LINUX_CEC_DEV_H -+ -+#include <linux/cdev.h> -+#include <linux/list.h> -+#include <linux/mutex.h> -+#include <linux/spinlock.h> -+#include <linux/wait.h> -+ -+#include <uapi/linux/cec-dev.h> -+ -+struct device; -+ -+struct cec_dev { -+ struct cdev cdev; -+ dev_t devn; -+ -+ struct mutex mutex; -+ unsigned users; -+ -+ spinlock_t lock; -+ wait_queue_head_t waitq; -+ struct list_head events; -+ u8 write_busy; -+ -+ u8 retries; -+ u16 addresses; -+ u16 physical; -+ -+ int (*open)(struct cec_dev *); -+ void (*release)(struct cec_dev *); -+ void (*send_message)(struct cec_dev *, u8 *, size_t); -+ void (*set_address)(struct cec_dev *, unsigned); -+}; -+ -+void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len); -+ -+static inline void cec_dev_receive(struct cec_dev *cec_dev, u8 *msg, -+ unsigned len) -+{ -+ cec_dev_event(cec_dev, MESSAGE_TYPE_RECEIVE_SUCCESS, msg, len); -+} -+ -+static inline void cec_dev_send_complete(struct cec_dev *cec_dev, int ack) -+{ -+ cec_dev->retries = 0; -+ cec_dev->write_busy = 0; -+ -+ cec_dev_event(cec_dev, ack ? MESSAGE_TYPE_SEND_SUCCESS : -+ MESSAGE_TYPE_NOACK, NULL, 0); -+} -+ -+static inline void cec_dev_disconnect(struct cec_dev *cec_dev) -+{ -+ cec_dev->physical = 0; -+ cec_dev_event(cec_dev, MESSAGE_TYPE_DISCONNECTED, NULL, 0); -+} -+ -+static inline void cec_dev_connect(struct cec_dev *cec_dev, u32 phys) -+{ -+ cec_dev->physical = phys; -+ cec_dev_event(cec_dev, MESSAGE_TYPE_CONNECTED, NULL, 0); -+} -+ -+void cec_dev_init(struct cec_dev *cec_dev, struct module *); -+int cec_dev_add(struct cec_dev *cec_dev, struct device *, const char *name); -+void cec_dev_remove(struct cec_dev *cec_dev); -+ -+#endif -diff -Nur linux-3.15-rc6.orig/include/linux/mmc/host.h linux-3.15-rc6/include/linux/mmc/host.h ---- linux-3.15-rc6.orig/include/linux/mmc/host.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/include/linux/mmc/host.h 2014-05-23 11:26:48.400940347 +0200 -@@ -278,6 +278,7 @@ - #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ - MMC_CAP2_PACKED_WR) - #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ -+#define MMC_CAP2_SDIO_NOTHREAD (1 << 15) - - mmc_pm_flag_t pm_caps; /* supported pm features */ - -@@ -293,6 +294,11 @@ - unsigned long clkgate_delay; - #endif - -+ /* card specific properties to deal with power and reset */ -+ struct regulator *card_regulator; /* External VCC needed by the card */ -+ struct gpio_desc *card_reset_gpios[2]; /* External resets, active low */ -+ struct clk *card_clk; /* External clock needed by the card */ -+ - /* host specific block data */ - unsigned int max_seg_size; /* see blk_queue_max_segment_size */ - unsigned short max_segs; /* see blk_queue_max_segments */ -@@ -391,6 +397,8 @@ - wake_up_process(host->sdio_irq_thread); - } - -+void sdio_run_irqs(struct mmc_host *host); -+ - #ifdef CONFIG_REGULATOR - int mmc_regulator_get_ocrmask(struct regulator *supply); - int mmc_regulator_set_ocr(struct mmc_host *mmc, -diff -Nur linux-3.15-rc6.orig/include/linux/mmc/sdhci.h linux-3.15-rc6/include/linux/mmc/sdhci.h ---- linux-3.15-rc6.orig/include/linux/mmc/sdhci.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/include/linux/mmc/sdhci.h 2014-05-23 11:26:48.400940347 +0200 -@@ -57,12 +57,8 @@ - #define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) - /* Controller reports inverted write-protect state */ - #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) --/* Controller has nonstandard clock management */ --#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17) - /* Controller does not like fast PIO transfers */ - #define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) --/* Controller losing signal/interrupt enable states after reset */ --#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19) - /* Controller has to be forced to use block size of 2048 bytes */ - #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) - /* Controller cannot do multi-block transfers */ -@@ -147,6 +143,7 @@ - - bool runtime_suspended; /* Host is runtime suspended */ - bool bus_on; /* Bus power prevents runtime suspend */ -+ bool preset_enabled; /* Preset is enabled */ - - struct mmc_request *mrq; /* Current request */ - struct mmc_command *cmd; /* Current command */ -@@ -164,8 +161,7 @@ - dma_addr_t adma_addr; /* Mapped ADMA descr. table */ - dma_addr_t align_addr; /* Mapped bounce buffer */ - -- struct tasklet_struct card_tasklet; /* Tasklet structures */ -- struct tasklet_struct finish_tasklet; -+ struct tasklet_struct finish_tasklet; /* Tasklet structures */ - - struct timer_list timer; /* Timer for timeouts */ - -@@ -177,6 +173,13 @@ - unsigned int ocr_avail_mmc; - u32 ocr_mask; /* available voltages */ - -+ unsigned timing; /* Current timing */ -+ -+ u32 thread_isr; -+ -+ /* cached registers */ -+ u32 ier; -+ - wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ - unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ - -diff -Nur linux-3.15-rc6.orig/include/uapi/linux/cec-dev.h linux-3.15-rc6/include/uapi/linux/cec-dev.h ---- linux-3.15-rc6.orig/include/uapi/linux/cec-dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.15-rc6/include/uapi/linux/cec-dev.h 2014-05-23 11:26:48.400940347 +0200 -@@ -0,0 +1,34 @@ -+#ifndef _UAPI_LINUX_CEC_DEV_H -+#define _UAPI_LINUX_CEC_DEV_H -+ -+#include <linux/ioctl.h> -+#include <linux/types.h> -+ -+#define MAX_MESSAGE_LEN 16 -+ -+enum { -+ HDMICEC_IOC_MAGIC = 'H', -+ /* This is wrong: we pass the argument as a number, not a pointer */ -+ HDMICEC_IOC_O_SETLOGICALADDRESS = _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char), -+ HDMICEC_IOC_SETLOGICALADDRESS = _IO(HDMICEC_IOC_MAGIC, 1), -+ HDMICEC_IOC_STARTDEVICE = _IO(HDMICEC_IOC_MAGIC, 2), -+ HDMICEC_IOC_STOPDEVICE = _IO(HDMICEC_IOC_MAGIC, 3), -+ HDMICEC_IOC_GETPHYADDRESS = _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]), -+}; -+ -+enum { -+ MESSAGE_TYPE_RECEIVE_SUCCESS = 1, -+ MESSAGE_TYPE_NOACK, -+ MESSAGE_TYPE_DISCONNECTED, -+ MESSAGE_TYPE_CONNECTED, -+ MESSAGE_TYPE_SEND_SUCCESS, -+ MESSAGE_TYPE_SEND_ERROR, -+}; -+ -+struct cec_user_event { -+ __u32 event_type; -+ __u32 msg_len; -+ __u8 msg[MAX_MESSAGE_LEN]; -+}; -+ -+#endif -diff -Nur linux-3.15-rc6.orig/include/uapi/linux/videodev2.h linux-3.15-rc6/include/uapi/linux/videodev2.h ---- linux-3.15-rc6.orig/include/uapi/linux/videodev2.h 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/include/uapi/linux/videodev2.h 2014-05-23 11:26:48.400940347 +0200 -@@ -299,6 +299,7 @@ - #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ - #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ - #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ -+#define V4L2_PIX_FMT_RGB666 v4l2_fourcc('R', 'G', 'B', 'H') /* 18 RGB-6-6-6 */ - #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ - #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ - #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ -diff -Nur linux-3.15-rc6.orig/sound/soc/fsl/imx-pcm-dma.c linux-3.15-rc6/sound/soc/fsl/imx-pcm-dma.c ---- linux-3.15-rc6.orig/sound/soc/fsl/imx-pcm-dma.c 2014-05-21 23:42:02.000000000 +0200 -+++ linux-3.15-rc6/sound/soc/fsl/imx-pcm-dma.c 2014-05-23 11:26:48.400940347 +0200 -@@ -44,7 +44,7 @@ - .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, - .period_bytes_min = 128, - .period_bytes_max = 65535, /* Limited by SDMA engine */ -- .periods_min = 2, -+ .periods_min = 4, - .periods_max = 255, - .fifo_size = 0, - }; diff --git a/target/arm/cubox-i/patches/3.15/rmk.patch b/target/arm/cubox-i/patches/3.15/rmk.patch new file mode 100644 index 000000000..7ccbf3b4a --- /dev/null +++ b/target/arm/cubox-i/patches/3.15/rmk.patch @@ -0,0 +1,6640 @@ + .../DocBook/media/v4l/pixfmt-packed-rgb.xml | 39 ++ + .../devicetree/bindings/leds/leds-pwm.txt | 2 + + Documentation/devicetree/bindings/mmc/mmc.txt | 11 + + .../bindings/staging/imx-drm/fsl-imx-drm.txt | 3 +- + arch/arm/boot/dts/imx6dl-hummingboard.dts | 27 + + arch/arm/boot/dts/imx6q-cubox-i.dts | 4 + + arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 78 ++- + arch/arm/boot/dts/imx6qdl-microsom.dtsi | 98 +++ + arch/arm/configs/imx_v6_v7_defconfig | 1 + + arch/arm/mach-imx/clk-imx6q.c | 12 + + arch/arm/mach-imx/clk-pllv3.c | 27 +- + drivers/Kconfig | 2 + + drivers/Makefile | 1 + + drivers/ata/ahci_imx.c | 184 +++++- + drivers/cec/Kconfig | 14 + + drivers/cec/Makefile | 1 + + drivers/cec/cec-dev.c | 384 +++++++++++ + drivers/gpu/drm/drm_crtc_helper.c | 6 - + drivers/leds/leds-pwm.c | 144 ++-- + drivers/mmc/core/core.c | 42 ++ + drivers/mmc/core/host.c | 68 ++ + drivers/mmc/core/sdio_irq.c | 41 +- + drivers/mmc/host/Kconfig | 63 +- + drivers/mmc/host/dw_mmc.c | 2 + + drivers/mmc/host/sdhci-acpi.c | 8 + + drivers/mmc/host/sdhci-bcm-kona.c | 4 + + drivers/mmc/host/sdhci-bcm2835.c | 4 + + drivers/mmc/host/sdhci-cns3xxx.c | 13 +- + drivers/mmc/host/sdhci-dove.c | 4 + + drivers/mmc/host/sdhci-esdhc-imx.c | 82 +-- + drivers/mmc/host/sdhci-esdhc.h | 4 +- + drivers/mmc/host/sdhci-of-arasan.c | 4 + + drivers/mmc/host/sdhci-of-esdhc.c | 70 +- + drivers/mmc/host/sdhci-of-hlwd.c | 4 + + drivers/mmc/host/sdhci-pci.c | 9 +- + drivers/mmc/host/sdhci-pltfm.c | 4 + + drivers/mmc/host/sdhci-pxav2.c | 14 +- + drivers/mmc/host/sdhci-pxav3.c | 13 +- + drivers/mmc/host/sdhci-s3c.c | 36 +- + drivers/mmc/host/sdhci-sirf.c | 4 + + drivers/mmc/host/sdhci-spear.c | 5 +- + drivers/mmc/host/sdhci-tegra.c | 27 +- + drivers/mmc/host/sdhci.c | 722 ++++++++++----------- + drivers/mmc/host/sdhci.h | 20 +- + drivers/regulator/anatop-regulator.c | 1 + + drivers/regulator/core.c | 2 +- + drivers/regulator/dummy.c | 1 + + drivers/regulator/fixed.c | 4 +- + drivers/staging/imx-drm/Kconfig | 18 + + drivers/staging/imx-drm/Makefile | 3 + + drivers/staging/imx-drm/drm-ddc-connector.c | 92 +++ + drivers/staging/imx-drm/drm-ddc-connector.h | 26 + + drivers/staging/imx-drm/dw-hdmi-audio.c | 652 +++++++++++++++++++ + drivers/staging/imx-drm/dw-hdmi-audio.h | 15 + + drivers/staging/imx-drm/dw-hdmi-cec.c | 205 ++++++ + drivers/staging/imx-drm/dw-hdmi-cec.h | 16 + + drivers/staging/imx-drm/imx-hdmi.c | 178 ++--- + drivers/staging/imx-drm/imx-ldb.c | 21 + + drivers/staging/imx-drm/imx-tve.c | 63 +- + drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h | 5 + + drivers/staging/imx-drm/ipu-v3/ipu-common.c | 41 +- + drivers/staging/imx-drm/ipu-v3/ipu-dc.c | 94 ++- + drivers/staging/imx-drm/ipu-v3/ipu-di.c | 2 +- + drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c | 25 +- + drivers/staging/imx-drm/ipu-v3/ipu-dp.c | 71 +- + drivers/staging/imx-drm/ipu-v3/ipu-prv.h | 3 + + drivers/staging/imx-drm/ipuv3-crtc.c | 16 +- + drivers/staging/imx-drm/ipuv3-plane.c | 4 + + drivers/staging/imx-drm/parallel-display.c | 2 + + include/linux/cec-dev.h | 69 ++ + include/linux/mmc/host.h | 8 + + include/linux/mmc/sdhci.h | 15 +- + include/uapi/linux/cec-dev.h | 34 + + include/uapi/linux/videodev2.h | 1 + + sound/soc/fsl/imx-pcm-dma.c | 2 +- + 75 files changed, 3162 insertions(+), 832 deletions(-) + +diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +index e1c4f8b4c0b3..88a7fe1ecaf1 100644 +--- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml ++++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +@@ -279,6 +279,45 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para> + <entry></entry> + <entry></entry> + </row> ++ <row id="V4L2-PIX-FMT-RGB666"> ++ <entry><constant>V4L2_PIX_FMT_RGB666</constant></entry> ++ <entry>'RGBH'</entry> ++ <entry></entry> ++ <entry>r<subscript>5</subscript></entry> ++ <entry>r<subscript>4</subscript></entry> ++ <entry>r<subscript>3</subscript></entry> ++ <entry>r<subscript>2</subscript></entry> ++ <entry>r<subscript>1</subscript></entry> ++ <entry>r<subscript>0</subscript></entry> ++ <entry>g<subscript>5</subscript></entry> ++ <entry>g<subscript>4</subscript></entry> ++ <entry></entry> ++ <entry>g<subscript>3</subscript></entry> ++ <entry>g<subscript>2</subscript></entry> ++ <entry>g<subscript>1</subscript></entry> ++ <entry>g<subscript>0</subscript></entry> ++ <entry>b<subscript>5</subscript></entry> ++ <entry>b<subscript>4</subscript></entry> ++ <entry>b<subscript>3</subscript></entry> ++ <entry>b<subscript>2</subscript></entry> ++ <entry></entry> ++ <entry>b<subscript>1</subscript></entry> ++ <entry>b<subscript>0</subscript></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ <entry></entry> ++ </row> + <row id="V4L2-PIX-FMT-BGR24"> + <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry> + <entry>'BGR3'</entry> +diff --git a/Documentation/devicetree/bindings/leds/leds-pwm.txt b/Documentation/devicetree/bindings/leds/leds-pwm.txt +index 7297107cf832..6c6583c35f2f 100644 +--- a/Documentation/devicetree/bindings/leds/leds-pwm.txt ++++ b/Documentation/devicetree/bindings/leds/leds-pwm.txt +@@ -13,6 +13,8 @@ node's name represents the name of the corresponding LED. + For the pwms and pwm-names property please refer to: + Documentation/devicetree/bindings/pwm/pwm.txt + - max-brightness : Maximum brightness possible for the LED ++- active-low : (optional) For PWMs where the LED is wired to supply ++ rather than ground. + - label : (optional) + see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : (optional) +diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt +index 9dce540771fb..b9b534ebc0c5 100644 +--- a/Documentation/devicetree/bindings/mmc/mmc.txt ++++ b/Documentation/devicetree/bindings/mmc/mmc.txt +@@ -5,6 +5,8 @@ these definitions. + Interpreted by the OF core: + - reg: Registers location and length. + - interrupts: Interrupts used by the MMC controller. ++- clocks: Clocks needed for the host controller, if any. ++- clock-names: Goes with clocks above. + + Card detection: + If no property below is supplied, host native card detect is used. +@@ -39,6 +41,15 @@ If no property below is supplied, host native card detect is used. + - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported + - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported + ++Card power and reset control: ++The following properties can be specified for cases where the MMC ++peripheral needs additional reset, regulator and clock lines. It is for ++example common for WiFi/BT adapters to have these separate from the main ++MMC bus: ++ - card-reset-gpios: Specify GPIOs for card reset (reset active low) ++ - card-external-vcc-supply: Regulator to drive (independent) card VCC ++ - clock with name "card_ext_clock": External clock provided to the card ++ + *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line + polarity properties, we have to fix the meaning of the "normal" and "inverted" + line levels. We choose to follow the SDHCI standard, which specifies both those +diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt +index 3be5ce7a9654..83137ef5a1ba 100644 +--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt ++++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt +@@ -60,7 +60,8 @@ Parallel display support + - compatible: Should be "fsl,imx-parallel-display" + Optional properties: + - interface_pix_fmt: How this display is connected to the +- display interface. Currently supported types: "rgb24", "rgb565", "bgr666" ++ display interface. Currently supported types: "rgb24", "rgb565", "bgr666", ++ "rgb666" + - edid: verbatim EDID data block describing attached display. + - ddc: phandle describing the i2c bus handling the display data + channel +diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts +index 5bfae54fb780..5cfab68fe43d 100644 +--- a/arch/arm/boot/dts/imx6dl-hummingboard.dts ++++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts +@@ -67,6 +67,13 @@ + status = "okay"; + }; + ++&hdmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_hdmi>; ++ ddc-i2c-bus = <&i2c2>; ++ status = "okay"; ++}; ++ + &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_i2c1>; +@@ -82,6 +89,13 @@ + */ + }; + ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_i2c2>; ++ status = "okay"; ++}; ++ + &iomuxc { + hummingboard { + pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 { +@@ -97,6 +111,12 @@ + >; + }; + ++ pinctrl_hummingboard_hdmi: hummingboard-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ + pinctrl_hummingboard_i2c1: hummingboard-i2c1 { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 +@@ -104,6 +124,13 @@ + >; + }; + ++ pinctrl_hummingboard_i2c2: hummingboard-i2c2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ + pinctrl_hummingboard_spdif: hummingboard-spdif { + fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>; + }; +diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts +index bc5f31e3e892..9efd8b0c8011 100644 +--- a/arch/arm/boot/dts/imx6q-cubox-i.dts ++++ b/arch/arm/boot/dts/imx6q-cubox-i.dts +@@ -13,4 +13,8 @@ + + &sata { + status = "okay"; ++ fsl,transmit-level-mV = <1104>; ++ fsl,transmit-boost-mdB = <0>; ++ fsl,transmit-atten-16ths = <9>; ++ fsl,no-spread-spectrum; + }; +diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +index c2a24888a276..f45380073973 100644 +--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi ++++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +@@ -12,6 +12,19 @@ + pinctrl-0 = <&pinctrl_cubox_i_ir>; + }; + ++ pwmleds { ++ compatible = "pwm-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_pwm1>; ++ ++ front { ++ active-low; ++ label = "imx6:red:front"; ++ max-brightness = <248>; ++ pwms = <&pwm1 0 50000>; ++ }; ++ }; ++ + regulators { + compatible = "simple-bus"; + +@@ -55,6 +68,20 @@ + }; + }; + ++&hdmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_hdmi>; ++ ddc-i2c-bus = <&i2c2>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_i2c2>; ++ status = "okay"; ++}; ++ + &i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_i2c3>; +@@ -69,6 +96,19 @@ + + &iomuxc { + cubox_i { ++ pinctrl_cubox_i_hdmi: cubox-i-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_cubox_i_i2c2: cubox-i-i2c2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ + pinctrl_cubox_i_i2c3: cubox-i-i2c3 { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 +@@ -82,6 +122,10 @@ + >; + }; + ++ pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led { ++ fsl,pins = <MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0>; ++ }; ++ + pinctrl_cubox_i_spdif: cubox-i-spdif { + fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>; + }; +@@ -111,6 +155,28 @@ + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; ++ ++ pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 ++ >; ++ }; ++ ++ pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 ++ >; ++ }; + }; + }; + +@@ -130,9 +196,19 @@ + status = "okay"; + }; + ++&uart4 { ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ status = "okay"; ++}; ++ + &usdhc2 { +- pinctrl-names = "default"; ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; ++ pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>; ++ pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>; + vmmc-supply = <®_3p3v>; + cd-gpios = <&gpio1 4 0>; + status = "okay"; +diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-microsom.dtsi +index d729d0b15f25..a5d72895d9ce 100644 +--- a/arch/arm/boot/dts/imx6qdl-microsom.dtsi ++++ b/arch/arm/boot/dts/imx6qdl-microsom.dtsi +@@ -1,9 +1,69 @@ + /* + * Copyright (C) 2013,2014 Russell King + */ ++#include <dt-bindings/gpio/gpio.h> ++/ { ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_brcm_osc: brcm-osc-reg { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio5 5 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_osc_reg>; ++ regulator-name = "brcm_osc_reg"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ reg_brcm: brcm-reg { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_reg>; ++ regulator-name = "brcm_reg"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ startup-delay-us = <200000>; ++ }; ++ }; ++}; + + &iomuxc { + microsom { ++ pinctrl_microsom_brcm_osc_reg: microsom-brcm-osc-reg { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_brcm_reg: microsom-brcm-reg { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_brcm_wifi: microsom-brcm-wifi { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 ++ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070 ++ MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 ++ MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_brcm_bt: microsom-brcm-bt { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 ++ MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070 ++ MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 ++ >; ++ }; ++ + pinctrl_microsom_uart1: microsom-uart1 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 +@@ -11,6 +71,15 @@ + >; + }; + ++ pinctrl_microsom_uart4_1: microsom-uart4 { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 ++ >; ++ }; ++ + pinctrl_microsom_usbotg: microsom-usbotg { + /* + * Similar to pinctrl_usbotg_2, but we want it +@@ -18,6 +87,17 @@ + */ + fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>; + }; ++ ++ pinctrl_microsom_usdhc1: microsom-usdhc1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 ++ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 ++ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 ++ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 ++ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 ++ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 ++ >; ++ }; + }; + }; + +@@ -27,7 +107,25 @@ + status = "okay"; + }; + ++/* UART4 - Connected to optional BRCM Wifi/BT/FM */ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4_1>; ++ fsl,uart-has-rtscts; ++}; ++ + &usbotg { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_usbotg>; + }; ++ ++/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */ ++&usdhc1 { ++ card-external-vcc-supply = <®_brcm>; ++ card-reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>; ++ keep-power-in-suspend; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>; ++ vmmc-supply = <®_brcm>; ++}; +diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig +index 09e974392fa1..ea50d34f7944 100644 +--- a/arch/arm/configs/imx_v6_v7_defconfig ++++ b/arch/arm/configs/imx_v6_v7_defconfig +@@ -245,6 +245,7 @@ CONFIG_DRM_IMX_TVE=y + CONFIG_DRM_IMX_LDB=y + CONFIG_DRM_IMX_IPUV3_CORE=y + CONFIG_DRM_IMX_IPUV3=y ++CONFIG_DRM_IMX_HDMI=y + CONFIG_COMMON_CLK_DEBUG=y + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_PWM=y +diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c +index 2b4d6acfa34a..fefa6c3d4c86 100644 +--- a/arch/arm/mach-imx/clk-imx6q.c ++++ b/arch/arm/mach-imx/clk-imx6q.c +@@ -454,6 +454,18 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) + clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]); + clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]); + ++ if (cpu_is_imx6dl()) ++ clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]); ++ ++ clk_set_parent(clk[ipu1_di0_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu1_di1_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu2_di0_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu2_di1_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu1_di0_sel], clk[ipu1_di0_pre]); ++ clk_set_parent(clk[ipu1_di1_sel], clk[ipu1_di1_pre]); ++ clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]); ++ clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]); ++ + /* + * The gpmi needs 100MHz frequency in the EDO/Sync mode, + * We can not get the 100MHz from the pll2_pfd0_352m. +diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c +index 61364050fccd..3776f974d1dc 100644 +--- a/arch/arm/mach-imx/clk-pllv3.c ++++ b/arch/arm/mach-imx/clk-pllv3.c +@@ -273,9 +273,10 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; +- u32 val, div; ++ u32 val, newval, div; + u32 mfn, mfd = 1000000; + s64 temp64; ++ int ret; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; +@@ -287,13 +288,27 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, + mfn = temp64; + + val = readl_relaxed(pll->base); +- val &= ~pll->div_mask; +- val |= div; +- writel_relaxed(val, pll->base); ++ ++ /* set the PLL into bypass mode */ ++ newval = val | BM_PLL_BYPASS; ++ writel_relaxed(newval, pll->base); ++ ++ /* configure the new frequency */ ++ newval &= ~pll->div_mask; ++ newval |= div; ++ writel_relaxed(newval, pll->base); + writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); +- writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); ++ writel(mfd, pll->base + PLL_DENOM_OFFSET); + +- return clk_pllv3_wait_lock(pll); ++ ret = clk_pllv3_wait_lock(pll); ++ if (ret == 0 && val & BM_PLL_POWER) { ++ /* only if it locked can we switch back to the PLL */ ++ newval &= ~BM_PLL_BYPASS; ++ newval |= val & BM_PLL_BYPASS; ++ writel(newval, pll->base); ++ } ++ ++ return ret; + } + + static const struct clk_ops clk_pllv3_av_ops = { +diff --git a/drivers/Kconfig b/drivers/Kconfig +index 0a0a90f52d26..05a21b857996 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -174,4 +174,6 @@ source "drivers/powercap/Kconfig" + + source "drivers/mcb/Kconfig" + ++source "drivers/cec/Kconfig" ++ + endmenu +diff --git a/drivers/Makefile b/drivers/Makefile +index 7183b6af5dac..470eec2238ca 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -157,3 +157,4 @@ obj-$(CONFIG_NTB) += ntb/ + obj-$(CONFIG_FMC) += fmc/ + obj-$(CONFIG_POWERCAP) += powercap/ + obj-$(CONFIG_MCB) += mcb/ ++obj-$(CONFIG_CEC) += cec/ +diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c +index 8befeb69eeb1..54e2972fc6da 100644 +--- a/drivers/ata/ahci_imx.c ++++ b/drivers/ata/ahci_imx.c +@@ -62,6 +62,7 @@ struct imx_ahci_priv { + struct regmap *gpr; + bool no_device; + bool first_time; ++ u32 phy_params; + }; + + static int ahci_imx_hotplug; +@@ -246,14 +247,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) + IMX6Q_GPR13_SATA_TX_LVL_MASK | + IMX6Q_GPR13_SATA_MPLL_CLK_EN | + IMX6Q_GPR13_SATA_TX_EDGE_RATE, +- IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | +- IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | +- IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | +- IMX6Q_GPR13_SATA_SPD_MODE_3P0G | +- IMX6Q_GPR13_SATA_MPLL_SS_EN | +- IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | +- IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | +- IMX6Q_GPR13_SATA_TX_LVL_1_025_V); ++ imxpriv->phy_params); + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + IMX6Q_GPR13_SATA_MPLL_CLK_EN); +@@ -324,6 +318,10 @@ static void ahci_imx_error_handler(struct ata_port *ap) + writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); + imx_sata_disable(hpriv); + imxpriv->no_device = true; ++ ++ dev_info(ap->dev, "no device found, disabling link.\n"); ++ dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX ++ ".hotplug=1 to enable hotplug\n"); + } + + static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, +@@ -364,6 +362,165 @@ static const struct of_device_id imx_ahci_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, imx_ahci_of_match); + ++struct reg_value { ++ u32 of_value; ++ u32 reg_value; ++}; ++ ++struct reg_property { ++ const char *name; ++ const struct reg_value *values; ++ size_t num_values; ++ u32 def_value; ++ u32 set_value; ++}; ++ ++static const struct reg_value gpr13_tx_level[] = { ++ { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V }, ++ { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V }, ++ { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V }, ++ { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V }, ++ { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V }, ++ { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V }, ++ { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V }, ++ { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V }, ++ { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V }, ++ { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V }, ++ { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V }, ++ { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V }, ++ { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V }, ++ { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V }, ++ { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V }, ++ { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V }, ++ { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V }, ++ { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V }, ++ { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V }, ++ { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V }, ++ { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V }, ++ { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V }, ++ { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V }, ++ { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V }, ++ { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V }, ++ { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V }, ++ { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V }, ++ { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V }, ++ { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V }, ++ { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V }, ++ { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V }, ++ { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V } ++}; ++ ++static const struct reg_value gpr13_tx_boost[] = { ++ { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB }, ++ { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB }, ++ { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB }, ++ { 111, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, ++ { 148, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, ++ { 185, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, ++ { 222, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, ++ { 259, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, ++ { 296, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, ++ { 333, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, ++ { 370, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, ++ { 407, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, ++ { 444, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, ++ { 481, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, ++ { 528, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, ++ { 575, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB } ++}; ++ ++static const struct reg_value gpr13_tx_atten[] = { ++ { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 }, ++ { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 }, ++ { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 }, ++ { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 }, ++ { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 }, ++ { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 }, ++}; ++ ++static const struct reg_value gpr13_rx_eq[] = { ++ { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB }, ++ { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB }, ++ { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB }, ++ { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB }, ++ { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB }, ++ { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB }, ++ { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB }, ++ { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB }, ++}; ++ ++static const struct reg_property gpr13_props[] = { ++ { ++ .name = "fsl,transmit-level-mV", ++ .values = gpr13_tx_level, ++ .num_values = ARRAY_SIZE(gpr13_tx_level), ++ .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V, ++ }, { ++ .name = "fsl,transmit-boost-mdB", ++ .values = gpr13_tx_boost, ++ .num_values = ARRAY_SIZE(gpr13_tx_boost), ++ .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB, ++ }, { ++ .name = "fsl,transmit-atten-16ths", ++ .values = gpr13_tx_atten, ++ .num_values = ARRAY_SIZE(gpr13_tx_atten), ++ .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16, ++ }, { ++ .name = "fsl,receive-eq-mdB", ++ .values = gpr13_rx_eq, ++ .num_values = ARRAY_SIZE(gpr13_rx_eq), ++ .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB, ++ }, { ++ .name = "fsl,no-spread-spectrum", ++ .def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN, ++ .set_value = 0, ++ }, ++}; ++ ++static u32 imx_ahci_parse_props(struct device *dev, ++ const struct reg_property *prop, size_t num) ++{ ++ struct device_node *np = dev->of_node; ++ u32 reg_value = 0; ++ int i, j; ++ ++ for (i = 0; i < num; i++, prop++) { ++ u32 of_val; ++ ++ if (prop->num_values == 0) { ++ if (of_property_read_bool(np, prop->name)) ++ reg_value |= prop->set_value; ++ else ++ reg_value |= prop->def_value; ++ continue; ++ } ++ ++ if (of_property_read_u32(np, prop->name, &of_val)) { ++ dev_info(dev, "%s not specified, using %08x\n", ++ prop->name, prop->def_value); ++ reg_value |= prop->def_value; ++ continue; ++ } ++ ++ for (j = 0; j < prop->num_values; j++) { ++ if (prop->values[j].of_value == of_val) { ++ dev_info(dev, "%s value %u, using %08x\n", ++ prop->name, of_val, prop->values[j].reg_value); ++ reg_value |= prop->values[j].reg_value; ++ break; ++ } ++ } ++ ++ if (j == prop->num_values) { ++ dev_err(dev, "DT property %s is not a valid value\n", ++ prop->name); ++ reg_value |= prop->def_value; ++ } ++ } ++ ++ return reg_value; ++} ++ + static int imx_ahci_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -392,6 +549,8 @@ static int imx_ahci_probe(struct platform_device *pdev) + } + + if (imxpriv->type == AHCI_IMX6Q) { ++ u32 reg_value; ++ + imxpriv->gpr = syscon_regmap_lookup_by_compatible( + "fsl,imx6q-iomuxc-gpr"); + if (IS_ERR(imxpriv->gpr)) { +@@ -399,6 +558,15 @@ static int imx_ahci_probe(struct platform_device *pdev) + "failed to find fsl,imx6q-iomux-gpr regmap\n"); + return PTR_ERR(imxpriv->gpr); + } ++ ++ reg_value = imx_ahci_parse_props(dev, gpr13_props, ++ ARRAY_SIZE(gpr13_props)); ++ ++ imxpriv->phy_params = ++ IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | ++ IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | ++ IMX6Q_GPR13_SATA_SPD_MODE_3P0G | ++ reg_value; + } + + hpriv = ahci_platform_get_resources(pdev); +diff --git a/drivers/cec/Kconfig b/drivers/cec/Kconfig +new file mode 100644 +index 000000000000..d67cfb83de6a +--- /dev/null ++++ b/drivers/cec/Kconfig +@@ -0,0 +1,14 @@ ++# ++# Consumer Electroncs Control support ++# ++ ++menu "Consumer Electronics Control devices" ++ ++config CEC ++ bool ++ ++config HDMI_CEC_CORE ++ tristate ++ select CEC ++ ++endmenu +diff --git a/drivers/cec/Makefile b/drivers/cec/Makefile +new file mode 100644 +index 000000000000..b94278bc8321 +--- /dev/null ++++ b/drivers/cec/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o +diff --git a/drivers/cec/cec-dev.c b/drivers/cec/cec-dev.c +new file mode 100644 +index 000000000000..ba58d8217851 +--- /dev/null ++++ b/drivers/cec/cec-dev.c +@@ -0,0 +1,384 @@ ++/* ++ * HDMI Consumer Electronics Control ++ * ++ * This provides the user API for communication with HDMI CEC complaint ++ * devices in kernel drivers, and is based upon the protocol developed ++ * by Freescale for their i.MX SoCs. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/cec-dev.h> ++#include <linux/device.h> ++#include <linux/fs.h> ++#include <linux/module.h> ++#include <linux/poll.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++ ++struct cec_event { ++ struct cec_user_event usr; ++ struct list_head node; ++}; ++ ++static struct class *cec_class; ++static int cec_major; ++ ++static void cec_dev_send_message(struct cec_dev *cec_dev, u8 *msg, ++ size_t count) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&cec_dev->lock, flags); ++ cec_dev->retries = 5; ++ cec_dev->write_busy = 1; ++ cec_dev->send_message(cec_dev, msg, count); ++ spin_unlock_irqrestore(&cec_dev->lock, flags); ++} ++ ++void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len) ++{ ++ struct cec_event *event; ++ unsigned long flags; ++ ++ event = kzalloc(sizeof(*event), GFP_ATOMIC); ++ if (event) { ++ event->usr.event_type = type; ++ event->usr.msg_len = len; ++ if (msg) ++ memcpy(event->usr.msg, msg, len); ++ ++ spin_lock_irqsave(&cec_dev->lock, flags); ++ list_add_tail(&event->node, &cec_dev->events); ++ spin_unlock_irqrestore(&cec_dev->lock, flags); ++ wake_up(&cec_dev->waitq); ++ } ++} ++EXPORT_SYMBOL_GPL(cec_dev_event); ++ ++static int cec_dev_lock_write(struct cec_dev *cec_dev, struct file *file) ++ __acquires(cec_dev->mutex) ++{ ++ int ret; ++ ++ do { ++ if (file->f_flags & O_NONBLOCK) { ++ if (cec_dev->write_busy) ++ return -EAGAIN; ++ } else { ++ ret = wait_event_interruptible(cec_dev->waitq, ++ !cec_dev->write_busy); ++ if (ret) ++ break; ++ } ++ ++ ret = mutex_lock_interruptible(&cec_dev->mutex); ++ if (ret) ++ break; ++ ++ if (!cec_dev->write_busy) ++ break; ++ ++ mutex_unlock(&cec_dev->mutex); ++ } while (1); ++ ++ return ret; ++} ++ ++static ssize_t cec_dev_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct cec_dev *cec_dev = file->private_data; ++ ssize_t ret; ++ ++ if (count > sizeof(struct cec_user_event)) ++ count = sizeof(struct cec_user_event); ++ ++ if (!access_ok(VERIFY_WRITE, buf, count)) ++ return -EFAULT; ++ ++ do { ++ struct cec_event *event = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&cec_dev->lock, flags); ++ if (!list_empty(&cec_dev->events)) { ++ event = list_first_entry(&cec_dev->events, ++ struct cec_event, node); ++ list_del(&event->node); ++ } ++ spin_unlock_irqrestore(&cec_dev->lock, flags); ++ ++ if (event) { ++ ret = __copy_to_user(buf, &event->usr, count) ? ++ -EFAULT : count; ++ kfree(event); ++ break; ++ } ++ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ break; ++ } ++ ++ ret = wait_event_interruptible(cec_dev->waitq, ++ !list_empty(&cec_dev->events)); ++ if (ret) ++ break; ++ } while (1); ++ ++ return ret; ++} ++ ++static ssize_t cec_dev_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct cec_dev *cec_dev = file->private_data; ++ u8 msg[MAX_MESSAGE_LEN]; ++ int ret; ++ ++ if (count > sizeof(msg)) ++ return -E2BIG; ++ ++ if (copy_from_user(msg, buf, count)) ++ return -EFAULT; ++ ++ ret = cec_dev_lock_write(cec_dev, file); ++ if (ret) ++ return ret; ++ ++ cec_dev_send_message(cec_dev, msg, count); ++ ++ mutex_unlock(&cec_dev->mutex); ++ ++ return count; ++} ++ ++static long cec_dev_ioctl(struct file *file, u_int cmd, unsigned long arg) ++{ ++ struct cec_dev *cec_dev = file->private_data; ++ int ret; ++ ++ switch (cmd) { ++ case HDMICEC_IOC_O_SETLOGICALADDRESS: ++ case HDMICEC_IOC_SETLOGICALADDRESS: ++ if (arg > 15) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ ret = cec_dev_lock_write(cec_dev, file); ++ if (ret == 0) { ++ unsigned char msg[1]; ++ ++ cec_dev->addresses = BIT(arg); ++ cec_dev->set_address(cec_dev, cec_dev->addresses); ++ ++ /* ++ * Send a ping message with the source and destination ++ * set to our address; the result indicates whether ++ * unit has chosen our address simultaneously. ++ */ ++ msg[0] = arg << 4 | arg; ++ cec_dev_send_message(cec_dev, msg, sizeof(msg)); ++ mutex_unlock(&cec_dev->mutex); ++ } ++ break; ++ ++ case HDMICEC_IOC_STARTDEVICE: ++ ret = mutex_lock_interruptible(&cec_dev->mutex); ++ if (ret == 0) { ++ cec_dev->addresses = BIT(15); ++ cec_dev->set_address(cec_dev, cec_dev->addresses); ++ mutex_unlock(&cec_dev->mutex); ++ } ++ break; ++ ++ case HDMICEC_IOC_STOPDEVICE: ++ ret = 0; ++ break; ++ ++ case HDMICEC_IOC_GETPHYADDRESS: ++ ret = put_user(cec_dev->physical, (u16 __user *)arg); ++ ret = -ENOIOCTLCMD; ++ break; ++ ++ default: ++ ret = -ENOIOCTLCMD; ++ break; ++ } ++ ++ return ret; ++} ++ ++static unsigned cec_dev_poll(struct file *file, poll_table *wait) ++{ ++ struct cec_dev *cec_dev = file->private_data; ++ unsigned mask = 0; ++ ++ poll_wait(file, &cec_dev->waitq, wait); ++ ++ if (cec_dev->write_busy == 0) ++ mask |= POLLOUT | POLLWRNORM; ++ if (!list_empty(&cec_dev->events)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ return mask; ++} ++ ++static int cec_dev_release(struct inode *inode, struct file *file) ++{ ++ struct cec_dev *cec_dev = file->private_data; ++ ++ mutex_lock(&cec_dev->mutex); ++ if (cec_dev->users >= 1) ++ cec_dev->users -= 1; ++ if (cec_dev->users == 0) { ++ /* ++ * Wait for any write to complete before shutting down. ++ * A message should complete in a maximum of 2.75ms * ++ * 160 bits + 4.7ms, or 444.7ms. Let's call that 500ms. ++ * If we time out, shutdown anyway. ++ */ ++ wait_event_timeout(cec_dev->waitq, !cec_dev->write_busy, ++ msecs_to_jiffies(500)); ++ ++ cec_dev->release(cec_dev); ++ ++ while (!list_empty(&cec_dev->events)) { ++ struct cec_event *event; ++ ++ event = list_first_entry(&cec_dev->events, ++ struct cec_event, node); ++ list_del(&event->node); ++ kfree(event); ++ } ++ } ++ mutex_unlock(&cec_dev->mutex); ++ return 0; ++} ++ ++static int cec_dev_open(struct inode *inode, struct file *file) ++{ ++ struct cec_dev *cec_dev = container_of(inode->i_cdev, struct cec_dev, ++ cdev); ++ int ret = 0; ++ ++ nonseekable_open(inode, file); ++ ++ file->private_data = cec_dev; ++ ++ ret = mutex_lock_interruptible(&cec_dev->mutex); ++ if (ret) ++ return ret; ++ ++ if (cec_dev->users++ == 0) { ++ cec_dev->addresses = BIT(15); ++ ++ ret = cec_dev->open(cec_dev); ++ if (ret < 0) ++ cec_dev->users = 0; ++ } ++ mutex_unlock(&cec_dev->mutex); ++ ++ return ret; ++} ++ ++static const struct file_operations hdmi_cec_fops = { ++ .owner = THIS_MODULE, ++ .read = cec_dev_read, ++ .write = cec_dev_write, ++ .open = cec_dev_open, ++ .unlocked_ioctl = cec_dev_ioctl, ++ .release = cec_dev_release, ++ .poll = cec_dev_poll, ++}; ++ ++void cec_dev_init(struct cec_dev *cec_dev, struct module *module) ++{ ++ cec_dev->devn = MKDEV(cec_major, 0); ++ ++ INIT_LIST_HEAD(&cec_dev->events); ++ init_waitqueue_head(&cec_dev->waitq); ++ spin_lock_init(&cec_dev->lock); ++ mutex_init(&cec_dev->mutex); ++ ++ cec_dev->addresses = BIT(15); ++ ++ cdev_init(&cec_dev->cdev, &hdmi_cec_fops); ++ cec_dev->cdev.owner = module; ++} ++EXPORT_SYMBOL_GPL(cec_dev_init); ++ ++int cec_dev_add(struct cec_dev *cec_dev, struct device *dev, const char *name) ++{ ++ struct device *cd; ++ int ret; ++ ++ ret = cdev_add(&cec_dev->cdev, cec_dev->devn, 1); ++ if (ret < 0) ++ goto err_cdev; ++ ++ cd = device_create(cec_class, dev, cec_dev->devn, NULL, name); ++ if (IS_ERR(cd)) { ++ ret = PTR_ERR(cd); ++ dev_err(dev, "can't create device: %d\n", ret); ++ goto err_dev; ++ } ++ ++ return 0; ++ ++ err_dev: ++ cdev_del(&cec_dev->cdev); ++ err_cdev: ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cec_dev_add); ++ ++void cec_dev_remove(struct cec_dev *cec_dev) ++{ ++ device_destroy(cec_class, cec_dev->devn); ++ cdev_del(&cec_dev->cdev); ++} ++EXPORT_SYMBOL_GPL(cec_dev_remove); ++ ++static int cec_init(void) ++{ ++ dev_t dev; ++ int ret; ++ ++ cec_class = class_create(THIS_MODULE, "hdmi-cec"); ++ if (IS_ERR(cec_class)) { ++ ret = PTR_ERR(cec_class); ++ pr_err("cec: can't create cec class: %d\n", ret); ++ goto err_class; ++ } ++ ++ ret = alloc_chrdev_region(&dev, 0, 1, "hdmi-cec"); ++ if (ret) { ++ pr_err("cec: can't create character devices: %d\n", ret); ++ goto err_chrdev; ++ } ++ ++ cec_major = MAJOR(dev); ++ ++ return 0; ++ ++ err_chrdev: ++ class_destroy(cec_class); ++ err_class: ++ return ret; ++} ++subsys_initcall(cec_init); ++ ++static void cec_exit(void) ++{ ++ unregister_chrdev_region(MKDEV(cec_major, 0), 1); ++ class_destroy(cec_class); ++} ++module_exit(cec_exit); ++ ++MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Generic HDMI CEC driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c +index df281b54db01..20585cf62091 100644 +--- a/drivers/gpu/drm/drm_crtc_helper.c ++++ b/drivers/gpu/drm/drm_crtc_helper.c +@@ -140,16 +140,10 @@ drm_encoder_disable(struct drm_encoder *encoder) + static void __drm_helper_disable_unused_functions(struct drm_device *dev) + { + struct drm_encoder *encoder; +- struct drm_connector *connector; + struct drm_crtc *crtc; + + drm_warn_on_modeset_not_all_locked(dev); + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { +- if (!connector->encoder) +- continue; +- } +- + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (!drm_helper_encoder_in_use(encoder)) { + drm_encoder_disable(encoder); +diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c +index 7d0aaed1e23a..f5cf1b0f2748 100644 +--- a/drivers/leds/leds-pwm.c ++++ b/drivers/leds/leds-pwm.c +@@ -69,6 +69,10 @@ static void led_pwm_set(struct led_classdev *led_cdev, + + duty *= brightness; + do_div(duty, max); ++ ++ if (led_dat->active_low) ++ duty = led_dat->period - duty; ++ + led_dat->duty = duty; + + if (led_dat->can_sleep) +@@ -92,55 +96,75 @@ static void led_pwm_cleanup(struct led_pwm_priv *priv) + } + } + +-static int led_pwm_create_of(struct platform_device *pdev, +- struct led_pwm_priv *priv) ++static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, ++ struct led_pwm *led, struct device_node *child) + { +- struct device_node *child; ++ struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; + int ret; + +- for_each_child_of_node(pdev->dev.of_node, child) { +- struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; ++ led_data->active_low = led->active_low; ++ led_data->period = led->pwm_period_ns; ++ led_data->cdev.name = led->name; ++ led_data->cdev.default_trigger = led->default_trigger; ++ led_data->cdev.brightness_set = led_pwm_set; ++ led_data->cdev.brightness = LED_OFF; ++ led_data->cdev.max_brightness = led->max_brightness; ++ led_data->cdev.flags = LED_CORE_SUSPENDRESUME; ++ ++ if (child) ++ led_data->pwm = devm_of_pwm_get(dev, child, NULL); ++ else ++ led_data->pwm = devm_pwm_get(dev, led->name); ++ if (IS_ERR(led_data->pwm)) { ++ ret = PTR_ERR(led_data->pwm); ++ dev_err(dev, "unable to request PWM for %s: %d\n", ++ led->name, ret); ++ return ret; ++ } + +- led_dat->cdev.name = of_get_property(child, "label", +- NULL) ? : child->name; ++ if (child) ++ led_data->period = pwm_get_period(led_data->pwm); + +- led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL); +- if (IS_ERR(led_dat->pwm)) { +- dev_err(&pdev->dev, "unable to request PWM for %s\n", +- led_dat->cdev.name); +- ret = PTR_ERR(led_dat->pwm); +- goto err; +- } +- /* Get the period from PWM core when n*/ +- led_dat->period = pwm_get_period(led_dat->pwm); ++ led_data->can_sleep = pwm_can_sleep(led_data->pwm); ++ if (led_data->can_sleep) ++ INIT_WORK(&led_data->work, led_pwm_work); + +- led_dat->cdev.default_trigger = of_get_property(child, +- "linux,default-trigger", NULL); +- of_property_read_u32(child, "max-brightness", +- &led_dat->cdev.max_brightness); ++ ret = led_classdev_register(dev, &led_data->cdev); ++ if (ret == 0) { ++ priv->num_leds++; ++ } else { ++ dev_err(dev, "failed to register PWM led for %s: %d\n", ++ led->name, ret); ++ } + +- led_dat->cdev.brightness_set = led_pwm_set; +- led_dat->cdev.brightness = LED_OFF; +- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; ++ return ret; ++} + +- led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); +- if (led_dat->can_sleep) +- INIT_WORK(&led_dat->work, led_pwm_work); ++static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) ++{ ++ struct device_node *child; ++ struct led_pwm led; ++ int ret = 0; + +- ret = led_classdev_register(&pdev->dev, &led_dat->cdev); +- if (ret < 0) { +- dev_err(&pdev->dev, "failed to register for %s\n", +- led_dat->cdev.name); ++ memset(&led, 0, sizeof(led)); ++ ++ for_each_child_of_node(dev->of_node, child) { ++ led.name = of_get_property(child, "label", NULL) ? : ++ child->name; ++ ++ led.default_trigger = of_get_property(child, ++ "linux,default-trigger", NULL); ++ led.active_low = of_property_read_bool(child, "active-low"); ++ of_property_read_u32(child, "max-brightness", ++ &led.max_brightness); ++ ++ ret = led_pwm_add(dev, priv, &led, child); ++ if (ret) { + of_node_put(child); +- goto err; ++ break; + } +- priv->num_leds++; + } + +- return 0; +-err: +- led_pwm_cleanup(priv); +- + return ret; + } + +@@ -166,51 +190,23 @@ static int led_pwm_probe(struct platform_device *pdev) + + if (pdata) { + for (i = 0; i < count; i++) { +- struct led_pwm *cur_led = &pdata->leds[i]; +- struct led_pwm_data *led_dat = &priv->leds[i]; +- +- led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name); +- if (IS_ERR(led_dat->pwm)) { +- ret = PTR_ERR(led_dat->pwm); +- dev_err(&pdev->dev, +- "unable to request PWM for %s\n", +- cur_led->name); +- goto err; +- } +- +- led_dat->cdev.name = cur_led->name; +- led_dat->cdev.default_trigger = cur_led->default_trigger; +- led_dat->active_low = cur_led->active_low; +- led_dat->period = cur_led->pwm_period_ns; +- led_dat->cdev.brightness_set = led_pwm_set; +- led_dat->cdev.brightness = LED_OFF; +- led_dat->cdev.max_brightness = cur_led->max_brightness; +- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; +- +- led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); +- if (led_dat->can_sleep) +- INIT_WORK(&led_dat->work, led_pwm_work); +- +- ret = led_classdev_register(&pdev->dev, &led_dat->cdev); +- if (ret < 0) +- goto err; ++ ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i], ++ NULL); ++ if (ret) ++ break; + } +- priv->num_leds = count; + } else { +- ret = led_pwm_create_of(pdev, priv); +- if (ret) +- return ret; ++ ret = led_pwm_create_of(&pdev->dev, priv); ++ } ++ ++ if (ret) { ++ led_pwm_cleanup(priv); ++ return ret; + } + + platform_set_drvdata(pdev, priv); + + return 0; +- +-err: +- priv->num_leds = i; +- led_pwm_cleanup(priv); +- +- return ret; + } + + static int led_pwm_remove(struct platform_device *pdev) +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index acbc3f2aaaf9..41c4033ec765 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -13,11 +13,13 @@ + #include <linux/module.h> + #include <linux/init.h> + #include <linux/interrupt.h> ++#include <linux/clk.h> + #include <linux/completion.h> + #include <linux/device.h> + #include <linux/delay.h> + #include <linux/pagemap.h> + #include <linux/err.h> ++#include <linux/gpio.h> + #include <linux/leds.h> + #include <linux/scatterlist.h> + #include <linux/log2.h> +@@ -1504,6 +1506,43 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) + mmc_host_clk_release(host); + } + ++static void mmc_card_power_up(struct mmc_host *host) ++{ ++ int i; ++ struct gpio_desc **gds = host->card_reset_gpios; ++ ++ for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) { ++ if (gds[i]) { ++ dev_dbg(host->parent, "Asserting reset line %d", i); ++ gpiod_set_value(gds[i], 1); ++ } ++ } ++ ++ if (host->card_regulator) { ++ dev_dbg(host->parent, "Enabling external regulator"); ++ if (regulator_enable(host->card_regulator)) ++ dev_err(host->parent, "Failed to enable external regulator"); ++ } ++ ++ if (host->card_clk) { ++ dev_dbg(host->parent, "Enabling external clock"); ++ clk_prepare_enable(host->card_clk); ++ } ++ ++ /* 2ms delay to let clocks and power settle */ ++ mmc_delay(20); ++ ++ for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) { ++ if (gds[i]) { ++ dev_dbg(host->parent, "Deasserting reset line %d", i); ++ gpiod_set_value(gds[i], 0); ++ } ++ } ++ ++ /* 2ms delay to after reset release */ ++ mmc_delay(20); ++} ++ + /* + * Apply power to the MMC stack. This is a two-stage process. + * First, we enable power to the card without the clock running. +@@ -1520,6 +1559,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) + if (host->ios.power_mode == MMC_POWER_ON) + return; + ++ /* Power up the card/module first, if needed */ ++ mmc_card_power_up(host); ++ + mmc_host_clk_hold(host); + + host->ios.vdd = fls(ocr) - 1; +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index fdea825dbb24..c523f55b317c 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -12,14 +12,18 @@ + * MMC host class device management + */ + ++#include <linux/kernel.h> ++#include <linux/clk.h> + #include <linux/device.h> + #include <linux/err.h> ++#include <linux/gpio/consumer.h> + #include <linux/idr.h> + #include <linux/of.h> + #include <linux/of_gpio.h> + #include <linux/pagemap.h> + #include <linux/export.h> + #include <linux/leds.h> ++#include <linux/regulator/consumer.h> + #include <linux/slab.h> + #include <linux/suspend.h> + +@@ -457,6 +461,66 @@ int mmc_of_parse(struct mmc_host *host) + + EXPORT_SYMBOL(mmc_of_parse); + ++static int mmc_of_parse_child(struct mmc_host *host) ++{ ++ struct device_node *np; ++ struct clk *clk; ++ int i; ++ ++ if (!host->parent || !host->parent->of_node) ++ return 0; ++ ++ np = host->parent->of_node; ++ ++ host->card_regulator = regulator_get(host->parent, "card-external-vcc"); ++ if (IS_ERR(host->card_regulator)) { ++ if (PTR_ERR(host->card_regulator) == -EPROBE_DEFER) ++ return PTR_ERR(host->card_regulator); ++ host->card_regulator = NULL; ++ } ++ ++ /* Parse card power/reset/clock control */ ++ if (of_find_property(np, "card-reset-gpios", NULL)) { ++ struct gpio_desc *gpd; ++ int level = 0; ++ ++ /* ++ * If the regulator is enabled, then we can hold the ++ * card in reset with an active high resets. Otherwise, ++ * hold the resets low. ++ */ ++ if (host->card_regulator && regulator_is_enabled(host->card_regulator)) ++ level = 1; ++ ++ for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) { ++ gpd = devm_gpiod_get_index(host->parent, "card-reset", i); ++ if (IS_ERR(gpd)) { ++ if (PTR_ERR(gpd) == -EPROBE_DEFER) ++ return PTR_ERR(gpd); ++ break; ++ } ++ gpiod_direction_output(gpd, gpiod_is_active_low(gpd) | level); ++ host->card_reset_gpios[i] = gpd; ++ } ++ ++ gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios)); ++ if (!IS_ERR(gpd)) { ++ dev_warn(host->parent, "More reset gpios than we can handle"); ++ gpiod_put(gpd); ++ } ++ } ++ ++ clk = of_clk_get_by_name(np, "card_ext_clock"); ++ if (IS_ERR(clk)) { ++ if (PTR_ERR(clk) == -EPROBE_DEFER) ++ return PTR_ERR(clk); ++ clk = NULL; ++ } ++ host->card_clk = clk; ++ ++ return 0; ++} ++ + /** + * mmc_alloc_host - initialise the per-host structure. + * @extra: sizeof private data structure +@@ -536,6 +600,10 @@ int mmc_add_host(struct mmc_host *host) + { + int err; + ++ err = mmc_of_parse_child(host); ++ if (err) ++ return err; ++ + WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && + !host->ops->enable_sdio_irq); + +diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c +index aaa90460ed23..5cc13c8d35bb 100644 +--- a/drivers/mmc/core/sdio_irq.c ++++ b/drivers/mmc/core/sdio_irq.c +@@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host) + return ret; + } + ++void sdio_run_irqs(struct mmc_host *host) ++{ ++ mmc_claim_host(host); ++ host->sdio_irq_pending = true; ++ process_sdio_pending_irqs(host); ++ mmc_release_host(host); ++} ++EXPORT_SYMBOL_GPL(sdio_run_irqs); ++ + static int sdio_irq_thread(void *_host) + { + struct mmc_host *host = _host; +@@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card) + WARN_ON(!host->claimed); + + if (!host->sdio_irqs++) { +- atomic_set(&host->sdio_irq_thread_abort, 0); +- host->sdio_irq_thread = +- kthread_run(sdio_irq_thread, host, "ksdioirqd/%s", +- mmc_hostname(host)); +- if (IS_ERR(host->sdio_irq_thread)) { +- int err = PTR_ERR(host->sdio_irq_thread); +- host->sdio_irqs--; +- return err; ++ if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { ++ atomic_set(&host->sdio_irq_thread_abort, 0); ++ host->sdio_irq_thread = ++ kthread_run(sdio_irq_thread, host, ++ "ksdioirqd/%s", mmc_hostname(host)); ++ if (IS_ERR(host->sdio_irq_thread)) { ++ int err = PTR_ERR(host->sdio_irq_thread); ++ host->sdio_irqs--; ++ return err; ++ } ++ } else { ++ mmc_host_clk_hold(host); ++ host->ops->enable_sdio_irq(host, 1); ++ mmc_host_clk_release(host); + } + } + +@@ -211,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card) + BUG_ON(host->sdio_irqs < 1); + + if (!--host->sdio_irqs) { +- atomic_set(&host->sdio_irq_thread_abort, 1); +- kthread_stop(host->sdio_irq_thread); ++ if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { ++ atomic_set(&host->sdio_irq_thread_abort, 1); ++ kthread_stop(host->sdio_irq_thread); ++ } else { ++ mmc_host_clk_hold(host); ++ host->ops->enable_sdio_irq(host, 0); ++ mmc_host_clk_release(host); ++ } + } + + return 0; +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 8aaf8c1f3f63..d8c1f31ab37f 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -25,8 +25,7 @@ config MMC_PXA + If unsure, say N. + + config MMC_SDHCI +- tristate "Secure Digital Host Controller Interface support" +- depends on HAS_DMA ++ tristate + help + This selects the generic Secure Digital Host Controller Interface. + It is used by manufacturers such as Texas Instruments(R), Ricoh(R) +@@ -59,7 +58,8 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER + + config MMC_SDHCI_PCI + tristate "SDHCI support on PCI bus" +- depends on MMC_SDHCI && PCI ++ depends on PCI && HAS_DMA ++ select MMC_SDHCI + help + This selects the PCI Secure Digital Host Controller Interface. + Most controllers found today are PCI devices. +@@ -83,7 +83,8 @@ config MMC_RICOH_MMC + + config MMC_SDHCI_ACPI + tristate "SDHCI support for ACPI enumerated SDHCI controllers" +- depends on MMC_SDHCI && ACPI ++ depends on ACPI && HAS_DMA ++ select MMC_SDHCI + help + This selects support for ACPI enumerated SDHCI controllers, + identified by ACPI Compatibility ID PNP0D40 or specific +@@ -94,8 +95,8 @@ config MMC_SDHCI_ACPI + If unsure, say N. + + config MMC_SDHCI_PLTFM +- tristate "SDHCI platform and OF driver helper" +- depends on MMC_SDHCI ++ tristate ++ select MMC_SDHCI + help + This selects the common helper functions support for Secure Digital + Host Controller Interface based platform and OF drivers. +@@ -106,8 +107,8 @@ config MMC_SDHCI_PLTFM + + config MMC_SDHCI_OF_ARASAN + tristate "SDHCI OF support for the Arasan SDHCI controllers" +- depends on MMC_SDHCI_PLTFM +- depends on OF ++ depends on OF && HAS_DMA ++ select MMC_SDHCI_PLTFM + help + This selects the Arasan Secure Digital Host Controller Interface + (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. +@@ -118,9 +119,9 @@ config MMC_SDHCI_OF_ARASAN + + config MMC_SDHCI_OF_ESDHC + tristate "SDHCI OF support for the Freescale eSDHC controller" +- depends on MMC_SDHCI_PLTFM +- depends on PPC_OF ++ depends on PPC_OF && HAS_DMA + select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER ++ select MMC_SDHCI_PLTFM + help + This selects the Freescale eSDHC controller support. + +@@ -130,9 +131,9 @@ config MMC_SDHCI_OF_ESDHC + + config MMC_SDHCI_OF_HLWD + tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" +- depends on MMC_SDHCI_PLTFM +- depends on PPC_OF ++ depends on PPC_OF && HAS_DMA + select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER ++ select MMC_SDHCI_PLTFM + help + This selects the Secure Digital Host Controller Interface (SDHCI) + found in the "Hollywood" chipset of the Nintendo Wii video game +@@ -144,8 +145,8 @@ config MMC_SDHCI_OF_HLWD + + config MMC_SDHCI_CNS3XXX + tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" +- depends on ARCH_CNS3XXX +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_CNS3XXX && HAS_DMA ++ select MMC_SDHCI_PLTFM + help + This selects the SDHCI support for CNS3xxx System-on-Chip devices. + +@@ -155,9 +156,9 @@ config MMC_SDHCI_CNS3XXX + + config MMC_SDHCI_ESDHC_IMX + tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" +- depends on ARCH_MXC +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_MXC && HAS_DMA + select MMC_SDHCI_IO_ACCESSORS ++ select MMC_SDHCI_PLTFM + help + This selects the Freescale eSDHC/uSDHC controller support + found on i.MX25, i.MX35 i.MX5x and i.MX6x. +@@ -168,9 +169,9 @@ config MMC_SDHCI_ESDHC_IMX + + config MMC_SDHCI_DOVE + tristate "SDHCI support on Marvell's Dove SoC" +- depends on ARCH_DOVE +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_DOVE && HAS_DMA + select MMC_SDHCI_IO_ACCESSORS ++ select MMC_SDHCI_PLTFM + help + This selects the Secure Digital Host Controller Interface in + Marvell's Dove SoC. +@@ -181,9 +182,9 @@ config MMC_SDHCI_DOVE + + config MMC_SDHCI_TEGRA + tristate "SDHCI platform support for the Tegra SD/MMC Controller" +- depends on ARCH_TEGRA +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_TEGRA && HAS_DMA + select MMC_SDHCI_IO_ACCESSORS ++ select MMC_SDHCI_PLTFM + help + This selects the Tegra SD/MMC controller. If you have a Tegra + platform with SD or MMC devices, say Y or M here. +@@ -192,7 +193,8 @@ config MMC_SDHCI_TEGRA + + config MMC_SDHCI_S3C + tristate "SDHCI support on Samsung S3C SoC" +- depends on MMC_SDHCI && PLAT_SAMSUNG ++ depends on PLAT_SAMSUNG && HAS_DMA ++ select MMC_SDHCI + help + This selects the Secure Digital Host Controller Interface (SDHCI) + often referrered to as the HSMMC block in some of the Samsung S3C +@@ -204,8 +206,8 @@ config MMC_SDHCI_S3C + + config MMC_SDHCI_SIRF + tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" +- depends on ARCH_SIRF +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_SIRF && HAS_DMA ++ select MMC_SDHCI_PLTFM + help + This selects the SDHCI support for SiRF System-on-Chip devices. + +@@ -215,8 +217,7 @@ config MMC_SDHCI_SIRF + + config MMC_SDHCI_PXAV3 + tristate "Marvell MMP2 SD Host Controller support (PXAV3)" +- depends on CLKDEV_LOOKUP +- select MMC_SDHCI ++ depends on CLKDEV_LOOKUP && HAS_DMA + select MMC_SDHCI_PLTFM + default CPU_MMP2 + help +@@ -228,8 +229,7 @@ config MMC_SDHCI_PXAV3 + + config MMC_SDHCI_PXAV2 + tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" +- depends on CLKDEV_LOOKUP +- select MMC_SDHCI ++ depends on CLKDEV_LOOKUP && HAS_DMA + select MMC_SDHCI_PLTFM + default CPU_PXA910 + help +@@ -241,7 +241,8 @@ config MMC_SDHCI_PXAV2 + + config MMC_SDHCI_SPEAR + tristate "SDHCI support on ST SPEAr platform" +- depends on MMC_SDHCI && PLAT_SPEAR ++ depends on PLAT_SPEAR && HAS_DMA ++ select MMC_SDHCI + help + This selects the Secure Digital Host Controller Interface (SDHCI) + often referrered to as the HSMMC block in some of the ST SPEAR range +@@ -263,7 +264,7 @@ config MMC_SDHCI_S3C_DMA + + config MMC_SDHCI_BCM_KONA + tristate "SDHCI support on Broadcom KONA platform" +- depends on ARCH_BCM_MOBILE ++ depends on ARCH_BCM_MOBILE && HAS_DMA + select MMC_SDHCI_PLTFM + help + This selects the Broadcom Kona Secure Digital Host Controller +@@ -274,9 +275,9 @@ config MMC_SDHCI_BCM_KONA + + config MMC_SDHCI_BCM2835 + tristate "SDHCI platform support for the BCM2835 SD/MMC Controller" +- depends on ARCH_BCM2835 +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_BCM2835 && HAS_DMA + select MMC_SDHCI_IO_ACCESSORS ++ select MMC_SDHCI_PLTFM + help + This selects the BCM2835 SD/MMC controller. If you have a BCM2835 + platform with SD or MMC devices, say Y or M here. +diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c +index cced599d5aeb..a2c12ebb376e 100644 +--- a/drivers/mmc/host/dw_mmc.c ++++ b/drivers/mmc/host/dw_mmc.c +@@ -2140,6 +2140,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) + if (!mmc) + return -ENOMEM; + ++ mmc_of_parse(mmc); ++ + slot = mmc_priv(mmc); + slot->id = id; + slot->mmc = mmc; +diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c +index ebb3f392b589..8ce3c28cb76e 100644 +--- a/drivers/mmc/host/sdhci-acpi.c ++++ b/drivers/mmc/host/sdhci-acpi.c +@@ -102,11 +102,19 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) + } + + static const struct sdhci_ops sdhci_acpi_ops_dflt = { ++ .set_clock = sdhci_set_clock, + .enable_dma = sdhci_acpi_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static const struct sdhci_ops sdhci_acpi_ops_int = { ++ .set_clock = sdhci_set_clock, + .enable_dma = sdhci_acpi_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + .hw_reset = sdhci_acpi_int_hw_reset, + }; + +diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c +index 6f166e63b817..dd780c315a63 100644 +--- a/drivers/mmc/host/sdhci-bcm-kona.c ++++ b/drivers/mmc/host/sdhci-bcm-kona.c +@@ -206,9 +206,13 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, + } + + static struct sdhci_ops sdhci_bcm_kona_ops = { ++ .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_bcm_kona_get_max_clk, + .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, + .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + .card_event = sdhci_bcm_kona_card_event, + }; + +diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c +index f6d8d67c545f..46af9a439d7b 100644 +--- a/drivers/mmc/host/sdhci-bcm2835.c ++++ b/drivers/mmc/host/sdhci-bcm2835.c +@@ -131,8 +131,12 @@ static const struct sdhci_ops bcm2835_sdhci_ops = { + .read_l = bcm2835_sdhci_readl, + .read_w = bcm2835_sdhci_readw, + .read_b = bcm2835_sdhci_readb, ++ .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_min_clock = bcm2835_sdhci_get_min_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = { +diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c +index f2cc26633cb2..14b74075589a 100644 +--- a/drivers/mmc/host/sdhci-cns3xxx.c ++++ b/drivers/mmc/host/sdhci-cns3xxx.c +@@ -30,13 +30,12 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) + u16 clk; + unsigned long timeout; + +- if (clock == host->clock) +- return; ++ host->mmc->actual_clock = 0; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) +- goto out; ++ return; + + while (host->max_clk / div > clock) { + /* +@@ -75,13 +74,14 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +-out: +- host->clock = clock; + } + + static const struct sdhci_ops sdhci_cns3xxx_ops = { + .get_max_clock = sdhci_cns3xxx_get_max_clk, + .set_clock = sdhci_cns3xxx_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { +@@ -90,8 +90,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | +- SDHCI_QUIRK_NONSTANDARD_CLOCK, ++ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, + }; + + static int sdhci_cns3xxx_probe(struct platform_device *pdev) +diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c +index 736d7a2eb7ec..0d315f4496c8 100644 +--- a/drivers/mmc/host/sdhci-dove.c ++++ b/drivers/mmc/host/sdhci-dove.c +@@ -86,6 +86,10 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) + static const struct sdhci_ops sdhci_dove_ops = { + .read_w = sdhci_dove_readw, + .read_l = sdhci_dove_readl, ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static const struct sdhci_pltfm_data sdhci_dove_pdata = { +diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c +index b841bb7cd371..4866d802f9e2 100644 +--- a/drivers/mmc/host/sdhci-esdhc-imx.c ++++ b/drivers/mmc/host/sdhci-esdhc-imx.c +@@ -160,7 +160,6 @@ struct pltfm_imx_data { + MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ + WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ + } multiblock_status; +- u32 uhs_mode; + u32 is_ddr; + }; + +@@ -382,7 +381,6 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) + if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) + ret |= SDHCI_CTRL_TUNED_CLK; + +- ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); + ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; + + return ret; +@@ -429,7 +427,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) + else + new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; + writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); +- imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); + if (val & SDHCI_CTRL_TUNED_CLK) +@@ -600,12 +597,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, + u32 temp, val; + + if (clock == 0) { ++ host->mmc->actual_clock = 0; ++ + if (esdhc_is_usdhc(imx_data)) { + val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); + writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, + host->ioaddr + ESDHC_VENDOR_SPEC); + } +- goto out; ++ return; + } + + if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr) +@@ -645,8 +644,6 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, + } + + mdelay(1); +-out: +- host->clock = clock; + } + + static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) +@@ -668,7 +665,7 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) + return -ENOSYS; + } + +-static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) ++static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) + { + u32 ctrl; + +@@ -686,8 +683,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) + + esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, + SDHCI_HOST_CONTROL); +- +- return 0; + } + + static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) +@@ -697,6 +692,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) + /* FIXME: delay a bit for card to be ready for next tuning due to errors */ + mdelay(1); + ++ /* This is balanced by the runtime put in sdhci_tasklet_finish */ + pm_runtime_get_sync(host->mmc->parent); + reg = readl(host->ioaddr + ESDHC_MIX_CTRL); + reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | +@@ -713,13 +709,12 @@ static void esdhc_request_done(struct mmc_request *mrq) + complete(&mrq->completion); + } + +-static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode) ++static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode, ++ struct scatterlist *sg) + { + struct mmc_command cmd = {0}; + struct mmc_request mrq = {NULL}; + struct mmc_data data = {0}; +- struct scatterlist sg; +- char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN]; + + cmd.opcode = opcode; + cmd.arg = 0; +@@ -728,11 +723,9 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode) + data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN; + data.blocks = 1; + data.flags = MMC_DATA_READ; +- data.sg = &sg; ++ data.sg = sg; + data.sg_len = 1; + +- sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern)); +- + mrq.cmd = &cmd; + mrq.cmd->mrq = &mrq; + mrq.data = &data; +@@ -742,14 +735,12 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode) + mrq.done = esdhc_request_done; + init_completion(&(mrq.completion)); + +- disable_irq(host->irq); +- spin_lock(&host->lock); ++ spin_lock_irq(&host->lock); + host->mrq = &mrq; + + sdhci_send_command(host, mrq.cmd); + +- spin_unlock(&host->lock); +- enable_irq(host->irq); ++ spin_unlock_irq(&host->lock); + + wait_for_completion(&mrq.completion); + +@@ -772,13 +763,21 @@ static void esdhc_post_tuning(struct sdhci_host *host) + + static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) + { ++ struct scatterlist sg; ++ char *tuning_pattern; + int min, max, avg, ret; + ++ tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL); ++ if (!tuning_pattern) ++ return -ENOMEM; ++ ++ sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN); ++ + /* find the mininum delay first which can pass tuning */ + min = ESDHC_TUNE_CTRL_MIN; + while (min < ESDHC_TUNE_CTRL_MAX) { + esdhc_prepare_tuning(host, min); +- if (!esdhc_send_tuning_cmd(host, opcode)) ++ if (!esdhc_send_tuning_cmd(host, opcode, &sg)) + break; + min += ESDHC_TUNE_CTRL_STEP; + } +@@ -787,7 +786,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) + max = min + ESDHC_TUNE_CTRL_STEP; + while (max < ESDHC_TUNE_CTRL_MAX) { + esdhc_prepare_tuning(host, max); +- if (esdhc_send_tuning_cmd(host, opcode)) { ++ if (esdhc_send_tuning_cmd(host, opcode, &sg)) { + max -= ESDHC_TUNE_CTRL_STEP; + break; + } +@@ -797,9 +796,11 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) + /* use average delay to get the best timing */ + avg = (min + max) / 2; + esdhc_prepare_tuning(host, avg); +- ret = esdhc_send_tuning_cmd(host, opcode); ++ ret = esdhc_send_tuning_cmd(host, opcode, &sg); + esdhc_post_tuning(host); + ++ kfree(tuning_pattern); ++ + dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", + ret ? "failed" : "passed", avg, ret); + +@@ -837,28 +838,20 @@ static int esdhc_change_pinstate(struct sdhci_host *host, + return pinctrl_select_state(imx_data->pinctrl, pinctrl); + } + +-static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) ++static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct esdhc_platform_data *boarddata = &imx_data->boarddata; + +- switch (uhs) { ++ switch (timing) { + case MMC_TIMING_UHS_SDR12: +- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12; +- break; + case MMC_TIMING_UHS_SDR25: +- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25; +- break; + case MMC_TIMING_UHS_SDR50: +- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50; +- break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: +- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104; + break; + case MMC_TIMING_UHS_DDR50: +- imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50; + writel(readl(host->ioaddr + ESDHC_MIX_CTRL) | + ESDHC_MIX_CTRL_DDREN, + host->ioaddr + ESDHC_MIX_CTRL); +@@ -875,7 +868,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) + break; + } + +- return esdhc_change_pinstate(host, uhs); ++ esdhc_change_pinstate(host, timing); ++} ++ ++static void esdhc_reset(struct sdhci_host *host, u8 mask) ++{ ++ sdhci_reset(host, mask); ++ ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + } + + static struct sdhci_ops sdhci_esdhc_ops = { +@@ -888,8 +889,9 @@ static struct sdhci_ops sdhci_esdhc_ops = { + .get_max_clock = esdhc_pltfm_get_max_clock, + .get_min_clock = esdhc_pltfm_get_min_clock, + .get_ro = esdhc_pltfm_get_ro, +- .platform_bus_width = esdhc_pltfm_bus_width, ++ .set_bus_width = esdhc_pltfm_set_bus_width, + .set_uhs_signaling = esdhc_set_uhs_signaling, ++ .reset = esdhc_reset, + }; + + static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { +@@ -1170,8 +1172,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) + + ret = sdhci_runtime_suspend_host(host); + +- clk_disable_unprepare(imx_data->clk_per); +- clk_disable_unprepare(imx_data->clk_ipg); ++ if (!sdhci_sdio_irq_enabled(host)) { ++ clk_disable_unprepare(imx_data->clk_per); ++ clk_disable_unprepare(imx_data->clk_ipg); ++ } + clk_disable_unprepare(imx_data->clk_ahb); + + return ret; +@@ -1183,8 +1187,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; + +- clk_prepare_enable(imx_data->clk_per); +- clk_prepare_enable(imx_data->clk_ipg); ++ if (!sdhci_sdio_irq_enabled(host)) { ++ clk_prepare_enable(imx_data->clk_per); ++ clk_prepare_enable(imx_data->clk_ipg); ++ } + clk_prepare_enable(imx_data->clk_ahb); + + return sdhci_runtime_resume_host(host); +diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h +index a7d9f95a7b03..3497cfaf683c 100644 +--- a/drivers/mmc/host/sdhci-esdhc.h ++++ b/drivers/mmc/host/sdhci-esdhc.h +@@ -20,10 +20,8 @@ + + #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ + SDHCI_QUIRK_NO_BUSY_IRQ | \ +- SDHCI_QUIRK_NONSTANDARD_CLOCK | \ + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ +- SDHCI_QUIRK_PIO_NEEDS_DELAY | \ +- SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) ++ SDHCI_QUIRK_PIO_NEEDS_DELAY) + + #define ESDHC_SYSTEM_CONTROL 0x2c + #define ESDHC_CLOCK_MASK 0x0000fff0 +diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c +index f7c7cf62437d..5bd1092310f2 100644 +--- a/drivers/mmc/host/sdhci-of-arasan.c ++++ b/drivers/mmc/host/sdhci-of-arasan.c +@@ -52,8 +52,12 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) + } + + static struct sdhci_ops sdhci_arasan_ops = { ++ .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_arasan_get_timeout_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static struct sdhci_pltfm_data sdhci_arasan_pdata = { +diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c +index 0b249970b119..605815e52f5f 100644 +--- a/drivers/mmc/host/sdhci-of-esdhc.c ++++ b/drivers/mmc/host/sdhci-of-esdhc.c +@@ -199,13 +199,14 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) + + static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) + { +- + int pre_div = 2; + int div = 1; + u32 temp; + ++ host->mmc->actual_clock = 0; ++ + if (clock == 0) +- goto out; ++ return; + + /* Workaround to reduce the clock frequency for p1010 esdhc */ + if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { +@@ -238,24 +239,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) + | (pre_div << ESDHC_PREDIV_SHIFT)); + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + mdelay(1); +-out: +- host->clock = clock; +-} +- +-#ifdef CONFIG_PM +-static u32 esdhc_proctl; +-static void esdhc_of_suspend(struct sdhci_host *host) +-{ +- esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); + } + +-static void esdhc_of_resume(struct sdhci_host *host) +-{ +- esdhc_of_enable_dma(host); +- sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); +-} +-#endif +- + static void esdhc_of_platform_init(struct sdhci_host *host) + { + u32 vvn; +@@ -269,7 +254,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host) + host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; + } + +-static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) ++static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) + { + u32 ctrl; + +@@ -289,8 +274,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) + + clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL, + ESDHC_CTRL_BUSWIDTH_MASK, ctrl); +- +- return 0; + } + + static const struct sdhci_ops sdhci_esdhc_ops = { +@@ -305,13 +288,46 @@ static const struct sdhci_ops sdhci_esdhc_ops = { + .get_max_clock = esdhc_of_get_max_clock, + .get_min_clock = esdhc_of_get_min_clock, + .platform_init = esdhc_of_platform_init, +-#ifdef CONFIG_PM +- .platform_suspend = esdhc_of_suspend, +- .platform_resume = esdhc_of_resume, +-#endif + .adma_workaround = esdhci_of_adma_workaround, +- .platform_bus_width = esdhc_pltfm_bus_width, ++ .set_bus_width = esdhc_pltfm_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++}; ++ ++#ifdef CONFIG_PM ++ ++static u32 esdhc_proctl; ++static int esdhc_of_suspend(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ ++ esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); ++ ++ return sdhci_suspend_host(host); ++} ++ ++static void esdhc_of_resume(device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ int ret = sdhci_resume_host(host); ++ ++ if (ret == 0) { ++ /* Isn't this already done by sdhci_resume_host() ? --rmk */ ++ esdhc_of_enable_dma(host); ++ sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); ++ } ++ ++ return ret; ++} ++ ++static const struct dev_pm_ops esdhc_pmops = { ++ .suspend = esdhci_of_suspend, ++ .resume = esdhci_of_resume, + }; ++#define ESDHC_PMOPS (&esdhc_pmops) ++#else ++#define ESDHC_PMOPS NULL ++#endif + + static const struct sdhci_pltfm_data sdhci_esdhc_pdata = { + /* +@@ -374,7 +390,7 @@ static struct platform_driver sdhci_esdhc_driver = { + .name = "sdhci-esdhc", + .owner = THIS_MODULE, + .of_match_table = sdhci_esdhc_of_match, +- .pm = SDHCI_PLTFM_PMOPS, ++ .pm = ESDHC_PMOPS, + }, + .probe = sdhci_esdhc_probe, + .remove = sdhci_esdhc_remove, +diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c +index 57c514a81ca5..b341661369a2 100644 +--- a/drivers/mmc/host/sdhci-of-hlwd.c ++++ b/drivers/mmc/host/sdhci-of-hlwd.c +@@ -58,6 +58,10 @@ static const struct sdhci_ops sdhci_hlwd_ops = { + .write_l = sdhci_hlwd_writel, + .write_w = sdhci_hlwd_writew, + .write_b = sdhci_hlwd_writeb, ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static const struct sdhci_pltfm_data sdhci_hlwd_pdata = { +diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c +index fdc612120362..52c42fcc284c 100644 +--- a/drivers/mmc/host/sdhci-pci.c ++++ b/drivers/mmc/host/sdhci-pci.c +@@ -1031,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) + return 0; + } + +-static int sdhci_pci_bus_width(struct sdhci_host *host, int width) ++static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width) + { + u8 ctrl; + +@@ -1052,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width) + } + + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +- +- return 0; + } + + static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) +@@ -1080,8 +1078,11 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host) + } + + static const struct sdhci_ops sdhci_pci_ops = { ++ .set_clock = sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, +- .platform_bus_width = sdhci_pci_bus_width, ++ .set_bus_width = sdhci_pci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + .hw_reset = sdhci_pci_hw_reset, + }; + +diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c +index bef250e95418..7e834fb78f42 100644 +--- a/drivers/mmc/host/sdhci-pltfm.c ++++ b/drivers/mmc/host/sdhci-pltfm.c +@@ -45,6 +45,10 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host) + EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); + + static const struct sdhci_ops sdhci_pltfm_ops = { ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + #ifdef CONFIG_OF +diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c +index d51e061ec576..3c0f3c0a1cc8 100644 +--- a/drivers/mmc/host/sdhci-pxav2.c ++++ b/drivers/mmc/host/sdhci-pxav2.c +@@ -51,11 +51,13 @@ + #define MMC_CARD 0x1000 + #define MMC_WIDTH 0x0100 + +-static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) ++static void pxav2_reset(struct sdhci_host *host, u8 mask) + { + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; + ++ sdhci_reset(host, mask); ++ + if (mask == SDHCI_RESET_ALL) { + u16 tmp = 0; + +@@ -88,7 +90,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) + } + } + +-static int pxav2_mmc_set_width(struct sdhci_host *host, int width) ++static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width) + { + u8 ctrl; + u16 tmp; +@@ -107,14 +109,14 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width) + } + writew(tmp, host->ioaddr + SD_CE_ATA_2); + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); +- +- return 0; + } + + static const struct sdhci_ops pxav2_sdhci_ops = { ++ .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, +- .platform_reset_exit = pxav2_set_private_registers, +- .platform_bus_width = pxav2_mmc_set_width, ++ .set_bus_width = pxav2_mmc_set_bus_width, ++ .reset = pxav2_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + #ifdef CONFIG_OF +diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c +index 2fd73b38c303..f4f128947561 100644 +--- a/drivers/mmc/host/sdhci-pxav3.c ++++ b/drivers/mmc/host/sdhci-pxav3.c +@@ -112,11 +112,13 @@ static int mv_conf_mbus_windows(struct platform_device *pdev, + return 0; + } + +-static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask) ++static void pxav3_reset(struct sdhci_host *host, u8 mask) + { + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; + ++ sdhci_reset(host, mask); ++ + if (mask == SDHCI_RESET_ALL) { + /* + * tune timing of read data/command when crc error happen +@@ -184,7 +186,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) + pxa->power_mode = power_mode; + } + +-static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) ++static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) + { + u16 ctrl_2; + +@@ -218,15 +220,16 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) + dev_dbg(mmc_dev(host->mmc), + "%s uhs = %d, ctrl_2 = %04X\n", + __func__, uhs, ctrl_2); +- +- return 0; + } + + static const struct sdhci_ops pxav3_sdhci_ops = { +- .platform_reset_exit = pxav3_set_private_registers, ++ .set_clock = sdhci_set_clock, + .set_uhs_signaling = pxav3_set_uhs_signaling, + .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = pxav3_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static struct sdhci_pltfm_data sdhci_pxav3_pdata = { +diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c +index d61eb5a70833..76d7c12d8ef9 100644 +--- a/drivers/mmc/host/sdhci-s3c.c ++++ b/drivers/mmc/host/sdhci-s3c.c +@@ -58,6 +58,8 @@ struct sdhci_s3c { + struct clk *clk_io; + struct clk *clk_bus[MAX_BUS_CLK]; + unsigned long clk_rates[MAX_BUS_CLK]; ++ ++ bool no_divider; + }; + + /** +@@ -70,6 +72,7 @@ struct sdhci_s3c { + */ + struct sdhci_s3c_drv_data { + unsigned int sdhci_quirks; ++ bool no_divider; + }; + + static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) +@@ -119,7 +122,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, + * If controller uses a non-standard clock division, find the best clock + * speed possible with selected clock source and skip the division. + */ +- if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { ++ if (ourhost->no_divider) { + rate = clk_round_rate(clksrc, wanted); + return wanted - rate; + } +@@ -161,9 +164,13 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) + int src; + u32 ctrl; + ++ host->mmc->actual_clock = 0; ++ + /* don't bother if the clock is going off. */ +- if (clock == 0) ++ if (clock == 0) { ++ sdhci_set_clock(host, clock); + return; ++ } + + for (src = 0; src < MAX_BUS_CLK; src++) { + delta = sdhci_s3c_consider_clock(ourhost, src, clock); +@@ -215,6 +222,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) + if (clock < 25 * 1000000) + ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); + writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); ++ ++ sdhci_set_clock(host, clock); + } + + /** +@@ -295,10 +304,11 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) + unsigned long timeout; + u16 clk = 0; + ++ host->mmc->actual_clock = 0; ++ + /* If the clock is going off, set to 0 at clock control register */ + if (clock == 0) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); +- host->clock = clock; + return; + } + +@@ -306,8 +316,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) + + clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + +- host->clock = clock; +- + clk = SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + +@@ -329,14 +337,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) + } + + /** +- * sdhci_s3c_platform_bus_width - support 8bit buswidth ++ * sdhci_s3c_set_bus_width - support 8bit buswidth + * @host: The SDHCI host being queried + * @width: MMC_BUS_WIDTH_ macro for the bus width being requested + * + * We have 8-bit width support but is not a v3 controller. + * So we add platform_bus_width() and support 8bit width. + */ +-static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width) ++static void sdhci_s3c_set_bus_width(struct sdhci_host *host, int width) + { + u8 ctrl; + +@@ -358,15 +366,15 @@ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width) + } + + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +- +- return 0; + } + + static struct sdhci_ops sdhci_s3c_ops = { + .get_max_clock = sdhci_s3c_get_max_clk, + .set_clock = sdhci_s3c_set_clock, + .get_min_clock = sdhci_s3c_get_min_clock, +- .platform_bus_width = sdhci_s3c_platform_bus_width, ++ .set_bus_width = sdhci_s3c_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static void sdhci_s3c_notify_change(struct platform_device *dev, int state) +@@ -606,8 +614,10 @@ static int sdhci_s3c_probe(struct platform_device *pdev) + /* Setup quirks for the controller */ + host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; + host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; +- if (drv_data) ++ if (drv_data) { + host->quirks |= drv_data->sdhci_quirks; ++ sc->no_divider = drv_data->no_divider; ++ } + + #ifndef CONFIG_MMC_SDHCI_S3C_DMA + +@@ -656,7 +666,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) + * If controller does not have internal clock divider, + * we can use overriding functions instead of default. + */ +- if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { ++ if (sc->no_divider) { + sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; + sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; + sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; +@@ -797,7 +807,7 @@ static const struct dev_pm_ops sdhci_s3c_pmops = { + + #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) + static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { +- .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, ++ .no_divider = true, + }; + #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) + #else +diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c +index 696122c1b468..17004531d089 100644 +--- a/drivers/mmc/host/sdhci-sirf.c ++++ b/drivers/mmc/host/sdhci-sirf.c +@@ -28,7 +28,11 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host) + } + + static struct sdhci_ops sdhci_sirf_ops = { ++ .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_sirf_get_max_clk, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static struct sdhci_pltfm_data sdhci_sirf_pdata = { +diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c +index 0316dec3f006..9d535c7336ef 100644 +--- a/drivers/mmc/host/sdhci-spear.c ++++ b/drivers/mmc/host/sdhci-spear.c +@@ -38,7 +38,10 @@ struct spear_sdhci { + + /* sdhci ops */ + static const struct sdhci_ops sdhci_pltfm_ops = { +- /* Nothing to do for now. */ ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + #ifdef CONFIG_OF +diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c +index a835898a68dd..985247649f46 100644 +--- a/drivers/mmc/host/sdhci-tegra.c ++++ b/drivers/mmc/host/sdhci-tegra.c +@@ -48,19 +48,6 @@ struct sdhci_tegra { + int power_gpio; + }; + +-static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) +-{ +- u32 val; +- +- if (unlikely(reg == SDHCI_PRESENT_STATE)) { +- /* Use wp_gpio here instead? */ +- val = readl(host->ioaddr + reg); +- return val | SDHCI_WRITE_PROTECT; +- } +- +- return readl(host->ioaddr + reg); +-} +- + static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +@@ -108,12 +95,14 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) + return mmc_gpio_get_ro(host->mmc); + } + +-static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) ++static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + ++ sdhci_reset(host, mask); ++ + if (!(mask & SDHCI_RESET_ALL)) + return; + +@@ -127,7 +116,7 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) + } + } + +-static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) ++static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) + { + u32 ctrl; + +@@ -144,16 +133,16 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) + ctrl &= ~SDHCI_CTRL_4BITBUS; + } + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +- return 0; + } + + static const struct sdhci_ops tegra_sdhci_ops = { + .get_ro = tegra_sdhci_get_ro, +- .read_l = tegra_sdhci_readl, + .read_w = tegra_sdhci_readw, + .write_l = tegra_sdhci_writel, +- .platform_bus_width = tegra_sdhci_buswidth, +- .platform_reset_exit = tegra_sdhci_reset_exit, ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = tegra_sdhci_set_bus_width, ++ .reset = tegra_sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + + static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 9a79fc4b60ca..48f4aef034fd 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -44,6 +44,8 @@ + + #define MAX_TUNING_LOOP 40 + ++#define ADMA_SIZE ((128 * 2 + 1) * 4) ++ + static unsigned int debug_quirks = 0; + static unsigned int debug_quirks2; + +@@ -131,43 +133,26 @@ static void sdhci_dumpregs(struct sdhci_host *host) + * * + \*****************************************************************************/ + +-static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set) +-{ +- u32 ier; +- +- ier = sdhci_readl(host, SDHCI_INT_ENABLE); +- ier &= ~clear; +- ier |= set; +- sdhci_writel(host, ier, SDHCI_INT_ENABLE); +- sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); +-} +- +-static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs) +-{ +- sdhci_clear_set_irqs(host, 0, irqs); +-} +- +-static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs) +-{ +- sdhci_clear_set_irqs(host, irqs, 0); +-} +- + static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) + { +- u32 present, irqs; ++ u32 present; + + if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || + (host->mmc->caps & MMC_CAP_NONREMOVABLE)) + return; + +- present = sdhci_readl(host, SDHCI_PRESENT_STATE) & +- SDHCI_CARD_PRESENT; +- irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; ++ if (enable) { ++ present = sdhci_readl(host, SDHCI_PRESENT_STATE) & ++ SDHCI_CARD_PRESENT; + +- if (enable) +- sdhci_unmask_irqs(host, irqs); +- else +- sdhci_mask_irqs(host, irqs); ++ host->ier |= present ? SDHCI_INT_CARD_REMOVE : ++ SDHCI_INT_CARD_INSERT; ++ } else { ++ host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); ++ } ++ ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + } + + static void sdhci_enable_card_detection(struct sdhci_host *host) +@@ -180,22 +165,9 @@ static void sdhci_disable_card_detection(struct sdhci_host *host) + sdhci_set_card_detection(host, false); + } + +-static void sdhci_reset(struct sdhci_host *host, u8 mask) ++void sdhci_reset(struct sdhci_host *host, u8 mask) + { + unsigned long timeout; +- u32 uninitialized_var(ier); +- +- if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { +- if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & +- SDHCI_CARD_PRESENT)) +- return; +- } +- +- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) +- ier = sdhci_readl(host, SDHCI_INT_ENABLE); +- +- if (host->ops->platform_reset_enter) +- host->ops->platform_reset_enter(host, mask); + + sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); + +@@ -220,16 +192,27 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) + timeout--; + mdelay(1); + } ++} ++EXPORT_SYMBOL_GPL(sdhci_reset); ++ ++static void sdhci_do_reset(struct sdhci_host *host, u8 mask) ++{ ++ if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { ++ if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & ++ SDHCI_CARD_PRESENT)) ++ return; ++ } + +- if (host->ops->platform_reset_exit) +- host->ops->platform_reset_exit(host, mask); ++ host->ops->reset(host, mask); + +- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) +- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); ++ if (mask & SDHCI_RESET_ALL) { ++ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { ++ if (host->ops->enable_dma) ++ host->ops->enable_dma(host); ++ } + +- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { +- if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL)) +- host->ops->enable_dma(host); ++ /* Resetting the controller clears many */ ++ host->preset_enabled = false; + } + } + +@@ -238,15 +221,18 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + static void sdhci_init(struct sdhci_host *host, int soft) + { + if (soft) +- sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +- sdhci_reset(host, SDHCI_RESET_ALL); ++ sdhci_do_reset(host, SDHCI_RESET_ALL); ++ ++ host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | ++ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | ++ SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | ++ SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | ++ SDHCI_INT_RESPONSE; + +- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, +- SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | +- SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | +- SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | +- SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + + if (soft) { + /* force clock reconfiguration */ +@@ -502,11 +488,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, + else + direction = DMA_TO_DEVICE; + +- /* +- * The ADMA descriptor table is mapped further down as we +- * need to fill it with data first. +- */ +- + host->align_addr = dma_map_single(mmc_dev(host->mmc), + host->align_buffer, 128 * 4, direction); + if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) +@@ -567,7 +548,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, + * If this triggers then we have a calculation bug + * somewhere. :/ + */ +- WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4); ++ WARN_ON((desc - host->adma_desc) > ADMA_SIZE); + } + + if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { +@@ -595,17 +576,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, + host->align_addr, 128 * 4, direction); + } + +- host->adma_addr = dma_map_single(mmc_dev(host->mmc), +- host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); +- if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr)) +- goto unmap_entries; +- BUG_ON(host->adma_addr & 0x3); +- + return 0; + +-unmap_entries: +- dma_unmap_sg(mmc_dev(host->mmc), data->sg, +- data->sg_len, direction); + unmap_align: + dma_unmap_single(mmc_dev(host->mmc), host->align_addr, + 128 * 4, direction); +@@ -623,19 +595,25 @@ static void sdhci_adma_table_post(struct sdhci_host *host, + u8 *align; + char *buffer; + unsigned long flags; ++ bool has_unaligned; + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + +- dma_unmap_single(mmc_dev(host->mmc), host->adma_addr, +- (128 * 2 + 1) * 4, DMA_TO_DEVICE); +- + dma_unmap_single(mmc_dev(host->mmc), host->align_addr, + 128 * 4, direction); + +- if (data->flags & MMC_DATA_READ) { ++ /* Do a quick scan of the SG list for any unaligned mappings */ ++ has_unaligned = false; ++ for_each_sg(data->sg, sg, host->sg_count, i) ++ if (sg_dma_address(sg) & 3) { ++ has_unaligned = true; ++ break; ++ } ++ ++ if (has_unaligned && data->flags & MMC_DATA_READ) { + dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, + data->sg_len, direction); + +@@ -721,9 +699,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) + u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR; + + if (host->flags & SDHCI_REQ_USE_DMA) +- sdhci_clear_set_irqs(host, pio_irqs, dma_irqs); ++ host->ier = (host->ier & ~pio_irqs) | dma_irqs; + else +- sdhci_clear_set_irqs(host, dma_irqs, pio_irqs); ++ host->ier = (host->ier & ~dma_irqs) | pio_irqs; ++ ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + } + + static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +@@ -976,8 +957,8 @@ static void sdhci_finish_data(struct sdhci_host *host) + * upon error conditions. + */ + if (data->error) { +- sdhci_reset(host, SDHCI_RESET_CMD); +- sdhci_reset(host, SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD); ++ sdhci_do_reset(host, SDHCI_RESET_DATA); + } + + sdhci_send_command(host, data->stop); +@@ -1107,24 +1088,23 @@ static void sdhci_finish_command(struct sdhci_host *host) + + static u16 sdhci_get_preset_value(struct sdhci_host *host) + { +- u16 ctrl, preset = 0; ++ u16 preset = 0; + +- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); +- +- switch (ctrl & SDHCI_CTRL_UHS_MASK) { +- case SDHCI_CTRL_UHS_SDR12: ++ switch (host->timing) { ++ case MMC_TIMING_UHS_SDR12: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12); + break; +- case SDHCI_CTRL_UHS_SDR25: ++ case MMC_TIMING_UHS_SDR25: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25); + break; +- case SDHCI_CTRL_UHS_SDR50: ++ case MMC_TIMING_UHS_SDR50: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50); + break; +- case SDHCI_CTRL_UHS_SDR104: ++ case MMC_TIMING_UHS_SDR104: ++ case MMC_TIMING_MMC_HS200: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104); + break; +- case SDHCI_CTRL_UHS_DDR50: ++ case MMC_TIMING_UHS_DDR50: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); + break; + default: +@@ -1136,32 +1116,22 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) + return preset; + } + +-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ++void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) + { + int div = 0; /* Initialized for compiler warning */ + int real_div = div, clk_mul = 1; + u16 clk = 0; + unsigned long timeout; + +- if (clock && clock == host->clock) +- return; +- + host->mmc->actual_clock = 0; + +- if (host->ops->set_clock) { +- host->ops->set_clock(host, clock); +- if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) +- return; +- } +- + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) +- goto out; ++ return; + + if (host->version >= SDHCI_SPEC_300) { +- if (sdhci_readw(host, SDHCI_HOST_CONTROL2) & +- SDHCI_CTRL_PRESET_VAL_ENABLE) { ++ if (host->preset_enabled) { + u16 pre_val; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); +@@ -1247,26 +1217,16 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +- +-out: +- host->clock = clock; +-} +- +-static inline void sdhci_update_clock(struct sdhci_host *host) +-{ +- unsigned int clock; +- +- clock = host->clock; +- host->clock = 0; +- sdhci_set_clock(host, clock); + } ++EXPORT_SYMBOL_GPL(sdhci_set_clock); + +-static int sdhci_set_power(struct sdhci_host *host, unsigned short power) ++static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd) + { + u8 pwr = 0; + +- if (power != (unsigned short)-1) { +- switch (1 << power) { ++ if (mode != MMC_POWER_OFF) { ++ switch (1 << vdd) { + case MMC_VDD_165_195: + pwr = SDHCI_POWER_180; + break; +@@ -1284,7 +1244,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) + } + + if (host->pwr == pwr) +- return -1; ++ return; + + host->pwr = pwr; + +@@ -1292,38 +1252,43 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) + sdhci_runtime_pm_bus_off(host); +- return 0; +- } +- +- /* +- * Spec says that we should clear the power reg before setting +- * a new value. Some controllers don't seem to like this though. +- */ +- if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) +- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); ++ vdd = 0; ++ } else { ++ /* ++ * Spec says that we should clear the power reg before setting ++ * a new value. Some controllers don't seem to like this though. ++ */ ++ if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) ++ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + +- /* +- * At least the Marvell CaFe chip gets confused if we set the voltage +- * and set turn on power at the same time, so set the voltage first. +- */ +- if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) +- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); ++ /* ++ * At least the Marvell CaFe chip gets confused if we set the ++ * voltage and set turn on power at the same time, so set the ++ * voltage first. ++ */ ++ if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) ++ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + +- pwr |= SDHCI_POWER_ON; ++ pwr |= SDHCI_POWER_ON; + +- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); ++ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + +- if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) +- sdhci_runtime_pm_bus_on(host); ++ if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) ++ sdhci_runtime_pm_bus_on(host); + +- /* +- * Some controllers need an extra 10ms delay of 10ms before they +- * can apply clock after applying power +- */ +- if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) +- mdelay(10); ++ /* ++ * Some controllers need an extra 10ms delay of 10ms before ++ * they can apply clock after applying power ++ */ ++ if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) ++ mdelay(10); ++ } + +- return power; ++ if (host->vmmc) { ++ spin_unlock_irq(&host->lock); ++ mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd); ++ spin_lock_irq(&host->lock); ++ } + } + + /*****************************************************************************\ +@@ -1427,10 +1392,52 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) + spin_unlock_irqrestore(&host->lock, flags); + } + ++void sdhci_set_bus_width(struct sdhci_host *host, int width) ++{ ++ u8 ctrl; ++ ++ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ++ if (width == MMC_BUS_WIDTH_8) { ++ ctrl &= ~SDHCI_CTRL_4BITBUS; ++ if (host->version >= SDHCI_SPEC_300) ++ ctrl |= SDHCI_CTRL_8BITBUS; ++ } else { ++ if (host->version >= SDHCI_SPEC_300) ++ ctrl &= ~SDHCI_CTRL_8BITBUS; ++ if (width == MMC_BUS_WIDTH_4) ++ ctrl |= SDHCI_CTRL_4BITBUS; ++ else ++ ctrl &= ~SDHCI_CTRL_4BITBUS; ++ } ++ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); ++} ++EXPORT_SYMBOL_GPL(sdhci_set_bus_width); ++ ++void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) ++{ ++ u16 ctrl_2; ++ ++ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ /* Select Bus Speed Mode for host */ ++ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; ++ if ((timing == MMC_TIMING_MMC_HS200) || ++ (timing == MMC_TIMING_UHS_SDR104)) ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR104; ++ else if (timing == MMC_TIMING_UHS_SDR12) ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR12; ++ else if (timing == MMC_TIMING_UHS_SDR25) ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR25; ++ else if (timing == MMC_TIMING_UHS_SDR50) ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR50; ++ else if (timing == MMC_TIMING_UHS_DDR50) ++ ctrl_2 |= SDHCI_CTRL_UHS_DDR50; ++ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); ++} ++EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); ++ + static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) + { + unsigned long flags; +- int vdd_bit = -1; + u8 ctrl; + + spin_lock_irqsave(&host->lock, flags); +@@ -1456,45 +1463,17 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) + !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) + sdhci_enable_preset_value(host, false); + +- sdhci_set_clock(host, ios->clock); +- +- if (ios->power_mode == MMC_POWER_OFF) +- vdd_bit = sdhci_set_power(host, -1); +- else +- vdd_bit = sdhci_set_power(host, ios->vdd); +- +- if (host->vmmc && vdd_bit != -1) { +- spin_unlock_irqrestore(&host->lock, flags); +- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); +- spin_lock_irqsave(&host->lock, flags); ++ if (!ios->clock || ios->clock != host->clock) { ++ host->ops->set_clock(host, ios->clock); ++ host->clock = ios->clock; + } + ++ sdhci_set_power(host, ios->power_mode, ios->vdd); ++ + if (host->ops->platform_send_init_74_clocks) + host->ops->platform_send_init_74_clocks(host, ios->power_mode); + +- /* +- * If your platform has 8-bit width support but is not a v3 controller, +- * or if it requires special setup code, you should implement that in +- * platform_bus_width(). +- */ +- if (host->ops->platform_bus_width) { +- host->ops->platform_bus_width(host, ios->bus_width); +- } else { +- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); +- if (ios->bus_width == MMC_BUS_WIDTH_8) { +- ctrl &= ~SDHCI_CTRL_4BITBUS; +- if (host->version >= SDHCI_SPEC_300) +- ctrl |= SDHCI_CTRL_8BITBUS; +- } else { +- if (host->version >= SDHCI_SPEC_300) +- ctrl &= ~SDHCI_CTRL_8BITBUS; +- if (ios->bus_width == MMC_BUS_WIDTH_4) +- ctrl |= SDHCI_CTRL_4BITBUS; +- else +- ctrl &= ~SDHCI_CTRL_4BITBUS; +- } +- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +- } ++ host->ops->set_bus_width(host, ios->bus_width); + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + +@@ -1516,13 +1495,13 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) + (ios->timing == MMC_TIMING_UHS_SDR25)) + ctrl |= SDHCI_CTRL_HISPD; + +- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); +- if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ++ if (!host->preset_enabled) { + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + /* + * We only need to set Driver Strength if the + * preset value enable is not set. + */ ++ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK; + if (ios->drv_type == MMC_SET_DRIVER_TYPE_A) + ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A; +@@ -1546,34 +1525,16 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + + /* Re-enable SD Clock */ +- sdhci_update_clock(host); ++ host->ops->set_clock(host, host->clock); + } + +- + /* Reset SD Clock Enable */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + +- if (host->ops->set_uhs_signaling) +- host->ops->set_uhs_signaling(host, ios->timing); +- else { +- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); +- /* Select Bus Speed Mode for host */ +- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; +- if ((ios->timing == MMC_TIMING_MMC_HS200) || +- (ios->timing == MMC_TIMING_UHS_SDR104)) +- ctrl_2 |= SDHCI_CTRL_UHS_SDR104; +- else if (ios->timing == MMC_TIMING_UHS_SDR12) +- ctrl_2 |= SDHCI_CTRL_UHS_SDR12; +- else if (ios->timing == MMC_TIMING_UHS_SDR25) +- ctrl_2 |= SDHCI_CTRL_UHS_SDR25; +- else if (ios->timing == MMC_TIMING_UHS_SDR50) +- ctrl_2 |= SDHCI_CTRL_UHS_SDR50; +- else if (ios->timing == MMC_TIMING_UHS_DDR50) +- ctrl_2 |= SDHCI_CTRL_UHS_DDR50; +- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +- } ++ host->ops->set_uhs_signaling(host, ios->timing); ++ host->timing = ios->timing; + + if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) && + ((ios->timing == MMC_TIMING_UHS_SDR12) || +@@ -1590,7 +1551,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) + } + + /* Re-enable SD Clock */ +- sdhci_update_clock(host); ++ host->ops->set_clock(host, host->clock); + } else + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + +@@ -1600,7 +1561,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) + * it on each ios seems to solve the problem. + */ + if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) +- sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +@@ -1709,24 +1670,16 @@ static int sdhci_get_ro(struct mmc_host *mmc) + + static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) + { +- if (host->flags & SDHCI_DEVICE_DEAD) +- goto out; +- +- if (enable) +- host->flags |= SDHCI_SDIO_IRQ_ENABLED; +- else +- host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; +- +- /* SDIO IRQ will be enabled as appropriate in runtime resume */ +- if (host->runtime_suspended) +- goto out; ++ if (!(host->flags & SDHCI_DEVICE_DEAD)) { ++ if (enable) ++ host->ier |= SDHCI_INT_CARD_INT; ++ else ++ host->ier &= ~SDHCI_INT_CARD_INT; + +- if (enable) +- sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); +- else +- sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); +-out: +- mmiowb(); ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ mmiowb(); ++ } + } + + static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +@@ -1734,9 +1687,18 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + ++ sdhci_runtime_pm_get(host); ++ + spin_lock_irqsave(&host->lock, flags); ++ if (enable) ++ host->flags |= SDHCI_SDIO_IRQ_ENABLED; ++ else ++ host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; ++ + sdhci_enable_sdio_irq_nolock(host, enable); + spin_unlock_irqrestore(&host->lock, flags); ++ ++ sdhci_runtime_pm_put(host); + } + + static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, +@@ -1798,9 +1760,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, + ctrl |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + +- /* Wait for 5ms */ +- usleep_range(5000, 5500); +- + /* 1.8V regulator output should be stable within 5 ms */ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (ctrl & SDHCI_CTRL_VDD_180) +@@ -1855,22 +1814,16 @@ static int sdhci_card_busy(struct mmc_host *mmc) + + static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + { +- struct sdhci_host *host; ++ struct sdhci_host *host = mmc_priv(mmc); + u16 ctrl; +- u32 ier; + int tuning_loop_counter = MAX_TUNING_LOOP; + unsigned long timeout; + int err = 0; +- bool requires_tuning_nonuhs = false; + unsigned long flags; + +- host = mmc_priv(mmc); +- + sdhci_runtime_pm_get(host); + spin_lock_irqsave(&host->lock, flags); + +- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); +- + /* + * The Host Controller needs tuning only in case of SDR104 mode + * and for SDR50 mode when Use Tuning for SDR50 is set in the +@@ -1878,15 +1831,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + * If the Host Controller supports the HS200 mode then the + * tuning function has to be executed. + */ +- if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && +- (host->flags & SDHCI_SDR50_NEEDS_TUNING || +- host->flags & SDHCI_SDR104_NEEDS_TUNING)) +- requires_tuning_nonuhs = true; +- +- if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || +- requires_tuning_nonuhs) +- ctrl |= SDHCI_CTRL_EXEC_TUNING; +- else { ++ switch (host->timing) { ++ case MMC_TIMING_MMC_HS200: ++ case MMC_TIMING_UHS_SDR104: ++ break; ++ ++ case MMC_TIMING_UHS_SDR50: ++ if (host->flags & SDHCI_SDR50_NEEDS_TUNING || ++ host->flags & SDHCI_SDR104_NEEDS_TUNING) ++ break; ++ /* FALLTHROUGH */ ++ ++ default: + spin_unlock_irqrestore(&host->lock, flags); + sdhci_runtime_pm_put(host); + return 0; +@@ -1899,6 +1855,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + return err; + } + ++ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ctrl |= SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + + /* +@@ -1911,8 +1869,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + * to make sure we don't hit a controller bug, we _only_ + * enable Buffer Read Ready interrupt here. + */ +- ier = sdhci_readl(host, SDHCI_INT_ENABLE); +- sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL); ++ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); ++ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); + + /* + * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number +@@ -2044,7 +2002,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + if (err && (host->flags & SDHCI_USING_RETUNING_TIMER)) + err = 0; + +- sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + spin_unlock_irqrestore(&host->lock, flags); + sdhci_runtime_pm_put(host); + +@@ -2054,26 +2013,30 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + + static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) + { +- u16 ctrl; +- + /* Host Controller v3.00 defines preset value registers */ + if (host->version < SDHCI_SPEC_300) + return; + +- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); +- + /* + * We only enable or disable Preset Value if they are not already + * enabled or disabled respectively. Otherwise, we bail out. + */ +- if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { +- ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; +- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); +- host->flags |= SDHCI_PV_ENABLED; +- } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { +- ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; ++ if (host->preset_enabled != enable) { ++ u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ++ if (enable) ++ ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; ++ else ++ ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; ++ + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); +- host->flags &= ~SDHCI_PV_ENABLED; ++ ++ if (enable) ++ host->flags |= SDHCI_PV_ENABLED; ++ else ++ host->flags &= ~SDHCI_PV_ENABLED; ++ ++ host->preset_enabled = enable; + } + } + +@@ -2095,8 +2058,8 @@ static void sdhci_card_event(struct mmc_host *mmc) + pr_err("%s: Resetting controller.\n", + mmc_hostname(host->mmc)); + +- sdhci_reset(host, SDHCI_RESET_CMD); +- sdhci_reset(host, SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD); ++ sdhci_do_reset(host, SDHCI_RESET_DATA); + + host->mrq->cmd->error = -ENOMEDIUM; + tasklet_schedule(&host->finish_tasklet); +@@ -2124,15 +2087,6 @@ static const struct mmc_host_ops sdhci_ops = { + * * + \*****************************************************************************/ + +-static void sdhci_tasklet_card(unsigned long param) +-{ +- struct sdhci_host *host = (struct sdhci_host*)param; +- +- sdhci_card_event(host->mmc); +- +- mmc_detect_change(host->mmc, msecs_to_jiffies(200)); +-} +- + static void sdhci_tasklet_finish(unsigned long param) + { + struct sdhci_host *host; +@@ -2169,12 +2123,12 @@ static void sdhci_tasklet_finish(unsigned long param) + /* Some controllers need this kick or reset won't work here */ + if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) + /* This is to force an update */ +- sdhci_update_clock(host); ++ host->ops->set_clock(host, host->clock); + + /* Spec says we should do both at the same time, but Ricoh + controllers do not like that. */ +- sdhci_reset(host, SDHCI_RESET_CMD); +- sdhci_reset(host, SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD); ++ sdhci_do_reset(host, SDHCI_RESET_DATA); + } + + host->mrq = NULL; +@@ -2424,101 +2378,94 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) + + static irqreturn_t sdhci_irq(int irq, void *dev_id) + { +- irqreturn_t result; ++ irqreturn_t result = IRQ_NONE; + struct sdhci_host *host = dev_id; +- u32 intmask, unexpected = 0; +- int cardint = 0, max_loops = 16; ++ u32 intmask, mask, unexpected = 0; ++ int max_loops = 16; + + spin_lock(&host->lock); + +- if (host->runtime_suspended) { ++ if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) { + spin_unlock(&host->lock); + return IRQ_NONE; + } + + intmask = sdhci_readl(host, SDHCI_INT_STATUS); +- + if (!intmask || intmask == 0xffffffff) { + result = IRQ_NONE; + goto out; + } + +-again: +- DBG("*** %s got interrupt: 0x%08x\n", +- mmc_hostname(host->mmc), intmask); +- +- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { +- u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & +- SDHCI_CARD_PRESENT; +- +- /* +- * There is a observation on i.mx esdhc. INSERT bit will be +- * immediately set again when it gets cleared, if a card is +- * inserted. We have to mask the irq to prevent interrupt +- * storm which will freeze the system. And the REMOVE gets +- * the same situation. +- * +- * More testing are needed here to ensure it works for other +- * platforms though. +- */ +- sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT : +- SDHCI_INT_CARD_REMOVE); +- sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE : +- SDHCI_INT_CARD_INSERT); ++ do { ++ /* Clear selected interrupts. */ ++ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | ++ SDHCI_INT_BUS_POWER); ++ sdhci_writel(host, mask, SDHCI_INT_STATUS); + +- sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | +- SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); +- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); +- tasklet_schedule(&host->card_tasklet); +- } ++ DBG("*** %s got interrupt: 0x%08x\n", ++ mmc_hostname(host->mmc), intmask); + +- if (intmask & SDHCI_INT_CMD_MASK) { +- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, +- SDHCI_INT_STATUS); +- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); +- } ++ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { ++ u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & ++ SDHCI_CARD_PRESENT; + +- if (intmask & SDHCI_INT_DATA_MASK) { +- sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK, +- SDHCI_INT_STATUS); +- sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); +- } +- +- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); ++ /* ++ * There is a observation on i.mx esdhc. INSERT ++ * bit will be immediately set again when it gets ++ * cleared, if a card is inserted. We have to mask ++ * the irq to prevent interrupt storm which will ++ * freeze the system. And the REMOVE gets the ++ * same situation. ++ * ++ * More testing are needed here to ensure it works ++ * for other platforms though. ++ */ ++ host->ier &= ~(SDHCI_INT_CARD_INSERT | ++ SDHCI_INT_CARD_REMOVE); ++ host->ier |= present ? SDHCI_INT_CARD_REMOVE : ++ SDHCI_INT_CARD_INSERT; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ ++ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | ++ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); ++ ++ host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT | ++ SDHCI_INT_CARD_REMOVE); ++ result = IRQ_WAKE_THREAD; ++ } + +- intmask &= ~SDHCI_INT_ERROR; ++ if (intmask & SDHCI_INT_CMD_MASK) ++ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); + +- if (intmask & SDHCI_INT_BUS_POWER) { +- pr_err("%s: Card is consuming too much power!\n", +- mmc_hostname(host->mmc)); +- sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); +- } ++ if (intmask & SDHCI_INT_DATA_MASK) ++ sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); + +- intmask &= ~SDHCI_INT_BUS_POWER; ++ if (intmask & SDHCI_INT_BUS_POWER) ++ pr_err("%s: Card is consuming too much power!\n", ++ mmc_hostname(host->mmc)); + +- if (intmask & SDHCI_INT_CARD_INT) +- cardint = 1; ++ if (intmask & SDHCI_INT_CARD_INT) { ++ sdhci_enable_sdio_irq_nolock(host, false); ++ host->thread_isr |= SDHCI_INT_CARD_INT; ++ result = IRQ_WAKE_THREAD; ++ } + +- intmask &= ~SDHCI_INT_CARD_INT; ++ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | ++ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | ++ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | ++ SDHCI_INT_CARD_INT); + +- if (intmask) { +- unexpected |= intmask; +- sdhci_writel(host, intmask, SDHCI_INT_STATUS); +- } +- +- result = IRQ_HANDLED; ++ if (intmask) { ++ unexpected |= intmask; ++ sdhci_writel(host, intmask, SDHCI_INT_STATUS); ++ } + +- intmask = sdhci_readl(host, SDHCI_INT_STATUS); ++ if (result == IRQ_NONE) ++ result = IRQ_HANDLED; + +- /* +- * If we know we'll call the driver to signal SDIO IRQ, disregard +- * further indications of Card Interrupt in the status to avoid a +- * needless loop. +- */ +- if (cardint) +- intmask &= ~SDHCI_INT_CARD_INT; +- if (intmask && --max_loops) +- goto again; ++ intmask = sdhci_readl(host, SDHCI_INT_STATUS); ++ } while (intmask && --max_loops); + out: + spin_unlock(&host->lock); + +@@ -2527,15 +2474,38 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) + mmc_hostname(host->mmc), unexpected); + sdhci_dumpregs(host); + } +- /* +- * We have to delay this as it calls back into the driver. +- */ +- if (cardint) +- mmc_signal_sdio_irq(host->mmc); + + return result; + } + ++static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) ++{ ++ struct sdhci_host *host = dev_id; ++ unsigned long flags; ++ u32 isr; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ isr = host->thread_isr; ++ host->thread_isr = 0; ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { ++ sdhci_card_event(host->mmc); ++ mmc_detect_change(host->mmc, msecs_to_jiffies(200)); ++ } ++ ++ if (isr & SDHCI_INT_CARD_INT) { ++ sdio_run_irqs(host->mmc); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->flags & SDHCI_SDIO_IRQ_ENABLED) ++ sdhci_enable_sdio_irq_nolock(host, true); ++ spin_unlock_irqrestore(&host->lock, flags); ++ } ++ ++ return isr ? IRQ_HANDLED : IRQ_NONE; ++} ++ + /*****************************************************************************\ + * * + * Suspend/resume * +@@ -2572,9 +2542,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups); + + int sdhci_suspend_host(struct sdhci_host *host) + { +- if (host->ops->platform_suspend) +- host->ops->platform_suspend(host); +- + sdhci_disable_card_detection(host); + + /* Disable tuning since we are suspending */ +@@ -2584,7 +2551,9 @@ int sdhci_suspend_host(struct sdhci_host *host) + } + + if (!device_may_wakeup(mmc_dev(host->mmc))) { +- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); ++ host->ier = 0; ++ sdhci_writel(host, 0, SDHCI_INT_ENABLE); ++ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); + free_irq(host->irq, host); + } else { + sdhci_enable_irq_wakeups(host); +@@ -2605,8 +2574,9 @@ int sdhci_resume_host(struct sdhci_host *host) + } + + if (!device_may_wakeup(mmc_dev(host->mmc))) { +- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, +- mmc_hostname(host->mmc), host); ++ ret = request_threaded_irq(host->irq, sdhci_irq, ++ sdhci_thread_irq, IRQF_SHARED, ++ mmc_hostname(host->mmc), host); + if (ret) + return ret; + } else { +@@ -2628,9 +2598,6 @@ int sdhci_resume_host(struct sdhci_host *host) + + sdhci_enable_card_detection(host); + +- if (host->ops->platform_resume) +- host->ops->platform_resume(host); +- + /* Set the re-tuning expiration flag */ + if (host->flags & SDHCI_USING_RETUNING_TIMER) + host->flags |= SDHCI_NEEDS_RETUNING; +@@ -2682,10 +2649,12 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) + } + + spin_lock_irqsave(&host->lock, flags); +- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); ++ host->ier &= SDHCI_INT_CARD_INT; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + spin_unlock_irqrestore(&host->lock, flags); + +- synchronize_irq(host->irq); ++ synchronize_hardirq(host->irq); + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = true; +@@ -2729,7 +2698,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) + host->runtime_suspended = false; + + /* Enable SDIO IRQ */ +- if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) ++ if (host->flags & SDHCI_SDIO_IRQ_ENABLED) + sdhci_enable_sdio_irq_nolock(host, true); + + /* Enable Card Detection */ +@@ -2788,7 +2757,7 @@ int sdhci_add_host(struct sdhci_host *host) + if (debug_quirks2) + host->quirks2 = debug_quirks2; + +- sdhci_reset(host, SDHCI_RESET_ALL); ++ sdhci_do_reset(host, SDHCI_RESET_ALL); + + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + host->version = (host->version & SDHCI_SPEC_VER_MASK) +@@ -2848,15 +2817,29 @@ int sdhci_add_host(struct sdhci_host *host) + * (128) and potentially one alignment transfer for + * each of those entries. + */ +- host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL); ++ host->adma_desc = dma_alloc_coherent(mmc_dev(host->mmc), ++ ADMA_SIZE, &host->adma_addr, ++ GFP_KERNEL); + host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); + if (!host->adma_desc || !host->align_buffer) { +- kfree(host->adma_desc); ++ dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, ++ host->adma_desc, host->adma_addr); + kfree(host->align_buffer); + pr_warning("%s: Unable to allocate ADMA " + "buffers. Falling back to standard DMA.\n", + mmc_hostname(mmc)); + host->flags &= ~SDHCI_USE_ADMA; ++ host->adma_desc = NULL; ++ host->align_buffer = NULL; ++ } else if (host->adma_addr & 3) { ++ pr_warning("%s: unable to allocate aligned ADMA descriptor\n", ++ mmc_hostname(mmc)); ++ host->flags &= ~SDHCI_USE_ADMA; ++ dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, ++ host->adma_desc, host->adma_addr); ++ kfree(host->align_buffer); ++ host->adma_desc = NULL; ++ host->align_buffer = NULL; + } + } + +@@ -2941,6 +2924,7 @@ int sdhci_add_host(struct sdhci_host *host) + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; + + mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; ++ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + + if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) + host->flags |= SDHCI_AUTO_CMD12; +@@ -3212,8 +3196,6 @@ int sdhci_add_host(struct sdhci_host *host) + /* + * Init tasklets. + */ +- tasklet_init(&host->card_tasklet, +- sdhci_tasklet_card, (unsigned long)host); + tasklet_init(&host->finish_tasklet, + sdhci_tasklet_finish, (unsigned long)host); + +@@ -3230,8 +3212,8 @@ int sdhci_add_host(struct sdhci_host *host) + + sdhci_init(host, 0); + +- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, +- mmc_hostname(mmc), host); ++ ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq, ++ IRQF_SHARED, mmc_hostname(mmc), host); + if (ret) { + pr_err("%s: Failed to request IRQ %d: %d\n", + mmc_hostname(mmc), host->irq, ret); +@@ -3273,12 +3255,12 @@ int sdhci_add_host(struct sdhci_host *host) + + #ifdef SDHCI_USE_LEDS_CLASS + reset: +- sdhci_reset(host, SDHCI_RESET_ALL); +- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); ++ sdhci_do_reset(host, SDHCI_RESET_ALL); ++ sdhci_writel(host, 0, SDHCI_INT_ENABLE); ++ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); + free_irq(host->irq, host); + #endif + untasklet: +- tasklet_kill(&host->card_tasklet); + tasklet_kill(&host->finish_tasklet); + + return ret; +@@ -3315,14 +3297,14 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) + #endif + + if (!dead) +- sdhci_reset(host, SDHCI_RESET_ALL); ++ sdhci_do_reset(host, SDHCI_RESET_ALL); + +- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); ++ sdhci_writel(host, 0, SDHCI_INT_ENABLE); ++ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); + free_irq(host->irq, host); + + del_timer_sync(&host->timer); + +- tasklet_kill(&host->card_tasklet); + tasklet_kill(&host->finish_tasklet); + + if (host->vmmc) { +@@ -3335,7 +3317,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) + regulator_put(host->vqmmc); + } + +- kfree(host->adma_desc); ++ if (host->adma_desc) ++ dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, ++ host->adma_desc, host->adma_addr); + kfree(host->align_buffer); + + host->adma_desc = NULL; +diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h +index 0a3ed01887db..4a5cd5e3fa3e 100644 +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -281,18 +281,14 @@ struct sdhci_ops { + unsigned int (*get_max_clock)(struct sdhci_host *host); + unsigned int (*get_min_clock)(struct sdhci_host *host); + unsigned int (*get_timeout_clock)(struct sdhci_host *host); +- int (*platform_bus_width)(struct sdhci_host *host, +- int width); ++ void (*set_bus_width)(struct sdhci_host *host, int width); + void (*platform_send_init_74_clocks)(struct sdhci_host *host, + u8 power_mode); + unsigned int (*get_ro)(struct sdhci_host *host); +- void (*platform_reset_enter)(struct sdhci_host *host, u8 mask); +- void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); ++ void (*reset)(struct sdhci_host *host, u8 mask); + int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); +- int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); ++ void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); + void (*hw_reset)(struct sdhci_host *host); +- void (*platform_suspend)(struct sdhci_host *host); +- void (*platform_resume)(struct sdhci_host *host); + void (*adma_workaround)(struct sdhci_host *host, u32 intmask); + void (*platform_init)(struct sdhci_host *host); + void (*card_event)(struct sdhci_host *host); +@@ -397,6 +393,16 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead); + extern void sdhci_send_command(struct sdhci_host *host, + struct mmc_command *cmd); + ++static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host) ++{ ++ return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED); ++} ++ ++void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); ++void sdhci_set_bus_width(struct sdhci_host *host, int width); ++void sdhci_reset(struct sdhci_host *host, u8 mask); ++void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); ++ + #ifdef CONFIG_PM + extern int sdhci_suspend_host(struct sdhci_host *host); + extern int sdhci_resume_host(struct sdhci_host *host); +diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c +index 7c397bb81e01..6da2fbbb9bd5 100644 +--- a/drivers/regulator/anatop-regulator.c ++++ b/drivers/regulator/anatop-regulator.c +@@ -267,6 +267,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) + config.driver_data = sreg; + config.of_node = pdev->dev.of_node; + config.regmap = sreg->anatop; ++ config.ena_gpio = -EINVAL; + + /* Only core regulators have the ramp up delay configuration. */ + if (sreg->control_reg && sreg->delay_bit_width) { +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 9a09f3cdbabb..19c4077374b6 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -3459,7 +3459,7 @@ regulator_register(const struct regulator_desc *regulator_desc, + + dev_set_drvdata(&rdev->dev, rdev); + +- if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) { ++ if (gpio_is_valid(config->ena_gpio)) { + ret = regulator_ena_gpio_request(rdev, config); + if (ret != 0) { + rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", +diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c +index 2436db9e2ca3..acc4ea593c95 100644 +--- a/drivers/regulator/dummy.c ++++ b/drivers/regulator/dummy.c +@@ -48,6 +48,7 @@ static int dummy_regulator_probe(struct platform_device *pdev) + + config.dev = &pdev->dev; + config.init_data = &dummy_initdata; ++ config.ena_gpio = -EINVAL; + + dummy_regulator_rdev = regulator_register(&dummy_desc, &config); + if (IS_ERR(dummy_regulator_rdev)) { +diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c +index c61f7e97e4f8..aabf10dc8a50 100644 +--- a/drivers/regulator/fixed.c ++++ b/drivers/regulator/fixed.c +@@ -161,9 +161,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) + drvdata->desc.n_voltages = 1; + + drvdata->desc.fixed_uV = config->microvolts; +- +- if (config->gpio >= 0) +- cfg.ena_gpio = config->gpio; ++ cfg.ena_gpio = config->gpio; + cfg.ena_gpio_invert = !config->enable_high; + if (config->enabled_at_boot) { + if (config->enable_high) +diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig +index c6e8ba7b3e4e..52516a7cf26f 100644 +--- a/drivers/staging/imx-drm/Kconfig ++++ b/drivers/staging/imx-drm/Kconfig +@@ -35,6 +35,7 @@ config DRM_IMX_TVE + config DRM_IMX_LDB + tristate "Support for LVDS displays" + depends on DRM_IMX && MFD_SYSCON ++ select DRM_PANEL + help + Choose this to enable the internal LVDS Display Bridge (LDB) + found on i.MX53 and i.MX6 processors. +@@ -60,3 +61,20 @@ config DRM_IMX_HDMI + depends on DRM_IMX + help + Choose this if you want to use HDMI on i.MX6. ++ ++config DRM_DW_HDMI_AUDIO ++ tristate "Synopsis Designware Audio interface" ++ depends on DRM_IMX_HDMI != n ++ help ++ Support the Audio interface which is part of the Synopsis ++ Designware HDMI block. This is used in conjunction with ++ the i.MX HDMI driver. ++ ++config DRM_DW_HDMI_CEC ++ tristate "Synopsis Designware CEC interface" ++ depends on DRM_IMX_HDMI != n ++ select HDMI_CEC_CORE ++ help ++ Support the CEC interface which is part of the Synposis ++ Designware HDMI block. This is used in conjunction with ++ the i.MX HDMI driver. +diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile +index 129e3a3f59f1..5eabd5e4e456 100644 +--- a/drivers/staging/imx-drm/Makefile ++++ b/drivers/staging/imx-drm/Makefile +@@ -3,6 +3,7 @@ imxdrm-objs := imx-drm-core.o + + obj-$(CONFIG_DRM_IMX) += imxdrm.o + ++obj-$(CONFIG_DRM_IMX) += drm-ddc-connector.o + obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o + obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o + obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o +@@ -11,3 +12,5 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ + imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o + obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o + obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o ++obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o ++obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o +diff --git a/drivers/staging/imx-drm/drm-ddc-connector.c b/drivers/staging/imx-drm/drm-ddc-connector.c +new file mode 100644 +index 000000000000..a36ed4b06ebe +--- /dev/null ++++ b/drivers/staging/imx-drm/drm-ddc-connector.c +@@ -0,0 +1,92 @@ ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <drm/drmP.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_edid.h> ++ ++#include "drm-ddc-connector.h" ++ ++static enum drm_connector_status ++drm_ddc_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); ++ ++ return ddc_conn->detect ? ddc_conn->detect(connector, force) : ++ connector_status_connected; ++} ++ ++int drm_ddc_connector_get_modes(struct drm_connector *connector) ++{ ++ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); ++ struct edid *edid; ++ int ret = 0; ++ ++ if (!ddc_conn->ddc) ++ return 0; ++ ++ edid = drm_get_edid(connector, ddc_conn->ddc); ++ if (edid) { ++ drm_mode_connector_update_edid_property(connector, edid); ++ ret = drm_add_edid_modes(connector, edid); ++ /* Store the ELD */ ++ drm_edid_to_eld(connector, edid); ++ kfree(edid); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(drm_ddc_connector_get_modes); ++ ++static void drm_ddc_connector_destroy(struct drm_connector *connector) ++{ ++ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); ++ ++ drm_sysfs_connector_remove(connector); ++ drm_connector_cleanup(connector); ++ if (ddc_conn->ddc) ++ i2c_put_adapter(ddc_conn->ddc); ++} ++ ++static const struct drm_connector_funcs drm_ddc_connector_funcs = { ++ .dpms = drm_helper_connector_dpms, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .detect = drm_ddc_connector_detect, ++ .destroy = drm_ddc_connector_destroy, ++}; ++ ++int drm_ddc_connector_add(struct drm_device *drm, ++ struct drm_ddc_connector *ddc_conn, int connector_type) ++{ ++ drm_connector_init(drm, &ddc_conn->connector, &drm_ddc_connector_funcs, ++ connector_type); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(drm_ddc_connector_add); ++ ++struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm, ++ struct device_node *np, void *private) ++{ ++ struct drm_ddc_connector *ddc_conn; ++ struct device_node *ddc_node; ++ ++ ddc_conn = devm_kzalloc(drm->dev, sizeof(*ddc_conn), GFP_KERNEL); ++ if (!ddc_conn) ++ return ERR_PTR(-ENOMEM); ++ ++ ddc_conn->private = private; ++ ++ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); ++ if (ddc_node) { ++ ddc_conn->ddc = of_find_i2c_adapter_by_node(ddc_node); ++ of_node_put(ddc_node); ++ if (!ddc_conn->ddc) ++ return ERR_PTR(-EPROBE_DEFER); ++ } ++ ++ return ddc_conn; ++} ++EXPORT_SYMBOL_GPL(drm_ddc_connector_create); ++ ++MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Generic DRM DDC connector module"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/imx-drm/drm-ddc-connector.h b/drivers/staging/imx-drm/drm-ddc-connector.h +new file mode 100644 +index 000000000000..38068e5105d3 +--- /dev/null ++++ b/drivers/staging/imx-drm/drm-ddc-connector.h +@@ -0,0 +1,26 @@ ++#ifndef DRM_DDC_CONNECTOR_H ++#define DRM_DDC_CONNECTOR_H ++ ++struct drm_ddc_connector { ++ struct i2c_adapter *ddc; ++ struct drm_connector connector; ++ enum drm_connector_status (*detect)(struct drm_connector *, bool); ++ void *private; ++}; ++ ++#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector) ++ ++int drm_ddc_connector_get_modes(struct drm_connector *connector); ++int drm_ddc_connector_add(struct drm_device *drm, ++ struct drm_ddc_connector *ddc_conn, int connector_type); ++struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm, ++ struct device_node *np, void *private); ++ ++static inline void *drm_ddc_private(struct drm_connector *connector) ++{ ++ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); ++ ++ return ddc_conn->private; ++} ++ ++#endif +diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c +new file mode 100644 +index 000000000000..e7495265ed84 +--- /dev/null ++++ b/drivers/staging/imx-drm/dw-hdmi-audio.c +@@ -0,0 +1,652 @@ ++/* ++ * DesignWare HDMI audio driver ++ * ++ * 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. ++ * ++ * Written and tested against the (alleged) DW HDMI Tx found in iMX6S. ++ */ ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++ ++#include <sound/asoundef.h> ++#include <sound/core.h> ++#include <sound/initval.h> ++#include <sound/pcm.h> ++ ++#include "dw-hdmi-audio.h" ++ ++#define DRIVER_NAME "dw-hdmi-audio" ++ ++/* Provide some bits rather than bit offsets */ ++enum { ++ HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7), ++ HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3), ++ HDMI_AHB_DMA_START_START = BIT(0), ++ HDMI_AHB_DMA_STOP_STOP = BIT(0), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL = ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR | ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST | ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY | ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE | ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL | ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY, ++ HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5), ++ HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4), ++ HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3), ++ HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2), ++ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), ++ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), ++ HDMI_IH_AHBDMAAUD_STAT0_ALL = ++ HDMI_IH_AHBDMAAUD_STAT0_ERROR | ++ HDMI_IH_AHBDMAAUD_STAT0_LOST | ++ HDMI_IH_AHBDMAAUD_STAT0_RETRY | ++ HDMI_IH_AHBDMAAUD_STAT0_DONE | ++ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL | ++ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY, ++ HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1, ++ HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1, ++ HDMI_AHB_DMA_CONF0_INCR4 = 0, ++ HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0), ++ HDMI_AHB_DMA_MASK_DONE = BIT(7), ++ HDMI_REVISION_ID = 0x0001, ++ HDMI_IH_AHBDMAAUD_STAT0 = 0x0109, ++ HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189, ++ HDMI_AUD_N1 = 0x3200, ++ HDMI_AUD_CTS1 = 0x3203, ++ HDMI_AHB_DMA_CONF0 = 0x3600, ++ HDMI_AHB_DMA_START = 0x3601, ++ HDMI_AHB_DMA_STOP = 0x3602, ++ HDMI_AHB_DMA_THRSLD = 0x3603, ++ HDMI_AHB_DMA_STRADDR0 = 0x3604, ++ HDMI_AHB_DMA_STPADDR0 = 0x3608, ++ HDMI_AHB_DMA_STAT = 0x3612, ++ HDMI_AHB_DMA_STAT_FULL = BIT(1), ++ HDMI_AHB_DMA_MASK = 0x3614, ++ HDMI_AHB_DMA_POL = 0x3615, ++ HDMI_AHB_DMA_CONF1 = 0x3616, ++ HDMI_AHB_DMA_BUFFPOL = 0x361a, ++}; ++ ++struct snd_dw_hdmi { ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ struct dw_hdmi_audio_data data; ++ struct snd_pcm_substream *substream; ++ void (*reformat)(struct snd_dw_hdmi *, size_t, size_t); ++ void *buf_src; ++ void *buf_dst; ++ dma_addr_t buf_addr; ++ unsigned buf_offset; ++ unsigned buf_period; ++ unsigned buf_size; ++ unsigned channels; ++ uint8_t revision; ++ uint8_t iec_offset; ++ uint8_t cs[192][8]; ++}; ++ ++static void dw_hdmi_writel(unsigned long val, void __iomem *ptr) ++{ ++ writeb_relaxed(val, ptr); ++ writeb_relaxed(val >> 8, ptr + 1); ++ writeb_relaxed(val >> 16, ptr + 2); ++ writeb_relaxed(val >> 24, ptr + 3); ++} ++ ++/* ++ * Convert to hardware format: The userspace buffer contains IEC958 samples, ++ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We ++ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio ++ * samples in 23..0. ++ * ++ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd ++ * ++ * Ideally, we could do with having the data properly formatted in userspace. ++ */ ++static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw, ++ size_t offset, size_t bytes) ++{ ++ uint32_t *src = dw->buf_src + offset; ++ uint32_t *dst = dw->buf_dst + offset; ++ uint32_t *end = dw->buf_src + offset + bytes; ++ ++ do { ++ uint32_t b, sample = *src++; ++ ++ b = (sample & 8) << (28 - 3); ++ ++ sample >>= 4; ++ ++ *dst++ = sample | b; ++ } while (src < end); ++} ++ ++static uint32_t parity(uint32_t sample) ++{ ++ sample ^= sample >> 16; ++ sample ^= sample >> 8; ++ sample ^= sample >> 4; ++ sample ^= sample >> 2; ++ sample ^= sample >> 1; ++ return (sample & 1) << 27; ++} ++ ++static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw, ++ size_t offset, size_t bytes) ++{ ++ uint32_t *src = dw->buf_src + offset; ++ uint32_t *dst = dw->buf_dst + offset; ++ uint32_t *end = dw->buf_src + offset + bytes; ++ ++ do { ++ unsigned i; ++ uint8_t *cs; ++ ++ cs = dw->cs[dw->iec_offset++]; ++ if (dw->iec_offset >= 192) ++ dw->iec_offset = 0; ++ ++ i = dw->channels; ++ do { ++ uint32_t sample = *src++; ++ ++ sample &= ~0xff000000; ++ sample |= *cs++ << 24; ++ sample |= parity(sample & ~0xf8000000); ++ ++ *dst++ = sample; ++ } while (--i); ++ } while (src < end); ++} ++ ++static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw, ++ struct snd_pcm_runtime *runtime) ++{ ++ uint8_t cs[4]; ++ unsigned ch, i, j; ++ ++ cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; ++ cs[1] = IEC958_AES1_CON_GENERAL; ++ cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC; ++ cs[3] = IEC958_AES3_CON_CLOCK_1000PPM; ++ ++ switch (runtime->rate) { ++ case 32000: ++ cs[3] |= IEC958_AES3_CON_FS_32000; ++ break; ++ case 44100: ++ cs[3] |= IEC958_AES3_CON_FS_44100; ++ break; ++ case 48000: ++ cs[3] |= IEC958_AES3_CON_FS_48000; ++ break; ++ case 88200: ++ cs[3] |= IEC958_AES3_CON_FS_88200; ++ break; ++ case 96000: ++ cs[3] |= IEC958_AES3_CON_FS_96000; ++ break; ++ case 176400: ++ cs[3] |= IEC958_AES3_CON_FS_176400; ++ break; ++ case 192000: ++ cs[3] |= IEC958_AES3_CON_FS_192000; ++ break; ++ } ++ ++ memset(dw->cs, 0, sizeof(dw->cs)); ++ ++ for (ch = 0; ch < 8; ch++) { ++ cs[2] &= ~IEC958_AES2_CON_CHANNEL; ++ cs[2] |= (ch + 1) << 4; ++ ++ for (i = 0; i < ARRAY_SIZE(cs); i++) { ++ unsigned c = cs[i]; ++ ++ for (j = 0; j < 8; j++, c >>= 1) ++ dw->cs[i * 8 + j][ch] = (c & 1) << 2; ++ } ++ } ++ dw->cs[0][0] |= BIT(4); ++} ++ ++static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw) ++{ ++ void __iomem *base = dw->data.base; ++ unsigned offset = dw->buf_offset; ++ unsigned period = dw->buf_period; ++ u32 start, stop; ++ ++ dw->reformat(dw, offset, period); ++ ++ /* Clear all irqs before enabling irqs and starting DMA */ ++ writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL, ++ base + HDMI_IH_AHBDMAAUD_STAT0); ++ ++ start = dw->buf_addr + offset; ++ stop = start + period - 1; ++ ++ /* Setup the hardware start/stop addresses */ ++ dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0); ++ dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0); ++ ++ writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK); ++ writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START); ++ ++ offset += period; ++ if (offset >= dw->buf_size) ++ offset = 0; ++ dw->buf_offset = offset; ++} ++ ++static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw) ++{ ++ dw->substream = NULL; ++ ++ /* Disable interrupts before disabling DMA */ ++ writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK); ++ writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP); ++} ++ ++static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) ++{ ++ struct snd_dw_hdmi *dw = data; ++ struct snd_pcm_substream *substream; ++ unsigned stat; ++ ++ stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0); ++ if (!stat) ++ return IRQ_NONE; ++ ++ writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0); ++ ++ substream = dw->substream; ++ if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) { ++ snd_pcm_period_elapsed(substream); ++ if (dw->substream) ++ dw_hdmi_start_dma(dw); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static struct snd_pcm_hardware dw_hdmi_hw = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID, ++ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | ++ SNDRV_PCM_FMTBIT_S24_LE, ++ .rates = SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .channels_min = 2, ++ .channels_max = 8, ++ .buffer_bytes_max = 64 * 1024, ++ .period_bytes_min = 256, ++ .period_bytes_max = 8192, /* ERR004323: must limit to 8k */ ++ .periods_min = 2, ++ .periods_max = 16, ++ .fifo_size = 0, ++}; ++ ++static unsigned rates_mask[] = { ++ SNDRV_PCM_RATE_32000, ++ SNDRV_PCM_RATE_44100, ++ SNDRV_PCM_RATE_48000, ++ SNDRV_PCM_RATE_88200, ++ SNDRV_PCM_RATE_96000, ++ SNDRV_PCM_RATE_176400, ++ SNDRV_PCM_RATE_192000, ++}; ++ ++static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw, ++ struct snd_pcm_runtime *runtime) ++{ ++ u8 *sad, *eld = dw->data.eld; ++ unsigned eld_ver, mnl, sad_count, rates, rate_mask, i; ++ unsigned max_channels; ++ ++ eld_ver = eld[0] >> 3; ++ if (eld_ver != 2 && eld_ver != 31) ++ return; ++ ++ mnl = eld[4] & 0x1f; ++ if (mnl > 16) ++ return; ++ ++ sad_count = eld[5] >> 4; ++ sad = eld + 20 + mnl; ++ ++ /* Start from the basic audio settings */ ++ max_channels = 2; ++ rates = 7; ++ while (sad_count > 0) { ++ switch (sad[0] & 0x78) { ++ case 0x08: /* PCM */ ++ max_channels = max(max_channels, (sad[0] & 7) + 1u); ++ rates |= sad[1]; ++ break; ++ } ++ sad += 3; ++ sad_count -= 1; ++ } ++ ++ for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++) ++ if (rates & 1 << i) ++ rate_mask |= rates_mask[i]; ++ ++ runtime->hw.rates &= rate_mask; ++ runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels); ++} ++ ++static int dw_hdmi_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct snd_dw_hdmi *dw = substream->private_data; ++ void __iomem *base = dw->data.base; ++ int ret; ++ ++ /* Clear FIFO */ ++ writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST, ++ base + HDMI_AHB_DMA_CONF0); ++ ++ /* Configure interrupt polarities */ ++ writeb_relaxed(~0, base + HDMI_AHB_DMA_POL); ++ writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL); ++ ++ /* Keep interrupts masked, and clear any pending */ ++ writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK); ++ writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0); ++ ++ ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED, ++ "dw-hdmi-audio", dw); ++ if (ret) ++ return ret; ++ ++ /* Un-mute done interrupt */ ++ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL & ++ ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE, ++ base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); ++ ++ runtime->hw = dw_hdmi_hw; ++ dw_hdmi_parse_eld(dw, runtime); ++ snd_pcm_limit_hw_rates(runtime); ++ ++ return 0; ++} ++ ++static int dw_hdmi_close(struct snd_pcm_substream *substream) ++{ ++ struct snd_dw_hdmi *dw = substream->private_data; ++ ++ /* Mute all interrupts */ ++ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, ++ dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); ++ ++ free_irq(dw->data.irq, dw); ++ ++ return 0; ++} ++ ++static int dw_hdmi_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_vmalloc_buffer(substream); ++} ++ ++static int dw_hdmi_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ return snd_pcm_lib_alloc_vmalloc_buffer(substream, ++ params_buffer_bytes(params)); ++} ++ ++static int dw_hdmi_prepare(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct snd_dw_hdmi *dw = substream->private_data; ++ uint8_t threshold, conf0, conf1; ++ ++ /* Setup as per 3.0.5 FSL 4.1.0 BSP */ ++ switch (dw->revision) { ++ case 0x0a: ++ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | ++ HDMI_AHB_DMA_CONF0_INCR4; ++ if (runtime->channels == 2) ++ threshold = 126; ++ else ++ threshold = 124; ++ break; ++ case 0x1a: ++ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | ++ HDMI_AHB_DMA_CONF0_INCR8; ++ threshold = 128; ++ break; ++ default: ++ /* NOTREACHED */ ++ return -EINVAL; ++ } ++ ++ dw->data.set_sample_rate(dw->data.hdmi, runtime->rate); ++ ++ /* Minimum number of bytes in the fifo. */ ++ runtime->hw.fifo_size = threshold * 32; ++ ++ conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK; ++ conf1 = (1 << runtime->channels) - 1; ++ ++ writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD); ++ writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0); ++ writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1); ++ ++ switch (runtime->format) { ++ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: ++ dw->reformat = dw_hdmi_reformat_iec958; ++ break; ++ case SNDRV_PCM_FORMAT_S24_LE: ++ dw_hdmi_create_cs(dw, runtime); ++ dw->reformat = dw_hdmi_reformat_s24; ++ break; ++ } ++ dw->iec_offset = 0; ++ dw->channels = runtime->channels; ++ dw->buf_src = runtime->dma_area; ++ dw->buf_dst = substream->dma_buffer.area; ++ dw->buf_addr = substream->dma_buffer.addr; ++ dw->buf_period = snd_pcm_lib_period_bytes(substream); ++ dw->buf_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ return 0; ++} ++ ++static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct snd_dw_hdmi *dw = substream->private_data; ++ void __iomem *base = dw->data.base; ++ unsigned n[3], cts[3]; ++ int ret = 0, i; ++ bool err005174; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ err005174 = dw->revision == 0x0a; ++ if (err005174) { ++ for (i = 2; i >= 1; i--) { ++ n[i] = readb_relaxed(base + HDMI_AUD_N1 + i); ++ cts[i] = readb_relaxed(base + HDMI_AUD_CTS1 + i); ++ writeb_relaxed(0, base + HDMI_AUD_N1 + i); ++ writeb_relaxed(0, base + HDMI_AUD_CTS1 + i); ++ } ++ } ++ ++ dw->buf_offset = 0; ++ dw->substream = substream; ++ dw_hdmi_start_dma(dw); ++ ++ if (err005174) { ++ for (i = 2; i >= 1; i--) ++ writeb_relaxed(cts[i], base + HDMI_AUD_CTS1 + i); ++ for (i = 2; i >= 1; i--) ++ writeb_relaxed(n[i], base + HDMI_AUD_N1 + i); ++ } ++ ++ substream->runtime->delay = substream->runtime->period_size; ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ dw_hdmi_stop_dma(dw); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct snd_dw_hdmi *dw = substream->private_data; ++ ++ return bytes_to_frames(runtime, dw->buf_offset); ++} ++ ++static struct snd_pcm_ops snd_dw_hdmi_ops = { ++ .open = dw_hdmi_open, ++ .close = dw_hdmi_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = dw_hdmi_hw_params, ++ .hw_free = dw_hdmi_hw_free, ++ .prepare = dw_hdmi_prepare, ++ .trigger = dw_hdmi_trigger, ++ .pointer = dw_hdmi_pointer, ++ .page = snd_pcm_lib_get_vmalloc_page, ++}; ++ ++static int snd_dw_hdmi_probe(struct platform_device *pdev) ++{ ++ const struct dw_hdmi_audio_data *data = pdev->dev.platform_data; ++ struct device *dev = pdev->dev.parent; ++ struct snd_dw_hdmi *dw; ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ unsigned revision; ++ int ret; ++ ++ writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, ++ data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); ++ revision = readb_relaxed(data->base + HDMI_REVISION_ID); ++ if (revision != 0x0a && revision != 0x1a) { ++ dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n", ++ revision); ++ return -ENXIO; ++ } ++ ++ ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, ++ THIS_MODULE, sizeof(struct snd_dw_hdmi), &card); ++ if (ret < 0) ++ return ret; ++ ++ strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); ++ strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname)); ++ snprintf(card->longname, sizeof(card->longname), ++ "%s rev 0x%02x, irq %d", card->shortname, revision, ++ data->irq); ++ ++ dw = card->private_data; ++ dw->card = card; ++ dw->data = *data; ++ dw->revision = revision; ++ ++ ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm); ++ if (ret < 0) ++ goto err; ++ ++ dw->pcm = pcm; ++ pcm->private_data = dw; ++ strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops); ++ ++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, ++ dev, 64 * 1024, 64 * 1024); ++ ++ ret = snd_card_register(card); ++ if (ret < 0) ++ goto err; ++ ++ platform_set_drvdata(pdev, dw); ++ ++ return 0; ++ ++err: ++ snd_card_free(card); ++ return ret; ++} ++ ++static int snd_dw_hdmi_remove(struct platform_device *pdev) ++{ ++ struct snd_dw_hdmi *dw = platform_get_drvdata(pdev); ++ ++ snd_card_free(dw->card); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int snd_dw_hdmi_suspend(struct device *dev) ++{ ++ struct snd_dw_hdmi *dw = dev_get_drvdata(dev); ++ ++ snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold); ++ snd_pcm_suspend_all(dw->pcm); ++ ++ return 0; ++} ++ ++static int snd_dw_hdmi_resume(struct device *dev) ++{ ++ struct snd_dw_hdmi *dw = dev_get_drvdata(dev); ++ ++ snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend, ++ snd_dw_hdmi_resume); ++#define PM_OPS &snd_dw_hdmi_pm ++#else ++#define PM_OPS NULL ++#endif ++ ++static struct platform_driver snd_dw_hdmi_driver = { ++ .probe = snd_dw_hdmi_probe, ++ .remove = snd_dw_hdmi_remove, ++ .driver = { ++ .name = "dw-hdmi-audio", ++ .owner = THIS_MODULE, ++ .pm = PM_OPS, ++ }, ++}; ++ ++module_platform_driver(snd_dw_hdmi_driver); ++ ++MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h +new file mode 100644 +index 000000000000..2d91d709381d +--- /dev/null ++++ b/drivers/staging/imx-drm/dw-hdmi-audio.h +@@ -0,0 +1,15 @@ ++#ifndef DW_HDMI_AUDIO_H ++#define DW_HDMI_AUDIO_H ++ ++struct imx_hdmi; ++ ++struct dw_hdmi_audio_data { ++ phys_addr_t phys; ++ void __iomem *base; ++ int irq; ++ struct imx_hdmi *hdmi; ++ u8 *eld; ++ void (*set_sample_rate)(struct imx_hdmi *, unsigned); ++}; ++ ++#endif +diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.c b/drivers/staging/imx-drm/dw-hdmi-cec.c +new file mode 100644 +index 000000000000..c94b75aa037b +--- /dev/null ++++ b/drivers/staging/imx-drm/dw-hdmi-cec.c +@@ -0,0 +1,205 @@ ++/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */ ++#include <linux/cec-dev.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++ ++#include "imx-hdmi.h" ++#include "dw-hdmi-cec.h" ++ ++#define DEV_NAME "mxc_hdmi_cec" ++ ++enum { ++ CEC_STAT_DONE = BIT(0), ++ CEC_STAT_EOM = BIT(1), ++ CEC_STAT_NACK = BIT(2), ++ CEC_STAT_ARBLOST = BIT(3), ++ CEC_STAT_ERROR_INIT = BIT(4), ++ CEC_STAT_ERROR_FOLL = BIT(5), ++ CEC_STAT_WAKEUP = BIT(6), ++ ++ CEC_CTRL_START = BIT(0), ++ CEC_CTRL_NORMAL = 1 << 1, ++}; ++ ++struct dw_hdmi_cec { ++ struct cec_dev cec; ++ ++ struct device *dev; ++ void __iomem *base; ++ const struct dw_hdmi_cec_ops *ops; ++ void *ops_data; ++ int irq; ++}; ++ ++static void dw_hdmi_set_address(struct cec_dev *cec_dev, unsigned addresses) ++{ ++ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); ++ ++ writeb(addresses & 255, cec->base + HDMI_CEC_ADDR_L); ++ writeb(addresses >> 8, cec->base + HDMI_CEC_ADDR_H); ++} ++ ++static void dw_hdmi_send_message(struct cec_dev *cec_dev, u8 *msg, ++ size_t count) ++{ ++ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); ++ unsigned i; ++ ++ for (i = 0; i < count; i++) ++ writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i); ++ ++ writeb(count, cec->base + HDMI_CEC_TX_CNT); ++ writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); ++} ++ ++static irqreturn_t dw_hdmi_cec_irq(int irq, void *data) ++{ ++ struct dw_hdmi_cec *cec = data; ++ struct cec_dev *cec_dev = &cec->cec; ++ unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0); ++ ++ if (stat == 0) ++ return IRQ_NONE; ++ ++ writeb(stat, cec->base + HDMI_IH_CEC_STAT0); ++ ++ if (stat & CEC_STAT_ERROR_INIT) { ++ if (cec->cec.retries) { ++ unsigned v = readb(cec->base + HDMI_CEC_CTRL); ++ writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL); ++ cec->cec.retries -= 1; ++ } else { ++ cec->cec.write_busy = 0; ++ cec_dev_event(cec_dev, MESSAGE_TYPE_SEND_ERROR, NULL, 0); ++ } ++ } else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK)) ++ cec_dev_send_complete(cec_dev, stat & CEC_STAT_DONE); ++ ++ if (stat & CEC_STAT_EOM) { ++ unsigned len, i; ++ u8 msg[MAX_MESSAGE_LEN]; ++ ++ len = readb(cec->base + HDMI_CEC_RX_CNT); ++ if (len > sizeof(msg)) ++ len = sizeof(msg); ++ ++ for (i = 0; i < len; i++) ++ msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i); ++ ++ writeb(0, cec->base + HDMI_CEC_LOCK); ++ ++ cec_dev_receive(cec_dev, msg, len); ++ } ++ ++ return IRQ_HANDLED; ++} ++EXPORT_SYMBOL(dw_hdmi_cec_irq); ++ ++static void dw_hdmi_cec_release(struct cec_dev *cec_dev) ++{ ++ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); ++ ++ writeb(~0, cec->base + HDMI_CEC_MASK); ++ writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); ++ writeb(0, cec->base + HDMI_CEC_POLARITY); ++ ++ free_irq(cec->irq, cec); ++ ++ cec->ops->disable(cec->ops_data); ++} ++ ++static int dw_hdmi_cec_open(struct cec_dev *cec_dev) ++{ ++ struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec); ++ unsigned irqs; ++ int ret; ++ ++ writeb(0, cec->base + HDMI_CEC_CTRL); ++ writeb(~0, cec->base + HDMI_IH_CEC_STAT0); ++ writeb(0, cec->base + HDMI_CEC_LOCK); ++ ++ ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED, ++ DEV_NAME, cec); ++ if (ret < 0) ++ return ret; ++ ++ dw_hdmi_set_address(cec_dev, cec_dev->addresses); ++ ++ cec->ops->enable(cec->ops_data); ++ ++ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | ++ CEC_STAT_DONE; ++ writeb(irqs, cec->base + HDMI_CEC_POLARITY); ++ writeb(~irqs, cec->base + HDMI_CEC_MASK); ++ writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0); ++ ++ return 0; ++} ++ ++static int dw_hdmi_cec_probe(struct platform_device *pdev) ++{ ++ struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev); ++ struct dw_hdmi_cec *cec; ++ ++ if (!data) ++ return -ENXIO; ++ ++ cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); ++ if (!cec) ++ return -ENOMEM; ++ ++ cec->dev = &pdev->dev; ++ cec->base = data->base; ++ cec->irq = data->irq; ++ cec->ops = data->ops; ++ cec->ops_data = data->ops_data; ++ cec->cec.open = dw_hdmi_cec_open; ++ cec->cec.release = dw_hdmi_cec_release; ++ cec->cec.send_message = dw_hdmi_send_message; ++ cec->cec.set_address = dw_hdmi_set_address; ++ ++ cec_dev_init(&cec->cec, THIS_MODULE); ++ ++ /* FIXME: soft-reset the CEC interface */ ++ ++ dw_hdmi_set_address(&cec->cec, cec->cec.addresses); ++ writeb(0, cec->base + HDMI_CEC_TX_CNT); ++ writeb(~0, cec->base + HDMI_CEC_MASK); ++ writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0); ++ writeb(0, cec->base + HDMI_CEC_POLARITY); ++ ++ /* ++ * Our device is just a convenience - we want to link to the real ++ * hardware device here, so that userspace can see the association ++ * between the HDMI hardware and its associated CEC chardev. ++ */ ++ return cec_dev_add(&cec->cec, cec->dev->parent, DEV_NAME); ++} ++ ++static int dw_hdmi_cec_remove(struct platform_device *pdev) ++{ ++ struct dw_hdmi_cec *cec = platform_get_drvdata(pdev); ++ ++ cec_dev_remove(&cec->cec); ++ ++ return 0; ++} ++ ++static struct platform_driver dw_hdmi_cec_driver = { ++ .probe = dw_hdmi_cec_probe, ++ .remove = dw_hdmi_cec_remove, ++ .driver = { ++ .name = "dw-hdmi-cec", ++ .owner = THIS_MODULE, ++ }, ++}; ++module_platform_driver(dw_hdmi_cec_driver); ++ ++MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec"); +diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.h b/drivers/staging/imx-drm/dw-hdmi-cec.h +new file mode 100644 +index 000000000000..5ff40cc237a8 +--- /dev/null ++++ b/drivers/staging/imx-drm/dw-hdmi-cec.h +@@ -0,0 +1,16 @@ ++#ifndef DW_HDMI_CEC_H ++#define DW_HDMI_CEC_H ++ ++struct dw_hdmi_cec_ops { ++ void (*enable)(void *); ++ void (*disable)(void *); ++}; ++ ++struct dw_hdmi_cec_data { ++ void __iomem *base; ++ int irq; ++ const struct dw_hdmi_cec_ops *ops; ++ void *ops_data; ++}; ++ ++#endif +diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c +index d47dedd2cdb4..627b4b608794 100644 +--- a/drivers/staging/imx-drm/imx-hdmi.c ++++ b/drivers/staging/imx-drm/imx-hdmi.c +@@ -28,6 +28,9 @@ + #include <drm/drm_edid.h> + #include <drm/drm_encoder_slave.h> + ++#include "drm-ddc-connector.h" ++#include "dw-hdmi-audio.h" ++#include "dw-hdmi-cec.h" + #include "ipu-v3/imx-ipu-v3.h" + #include "imx-hdmi.h" + #include "imx-drm.h" +@@ -112,27 +115,27 @@ struct hdmi_data_info { + }; + + struct imx_hdmi { +- struct drm_connector connector; ++ struct drm_ddc_connector *ddc_conn; + struct drm_encoder encoder; + ++ struct platform_device *audio; ++ struct platform_device *cec; + enum imx_hdmi_devtype dev_type; + struct device *dev; + struct clk *isfr_clk; + struct clk *iahb_clk; + +- enum drm_connector_status connector_status; +- + struct hdmi_data_info hdmi_data; + int vic; + + u8 edid[HDMI_EDID_LEN]; ++ u8 mc_clkdis; + bool cable_plugin; + + bool phy_enabled; + struct drm_display_mode previous_mode; + + struct regmap *regmap; +- struct i2c_adapter *ddc; + void __iomem *regs; + + unsigned int sample_rate; +@@ -362,6 +365,12 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi) + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); + } + ++static void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned rate) ++{ ++ hdmi->sample_rate = rate; ++ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); ++} ++ + /* + * this submodule is responsible for the video data synchronization. + * for example, for RGB 4:4:4 input, the data map is defined as +@@ -1148,8 +1157,6 @@ static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi) + /* HDMI Initialization Step B.4 */ + static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) + { +- u8 clkdis; +- + /* control period minimum duration */ + hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR); + hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR); +@@ -1161,23 +1168,28 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) + hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); + + /* Enable pixel clock and tmds data path */ +- clkdis = 0x7F; +- clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; +- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); ++ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE | ++ HDMI_MC_CLKDIS_CSCCLK_DISABLE | ++ HDMI_MC_CLKDIS_AUDCLK_DISABLE | ++ HDMI_MC_CLKDIS_PREPCLK_DISABLE | ++ HDMI_MC_CLKDIS_TMDSCLK_DISABLE; ++ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; ++ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); + +- clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; +- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); ++ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; ++ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); + + /* Enable csc path */ + if (is_color_space_conversion(hdmi)) { +- clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; +- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); ++ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; ++ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); + } + } + + static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) + { +- hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); ++ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; ++ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); + } + + /* Workaround to clear the overflow condition */ +@@ -1380,41 +1392,16 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi) + static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector + *connector, bool force) + { +- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, +- connector); +- return hdmi->connector_status; +-} +- +-static int imx_hdmi_connector_get_modes(struct drm_connector *connector) +-{ +- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, +- connector); +- struct edid *edid; +- int ret; +- +- if (!hdmi->ddc) +- return 0; +- +- edid = drm_get_edid(connector, hdmi->ddc); +- if (edid) { +- dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", +- edid->width_cm, edid->height_cm); +- +- drm_mode_connector_update_edid_property(connector, edid); +- ret = drm_add_edid_modes(connector, edid); +- kfree(edid); +- } else { +- dev_dbg(hdmi->dev, "failed to get edid\n"); +- } ++ struct imx_hdmi *hdmi = drm_ddc_private(connector); + +- return 0; ++ return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? ++ connector_status_connected : connector_status_disconnected; + } + + static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector + *connector) + { +- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, +- connector); ++ struct imx_hdmi *hdmi = drm_ddc_private(connector); + + return &hdmi->encoder; + } +@@ -1483,15 +1470,8 @@ static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { + .disable = imx_hdmi_encoder_disable, + }; + +-static struct drm_connector_funcs imx_hdmi_connector_funcs = { +- .dpms = drm_helper_connector_dpms, +- .fill_modes = drm_helper_probe_single_connector_modes, +- .detect = imx_hdmi_connector_detect, +- .destroy = imx_drm_connector_destroy, +-}; +- + static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { +- .get_modes = imx_hdmi_connector_get_modes, ++ .get_modes = drm_ddc_connector_get_modes, + .mode_valid = imx_drm_connector_mode_valid, + .best_encoder = imx_hdmi_connector_best_encoder, + }; +@@ -1524,7 +1504,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) + + hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); + +- hdmi->connector_status = connector_status_connected; + imx_hdmi_poweron(hdmi); + } else { + dev_dbg(hdmi->dev, "EVENT=plugout\n"); +@@ -1532,10 +1511,9 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) + hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, + HDMI_PHY_POL0); + +- hdmi->connector_status = connector_status_disconnected; + imx_hdmi_poweroff(hdmi); + } +- drm_helper_hpd_irq_event(hdmi->connector.dev); ++ drm_helper_hpd_irq_event(hdmi->ddc_conn->connector.dev); + } + + hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); +@@ -1553,24 +1531,42 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) + if (ret) + return ret; + +- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; ++ hdmi->ddc_conn->connector.polled = DRM_CONNECTOR_POLL_HPD; + + drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); + drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS); + +- drm_connector_helper_add(&hdmi->connector, ++ drm_connector_helper_add(&hdmi->ddc_conn->connector, + &imx_hdmi_connector_helper_funcs); +- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, +- DRM_MODE_CONNECTOR_HDMIA); +- +- hdmi->connector.encoder = &hdmi->encoder; ++ drm_ddc_connector_add(drm, hdmi->ddc_conn, DRM_MODE_CONNECTOR_HDMIA); + +- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); ++ drm_mode_connector_attach_encoder(&hdmi->ddc_conn->connector, &hdmi->encoder); + + return 0; + } + ++static void imx_hdmi_cec_enable(void *data) ++{ ++ struct imx_hdmi *hdmi = data; ++ ++ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; ++ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); ++} ++ ++static void imx_hdmi_cec_disable(void *data) ++{ ++ struct imx_hdmi *hdmi = data; ++ ++ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE; ++ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); ++} ++ ++static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = { ++ .enable = imx_hdmi_cec_enable, ++ .disable = imx_hdmi_cec_disable, ++}; ++ + static struct platform_device_id imx_hdmi_devtype[] = { + { + .name = "imx6q-hdmi", +@@ -1592,11 +1588,13 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); + static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); ++ struct platform_device_info pdevinfo; + const struct of_device_id *of_id = + of_match_device(imx_hdmi_dt_ids, dev); + struct drm_device *drm = data; + struct device_node *np = dev->of_node; +- struct device_node *ddc_node; ++ struct dw_hdmi_audio_data audio; ++ struct dw_hdmi_cec_data cec; + struct imx_hdmi *hdmi; + struct resource *iores; + int ret, irq; +@@ -1605,27 +1603,22 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) + if (!hdmi) + return -ENOMEM; + ++ hdmi->ddc_conn = drm_ddc_connector_create(drm, np, hdmi); ++ if (IS_ERR(hdmi->ddc_conn)) ++ return PTR_ERR(hdmi->ddc_conn); ++ ++ hdmi->ddc_conn->detect = imx_hdmi_connector_detect; ++ + hdmi->dev = dev; +- hdmi->connector_status = connector_status_disconnected; + hdmi->sample_rate = 48000; + hdmi->ratio = 100; ++ hdmi->mc_clkdis = 0x7f; + + if (of_id) { + const struct platform_device_id *device_id = of_id->data; + hdmi->dev_type = device_id->driver_data; + } + +- ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); +- if (ddc_node) { +- hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); +- if (!hdmi->ddc) +- dev_dbg(hdmi->dev, "failed to read ddc node\n"); +- +- of_node_put(ddc_node); +- } else { +- dev_dbg(hdmi->dev, "no ddc property found\n"); +- } +- + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; +@@ -1711,6 +1704,35 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) + /* Unmute interrupts */ + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); + ++ memset(&pdevinfo, 0, sizeof(pdevinfo)); ++ pdevinfo.parent = dev; ++ pdevinfo.id = PLATFORM_DEVID_AUTO; ++ ++ audio.phys = iores->start; ++ audio.base = hdmi->regs; ++ audio.irq = irq; ++ audio.hdmi = hdmi; ++ audio.eld = hdmi->ddc_conn->connector.eld; ++ audio.set_sample_rate = imx_hdmi_set_sample_rate; ++ ++ pdevinfo.name = "dw-hdmi-audio"; ++ pdevinfo.data = &audio; ++ pdevinfo.size_data = sizeof(audio); ++ pdevinfo.dma_mask = DMA_BIT_MASK(32); ++ hdmi->audio = platform_device_register_full(&pdevinfo); ++ ++ cec.base = hdmi->regs; ++ cec.irq = irq; ++ cec.ops = &imx_hdmi_cec_ops; ++ cec.ops_data = hdmi; ++ ++ pdevinfo.name = "dw-hdmi-cec"; ++ pdevinfo.data = &cec; ++ pdevinfo.size_data = sizeof(cec); ++ pdevinfo.dma_mask = 0; ++ ++ hdmi->cec = platform_device_register_full(&pdevinfo); ++ + dev_set_drvdata(dev, hdmi); + + return 0; +@@ -1728,15 +1750,19 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master, + { + struct imx_hdmi *hdmi = dev_get_drvdata(dev); + ++ if (!IS_ERR(hdmi->audio)) ++ platform_device_unregister(hdmi->audio); ++ if (!IS_ERR(hdmi->cec)) ++ platform_device_unregister(hdmi->cec); ++ + /* Disable all interrupts */ + hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); + +- hdmi->connector.funcs->destroy(&hdmi->connector); ++ hdmi->ddc_conn->connector.funcs->destroy(&hdmi->ddc_conn->connector); + hdmi->encoder.funcs->destroy(&hdmi->encoder); + + clk_disable_unprepare(hdmi->iahb_clk); + clk_disable_unprepare(hdmi->isfr_clk); +- i2c_put_adapter(hdmi->ddc); + } + + static const struct component_ops hdmi_ops = { +diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c +index fe4c1ef4e7a5..3a3bacec2e11 100644 +--- a/drivers/staging/imx-drm/imx-ldb.c ++++ b/drivers/staging/imx-drm/imx-ldb.c +@@ -24,6 +24,7 @@ + #include <drm/drmP.h> + #include <drm/drm_fb_helper.h> + #include <drm/drm_crtc_helper.h> ++#include <drm/drm_panel.h> + #include <linux/mfd/syscon.h> + #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> + #include <linux/of_address.h> +@@ -60,6 +61,7 @@ struct imx_ldb_channel { + struct imx_ldb *ldb; + struct drm_connector connector; + struct drm_encoder encoder; ++ struct drm_panel *panel; + struct device_node *child; + int chno; + void *edid; +@@ -96,6 +98,13 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) + struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); + int num_modes = 0; + ++ if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && ++ imx_ldb_ch->panel->funcs->get_modes) { ++ num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); ++ if (num_modes > 0) ++ return num_modes; ++ } ++ + if (imx_ldb_ch->edid) { + drm_mode_connector_update_edid_property(connector, + imx_ldb_ch->edid); +@@ -243,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) + } + + regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); ++ ++ drm_panel_enable(imx_ldb_ch->panel); + } + + static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, +@@ -294,6 +305,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) + (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) + return; + ++ drm_panel_disable(imx_ldb_ch->panel); ++ + if (imx_ldb_ch == &ldb->channel[0]) + ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; + else if (imx_ldb_ch == &ldb->channel[1]) +@@ -379,6 +392,9 @@ static int imx_ldb_register(struct drm_device *drm, + drm_connector_init(drm, &imx_ldb_ch->connector, + &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); + ++ if (imx_ldb_ch->panel) ++ drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); ++ + drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, + &imx_ldb_ch->encoder); + +@@ -493,6 +509,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) + + for_each_child_of_node(np, child) { + struct imx_ldb_channel *channel; ++ struct device_node *panel_node; + + ret = of_property_read_u32(child, "reg", &i); + if (ret || i < 0 || i > 1) +@@ -556,6 +573,10 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) + return -EINVAL; + } + ++ panel_node = of_parse_phandle(child, "fsl,panel", 0); ++ if (panel_node) ++ channel->panel = of_drm_find_panel(panel_node); ++ + ret = imx_ldb_register(drm, channel); + if (ret) + return ret; +diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c +index a23f4f773146..6eafba5072ad 100644 +--- a/drivers/staging/imx-drm/imx-tve.c ++++ b/drivers/staging/imx-drm/imx-tve.c +@@ -22,7 +22,6 @@ + #include <linux/clk-provider.h> + #include <linux/component.h> + #include <linux/module.h> +-#include <linux/i2c.h> + #include <linux/regmap.h> + #include <linux/regulator/consumer.h> + #include <linux/spinlock.h> +@@ -31,6 +30,7 @@ + #include <drm/drm_fb_helper.h> + #include <drm/drm_crtc_helper.h> + ++#include "drm-ddc-connector.h" + #include "ipu-v3/imx-ipu-v3.h" + #include "imx-drm.h" + +@@ -111,7 +111,7 @@ enum { + }; + + struct imx_tve { +- struct drm_connector connector; ++ struct drm_ddc_connector *ddc_conn; + struct drm_encoder encoder; + struct device *dev; + spinlock_t lock; /* register lock */ +@@ -120,7 +120,6 @@ struct imx_tve { + + struct regmap *regmap; + struct regulator *dac_reg; +- struct i2c_adapter *ddc; + struct clk *clk; + struct clk *di_sel_clk; + struct clk_hw clk_hw_di; +@@ -219,35 +218,10 @@ static int tve_setup_vga(struct imx_tve *tve) + return 0; + } + +-static enum drm_connector_status imx_tve_connector_detect( +- struct drm_connector *connector, bool force) +-{ +- return connector_status_connected; +-} +- +-static int imx_tve_connector_get_modes(struct drm_connector *connector) +-{ +- struct imx_tve *tve = con_to_tve(connector); +- struct edid *edid; +- int ret = 0; +- +- if (!tve->ddc) +- return 0; +- +- edid = drm_get_edid(connector, tve->ddc); +- if (edid) { +- drm_mode_connector_update_edid_property(connector, edid); +- ret = drm_add_edid_modes(connector, edid); +- kfree(edid); +- } +- +- return ret; +-} +- + static int imx_tve_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) + { +- struct imx_tve *tve = con_to_tve(connector); ++ struct imx_tve *tve = to_ddc_conn(connector)->private; + unsigned long rate; + int ret; + +@@ -274,7 +248,7 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector, + static struct drm_encoder *imx_tve_connector_best_encoder( + struct drm_connector *connector) + { +- struct imx_tve *tve = con_to_tve(connector); ++ struct imx_tve *tve = drm_ddc_private(connector); + + return &tve->encoder; + } +@@ -362,15 +336,8 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder) + tve_disable(tve); + } + +-static struct drm_connector_funcs imx_tve_connector_funcs = { +- .dpms = drm_helper_connector_dpms, +- .fill_modes = drm_helper_probe_single_connector_modes, +- .detect = imx_tve_connector_detect, +- .destroy = imx_drm_connector_destroy, +-}; +- + static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { +- .get_modes = imx_tve_connector_get_modes, ++ .get_modes = drm_ddc_connector_get_modes, + .best_encoder = imx_tve_connector_best_encoder, + .mode_valid = imx_tve_connector_mode_valid, + }; +@@ -513,12 +480,11 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) + drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs, + encoder_type); + +- drm_connector_helper_add(&tve->connector, ++ drm_connector_helper_add(&tve->ddc_conn->connector, + &imx_tve_connector_helper_funcs); +- drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, +- DRM_MODE_CONNECTOR_VGA); ++ drm_ddc_connector_add(drm, tve->ddc_conn, DRM_MODE_CONNECTOR_VGA); + +- drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); ++ drm_mode_connector_attach_encoder(&tve->ddc_conn->connector, &tve->encoder); + + return 0; + } +@@ -567,7 +533,6 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = data; + struct device_node *np = dev->of_node; +- struct device_node *ddc_node; + struct imx_tve *tve; + struct resource *res; + void __iomem *base; +@@ -579,15 +544,13 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) + if (!tve) + return -ENOMEM; + ++ tve->ddc_conn = drm_ddc_connector_create(drm, np, tve); ++ if (IS_ERR(tve->ddc_conn)) ++ return PTR_ERR(tve->ddc_conn); ++ + tve->dev = dev; + spin_lock_init(&tve->lock); + +- ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); +- if (ddc_node) { +- tve->ddc = of_find_i2c_adapter_by_node(ddc_node); +- of_node_put(ddc_node); +- } +- + tve->mode = of_get_tve_mode(np); + if (tve->mode != TVE_MODE_VGA) { + dev_err(dev, "only VGA mode supported, currently\n"); +@@ -694,7 +657,7 @@ static void imx_tve_unbind(struct device *dev, struct device *master, + { + struct imx_tve *tve = dev_get_drvdata(dev); + +- tve->connector.funcs->destroy(&tve->connector); ++ tve->ddc_conn->connector.funcs->destroy(&tve->ddc_conn->connector); + tve->encoder.funcs->destroy(&tve->encoder); + + if (!IS_ERR(tve->dac_reg)) +diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +index c4d14ead5837..c2c6fab05eaa 100644 +--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h ++++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +@@ -76,6 +76,7 @@ enum ipu_channel_irq { + IPU_IRQ_EOS = 192, + }; + ++int ipu_map_irq(struct ipu_soc *ipu, int irq); + int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, + enum ipu_channel_irq irq); + +@@ -114,8 +115,10 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel); + void ipu_dc_put(struct ipu_dc *dc); + int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, + u32 pixel_fmt, u32 width); ++void ipu_dc_enable(struct ipu_soc *ipu); + void ipu_dc_enable_channel(struct ipu_dc *dc); + void ipu_dc_disable_channel(struct ipu_dc *dc); ++void ipu_dc_disable(struct ipu_soc *ipu); + + /* + * IPU Display Interface (di) functions +@@ -152,8 +155,10 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc); + + struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow); + void ipu_dp_put(struct ipu_dp *); ++int ipu_dp_enable(struct ipu_soc *ipu); + int ipu_dp_enable_channel(struct ipu_dp *dp); + void ipu_dp_disable_channel(struct ipu_dp *dp); ++void ipu_dp_disable(struct ipu_soc *ipu); + int ipu_dp_setup_channel(struct ipu_dp *dp, + enum ipu_color_space in, enum ipu_color_space out); + int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos); +diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c +index ca85d3d70ae3..8fb4c207f3f1 100644 +--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c ++++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c +@@ -697,6 +697,12 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel) + } + EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); + ++bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno) ++{ ++ return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno)); ++} ++EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy); ++ + int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) + { + struct ipu_soc *ipu = channel->ipu; +@@ -714,6 +720,22 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) + } + EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy); + ++int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms) ++{ ++ unsigned long timeout; ++ ++ timeout = jiffies + msecs_to_jiffies(ms); ++ ipu_cm_write(ipu, BIT(irq % 32), IPU_INT_STAT(irq / 32)); ++ while (!(ipu_cm_read(ipu, IPU_INT_STAT(irq / 32) & BIT(irq % 32)))) { ++ if (time_after(jiffies, timeout)) ++ return -ETIMEDOUT; ++ cpu_relax(); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ipu_wait_interrupt); ++ + int ipu_idmac_disable_channel(struct ipuv3_channel *channel) + { + struct ipu_soc *ipu = channel->ipu; +@@ -933,15 +955,22 @@ static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) + chained_irq_exit(chip, desc); + } + +-int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, +- enum ipu_channel_irq irq_type) ++int ipu_map_irq(struct ipu_soc *ipu, int irq) + { +- int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num); ++ int virq; + +- if (!irq) +- irq = irq_create_mapping(ipu->domain, irq_type + channel->num); ++ virq = irq_linear_revmap(ipu->domain, irq); ++ if (!virq) ++ virq = irq_create_mapping(ipu->domain, irq); + +- return irq; ++ return virq; ++} ++EXPORT_SYMBOL_GPL(ipu_map_irq); ++ ++int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, ++ enum ipu_channel_irq irq_type) ++{ ++ return ipu_map_irq(ipu, irq_type + channel->num); + } + EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq); + +diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c +index d5de8bb5c803..97cf6fad2427 100644 +--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c ++++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c +@@ -18,6 +18,7 @@ + #include <linux/types.h> + #include <linux/errno.h> + #include <linux/delay.h> ++#include <linux/interrupt.h> + #include <linux/io.h> + + #include "../imx-drm.h" +@@ -92,6 +93,7 @@ enum ipu_dc_map { + IPU_DC_MAP_GBR24, /* TVEv2 */ + IPU_DC_MAP_BGR666, + IPU_DC_MAP_BGR24, ++ IPU_DC_MAP_RGB666, + }; + + struct ipu_dc { +@@ -110,6 +112,9 @@ struct ipu_dc_priv { + struct device *dev; + struct ipu_dc channels[IPU_DC_NUM_CHANNELS]; + struct mutex mutex; ++ struct completion comp; ++ int dc_irq; ++ int dp_irq; + }; + + static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) +@@ -155,6 +160,8 @@ static int ipu_pixfmt_to_map(u32 fmt) + return IPU_DC_MAP_BGR666; + case V4L2_PIX_FMT_BGR24: + return IPU_DC_MAP_BGR24; ++ case V4L2_PIX_FMT_RGB666: ++ return IPU_DC_MAP_RGB666; + default: + return -EINVAL; + } +@@ -220,12 +227,16 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, + writel(0x0, dc->base + DC_WR_CH_ADDR); + writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di)); + +- ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); +- + return 0; + } + EXPORT_SYMBOL_GPL(ipu_dc_init_sync); + ++void ipu_dc_enable(struct ipu_soc *ipu) ++{ ++ ipu_module_enable(ipu, IPU_CONF_DC_EN); ++} ++EXPORT_SYMBOL_GPL(ipu_dc_enable); ++ + void ipu_dc_enable_channel(struct ipu_dc *dc) + { + int di; +@@ -239,41 +250,55 @@ void ipu_dc_enable_channel(struct ipu_dc *dc) + } + EXPORT_SYMBOL_GPL(ipu_dc_enable_channel); + ++static irqreturn_t dc_irq_handler(int irq, void *dev_id) ++{ ++ struct ipu_dc *dc = dev_id; ++ u32 reg; ++ ++ reg = readl(dc->base + DC_WR_CH_CONF); ++ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; ++ writel(reg, dc->base + DC_WR_CH_CONF); ++ ++ /* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */ ++ ++ complete(&dc->priv->comp); ++ return IRQ_HANDLED; ++} ++ + void ipu_dc_disable_channel(struct ipu_dc *dc) + { + struct ipu_dc_priv *priv = dc->priv; ++ int irq, ret; + u32 val; +- int irq = 0, timeout = 50; + ++ /* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */ + if (dc->chno == 1) +- irq = IPU_IRQ_DC_FC_1; ++ irq = priv->dc_irq; + else if (dc->chno == 5) +- irq = IPU_IRQ_DP_SF_END; ++ irq = priv->dp_irq; + else + return; + +- /* should wait for the interrupt here */ +- mdelay(50); ++ init_completion(&priv->comp); ++ enable_irq(irq); ++ ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50)); ++ disable_irq(irq); ++ if (ret <= 0) { ++ dev_warn(priv->dev, "DC stop timeout after 50 ms\n"); + +- if (dc->di == 0) +- val = 0x00000002; +- else +- val = 0x00000020; +- +- /* Wait for DC triple buffer to empty */ +- while ((readl(priv->dc_reg + DC_STAT) & val) != val) { +- usleep_range(2000, 20000); +- timeout -= 2; +- if (timeout <= 0) +- break; ++ val = readl(dc->base + DC_WR_CH_CONF); ++ val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; ++ writel(val, dc->base + DC_WR_CH_CONF); + } +- +- val = readl(dc->base + DC_WR_CH_CONF); +- val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; +- writel(val, dc->base + DC_WR_CH_CONF); + } + EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); + ++void ipu_dc_disable(struct ipu_soc *ipu) ++{ ++ ipu_module_disable(ipu, IPU_CONF_DC_EN); ++} ++EXPORT_SYMBOL_GPL(ipu_dc_disable); ++ + static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map, + int byte_num, int offset, int mask) + { +@@ -340,7 +365,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, + struct ipu_dc_priv *priv; + static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, + 0x78, 0, 0x94, 0xb4}; +- int i; ++ int i, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -361,6 +386,23 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, + priv->channels[i].base = priv->dc_reg + channel_offsets[i]; + } + ++ priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1); ++ if (!priv->dc_irq) ++ return -EINVAL; ++ ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL, ++ &priv->channels[1]); ++ if (ret < 0) ++ return ret; ++ disable_irq(priv->dc_irq); ++ priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END); ++ if (!priv->dp_irq) ++ return -EINVAL; ++ ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL, ++ &priv->channels[5]); ++ if (ret < 0) ++ return ret; ++ disable_irq(priv->dp_irq); ++ + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) | + DC_WR_CH_CONF_PROG_DI_ID, + priv->channels[1].base + DC_WR_CH_CONF); +@@ -404,6 +446,12 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */ + ++ /* rgb666 */ ++ ipu_dc_map_clear(priv, IPU_DC_MAP_RGB666); ++ ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 0, 5, 0xfc); /* blue */ ++ ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 1, 11, 0xfc); /* green */ ++ ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 2, 17, 0xfc); /* red */ ++ + return 0; + } + +diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c +index 82a9ebad697c..849b3e120ef0 100644 +--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c ++++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c +@@ -595,7 +595,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) + } + } + +- if (!sig->clk_pol) ++ if (sig->clk_pol) + di_gen |= DI_GEN_POLARITY_DISP_CLK; + + ipu_di_write(di, di_gen, DI_GENERAL); +diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +index 45213017fa4b..59f182b28fc1 100644 +--- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c ++++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +@@ -28,7 +28,12 @@ + #define DMFC_GENERAL1 0x0014 + #define DMFC_GENERAL2 0x0018 + #define DMFC_IC_CTRL 0x001c +-#define DMFC_STAT 0x0020 ++#define DMFC_WR_CHAN_ALT 0x0020 ++#define DMFC_WR_CHAN_DEF_ALT 0x0024 ++#define DMFC_DP_CHAN_ALT 0x0028 ++#define DMFC_DP_CHAN_DEF_ALT 0x002c ++#define DMFC_GENERAL1_ALT 0x0030 ++#define DMFC_STAT 0x0034 + + #define DMFC_WR_CHAN_1_28 0 + #define DMFC_WR_CHAN_2_41 8 +@@ -133,6 +138,20 @@ int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) + } + EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); + ++static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv) ++{ ++ unsigned long timeout = jiffies + msecs_to_jiffies(1000); ++ ++ while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) { ++ if (time_after(jiffies, timeout)) { ++ dev_warn(priv->dev, ++ "Timeout waiting for DMFC FIFOs to clear\n"); ++ break; ++ } ++ cpu_relax(); ++ } ++} ++ + void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) + { + struct ipu_dmfc_priv *priv = dmfc->priv; +@@ -141,8 +160,10 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) + + priv->use_count--; + +- if (!priv->use_count) ++ if (!priv->use_count) { ++ ipu_dmfc_wait_fifos(priv); + ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); ++ } + + if (priv->use_count < 0) + priv->use_count = 0; +diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c +index 58f87c8d7c07..d90f82a87d19 100644 +--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c ++++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c +@@ -215,10 +215,9 @@ int ipu_dp_setup_channel(struct ipu_dp *dp, + } + EXPORT_SYMBOL_GPL(ipu_dp_setup_channel); + +-int ipu_dp_enable_channel(struct ipu_dp *dp) ++int ipu_dp_enable(struct ipu_soc *ipu) + { +- struct ipu_flow *flow = to_flow(dp); +- struct ipu_dp_priv *priv = flow->priv; ++ struct ipu_dp_priv *priv = ipu->dp_priv; + + mutex_lock(&priv->mutex); + +@@ -227,15 +226,28 @@ int ipu_dp_enable_channel(struct ipu_dp *dp) + + priv->use_count++; + +- if (dp->foreground) { +- u32 reg; ++ mutex_unlock(&priv->mutex); + +- reg = readl(flow->base + DP_COM_CONF); +- reg |= DP_COM_CONF_FG_EN; +- writel(reg, flow->base + DP_COM_CONF); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ipu_dp_enable); + +- ipu_srm_dp_sync_update(priv->ipu); +- } ++int ipu_dp_enable_channel(struct ipu_dp *dp) ++{ ++ struct ipu_flow *flow = to_flow(dp); ++ struct ipu_dp_priv *priv = flow->priv; ++ u32 reg; ++ ++ if (!dp->foreground) ++ return 0; ++ ++ mutex_lock(&priv->mutex); ++ ++ reg = readl(flow->base + DP_COM_CONF); ++ reg |= DP_COM_CONF_FG_EN; ++ writel(reg, flow->base + DP_COM_CONF); ++ ++ ipu_srm_dp_sync_update(priv->ipu); + + mutex_unlock(&priv->mutex); + +@@ -247,25 +259,38 @@ void ipu_dp_disable_channel(struct ipu_dp *dp) + { + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; ++ u32 reg, csc; ++ ++ if (!dp->foreground) ++ return; + + mutex_lock(&priv->mutex); + +- priv->use_count--; ++ reg = readl(flow->base + DP_COM_CONF); ++ csc = reg & DP_COM_CONF_CSC_DEF_MASK; ++ if (csc == DP_COM_CONF_CSC_DEF_FG) ++ reg &= ~DP_COM_CONF_CSC_DEF_MASK; + +- if (dp->foreground) { +- u32 reg, csc; ++ reg &= ~DP_COM_CONF_FG_EN; ++ writel(reg, flow->base + DP_COM_CONF); + +- reg = readl(flow->base + DP_COM_CONF); +- csc = reg & DP_COM_CONF_CSC_DEF_MASK; +- if (csc == DP_COM_CONF_CSC_DEF_FG) +- reg &= ~DP_COM_CONF_CSC_DEF_MASK; ++ writel(0, flow->base + DP_FG_POS); ++ ipu_srm_dp_sync_update(priv->ipu); + +- reg &= ~DP_COM_CONF_FG_EN; +- writel(reg, flow->base + DP_COM_CONF); ++ if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC)) ++ ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50); + +- writel(0, flow->base + DP_FG_POS); +- ipu_srm_dp_sync_update(priv->ipu); +- } ++ mutex_unlock(&priv->mutex); ++} ++EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); ++ ++void ipu_dp_disable(struct ipu_soc *ipu) ++{ ++ struct ipu_dp_priv *priv = ipu->dp_priv; ++ ++ mutex_lock(&priv->mutex); ++ ++ priv->use_count--; + + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DP_EN); +@@ -275,7 +300,7 @@ void ipu_dp_disable_channel(struct ipu_dp *dp) + + mutex_unlock(&priv->mutex); + } +-EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); ++EXPORT_SYMBOL_GPL(ipu_dp_disable); + + struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow) + { +diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h +index 4df00501adc2..bfc1b3366488 100644 +--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h ++++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h +@@ -185,6 +185,9 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu); + int ipu_module_enable(struct ipu_soc *ipu, u32 mask); + int ipu_module_disable(struct ipu_soc *ipu, u32 mask); + ++bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); ++int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); ++ + int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, + unsigned long base, u32 module, struct clk *ipu_clk); + void ipu_di_exit(struct ipu_soc *ipu, int id); +diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c +index c48f640db006..47bec5e17358 100644 +--- a/drivers/staging/imx-drm/ipuv3-crtc.c ++++ b/drivers/staging/imx-drm/ipuv3-crtc.c +@@ -60,24 +60,32 @@ struct ipu_crtc { + + static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) + { ++ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); ++ + if (ipu_crtc->enabled) + return; + +- ipu_di_enable(ipu_crtc->di); +- ipu_dc_enable_channel(ipu_crtc->dc); ++ ipu_dc_enable(ipu); + ipu_plane_enable(ipu_crtc->plane[0]); ++ /* Start DC channel and DI after IDMAC */ ++ ipu_dc_enable_channel(ipu_crtc->dc); ++ ipu_di_enable(ipu_crtc->di); + + ipu_crtc->enabled = 1; + } + + static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) + { ++ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); ++ + if (!ipu_crtc->enabled) + return; + +- ipu_plane_disable(ipu_crtc->plane[0]); ++ /* Stop DC channel and DI before IDMAC */ + ipu_dc_disable_channel(ipu_crtc->dc); + ipu_di_disable(ipu_crtc->di); ++ ipu_plane_disable(ipu_crtc->plane[0]); ++ ipu_dc_disable(ipu); + + ipu_crtc->enabled = 0; + } +@@ -158,7 +166,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, + sig_cfg.Vsync_pol = 1; + + sig_cfg.enable_pol = 1; +- sig_cfg.clk_pol = 1; ++ sig_cfg.clk_pol = 0; + sig_cfg.width = mode->hdisplay; + sig_cfg.height = mode->vdisplay; + sig_cfg.pixel_fmt = out_pixel_fmt; +diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c +index 27a8d735dae0..5697e59ddf1d 100644 +--- a/drivers/staging/imx-drm/ipuv3-plane.c ++++ b/drivers/staging/imx-drm/ipuv3-plane.c +@@ -239,6 +239,8 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane) + + void ipu_plane_enable(struct ipu_plane *ipu_plane) + { ++ if (ipu_plane->dp) ++ ipu_dp_enable(ipu_plane->ipu); + ipu_dmfc_enable_channel(ipu_plane->dmfc); + ipu_idmac_enable_channel(ipu_plane->ipu_ch); + if (ipu_plane->dp) +@@ -257,6 +259,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane) + ipu_dp_disable_channel(ipu_plane->dp); + ipu_idmac_disable_channel(ipu_plane->ipu_ch); + ipu_dmfc_disable_channel(ipu_plane->dmfc); ++ if (ipu_plane->dp) ++ ipu_dp_disable(ipu_plane->ipu); + } + + static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode) +diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c +index c60b6c645f42..01b7ce50fc30 100644 +--- a/drivers/staging/imx-drm/parallel-display.c ++++ b/drivers/staging/imx-drm/parallel-display.c +@@ -219,6 +219,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) + imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; + else if (!strcmp(fmt, "bgr666")) + imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; ++ else if (!strcmp(fmt, "rgb666")) ++ imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB666; + } + + panel_node = of_parse_phandle(np, "fsl,panel", 0); +diff --git a/include/linux/cec-dev.h b/include/linux/cec-dev.h +new file mode 100644 +index 000000000000..76a7d7f6a72d +--- /dev/null ++++ b/include/linux/cec-dev.h +@@ -0,0 +1,69 @@ ++#ifndef _LINUX_CEC_DEV_H ++#define _LINUX_CEC_DEV_H ++ ++#include <linux/cdev.h> ++#include <linux/list.h> ++#include <linux/mutex.h> ++#include <linux/spinlock.h> ++#include <linux/wait.h> ++ ++#include <uapi/linux/cec-dev.h> ++ ++struct device; ++ ++struct cec_dev { ++ struct cdev cdev; ++ dev_t devn; ++ ++ struct mutex mutex; ++ unsigned users; ++ ++ spinlock_t lock; ++ wait_queue_head_t waitq; ++ struct list_head events; ++ u8 write_busy; ++ ++ u8 retries; ++ u16 addresses; ++ u16 physical; ++ ++ int (*open)(struct cec_dev *); ++ void (*release)(struct cec_dev *); ++ void (*send_message)(struct cec_dev *, u8 *, size_t); ++ void (*set_address)(struct cec_dev *, unsigned); ++}; ++ ++void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len); ++ ++static inline void cec_dev_receive(struct cec_dev *cec_dev, u8 *msg, ++ unsigned len) ++{ ++ cec_dev_event(cec_dev, MESSAGE_TYPE_RECEIVE_SUCCESS, msg, len); ++} ++ ++static inline void cec_dev_send_complete(struct cec_dev *cec_dev, int ack) ++{ ++ cec_dev->retries = 0; ++ cec_dev->write_busy = 0; ++ ++ cec_dev_event(cec_dev, ack ? MESSAGE_TYPE_SEND_SUCCESS : ++ MESSAGE_TYPE_NOACK, NULL, 0); ++} ++ ++static inline void cec_dev_disconnect(struct cec_dev *cec_dev) ++{ ++ cec_dev->physical = 0; ++ cec_dev_event(cec_dev, MESSAGE_TYPE_DISCONNECTED, NULL, 0); ++} ++ ++static inline void cec_dev_connect(struct cec_dev *cec_dev, u32 phys) ++{ ++ cec_dev->physical = phys; ++ cec_dev_event(cec_dev, MESSAGE_TYPE_CONNECTED, NULL, 0); ++} ++ ++void cec_dev_init(struct cec_dev *cec_dev, struct module *); ++int cec_dev_add(struct cec_dev *cec_dev, struct device *, const char *name); ++void cec_dev_remove(struct cec_dev *cec_dev); ++ ++#endif +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index cb61ea4d6945..2fdfe30295d5 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -278,6 +278,7 @@ struct mmc_host { + #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ + MMC_CAP2_PACKED_WR) + #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ ++#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 15) + + mmc_pm_flag_t pm_caps; /* supported pm features */ + +@@ -293,6 +294,11 @@ struct mmc_host { + unsigned long clkgate_delay; + #endif + ++ /* card specific properties to deal with power and reset */ ++ struct regulator *card_regulator; /* External VCC needed by the card */ ++ struct gpio_desc *card_reset_gpios[2]; /* External resets, active low */ ++ struct clk *card_clk; /* External clock needed by the card */ ++ + /* host specific block data */ + unsigned int max_seg_size; /* see blk_queue_max_segment_size */ + unsigned short max_segs; /* see blk_queue_max_segments */ +@@ -391,6 +397,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) + wake_up_process(host->sdio_irq_thread); + } + ++void sdio_run_irqs(struct mmc_host *host); ++ + #ifdef CONFIG_REGULATOR + int mmc_regulator_get_ocrmask(struct regulator *supply); + int mmc_regulator_set_ocr(struct mmc_host *mmc, +diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h +index 7be12b883485..08abe9941884 100644 +--- a/include/linux/mmc/sdhci.h ++++ b/include/linux/mmc/sdhci.h +@@ -57,12 +57,8 @@ struct sdhci_host { + #define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) + /* Controller reports inverted write-protect state */ + #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) +-/* Controller has nonstandard clock management */ +-#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17) + /* Controller does not like fast PIO transfers */ + #define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) +-/* Controller losing signal/interrupt enable states after reset */ +-#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19) + /* Controller has to be forced to use block size of 2048 bytes */ + #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) + /* Controller cannot do multi-block transfers */ +@@ -147,6 +143,7 @@ struct sdhci_host { + + bool runtime_suspended; /* Host is runtime suspended */ + bool bus_on; /* Bus power prevents runtime suspend */ ++ bool preset_enabled; /* Preset is enabled */ + + struct mmc_request *mrq; /* Current request */ + struct mmc_command *cmd; /* Current command */ +@@ -164,8 +161,7 @@ struct sdhci_host { + dma_addr_t adma_addr; /* Mapped ADMA descr. table */ + dma_addr_t align_addr; /* Mapped bounce buffer */ + +- struct tasklet_struct card_tasklet; /* Tasklet structures */ +- struct tasklet_struct finish_tasklet; ++ struct tasklet_struct finish_tasklet; /* Tasklet structures */ + + struct timer_list timer; /* Timer for timeouts */ + +@@ -177,6 +173,13 @@ struct sdhci_host { + unsigned int ocr_avail_mmc; + u32 ocr_mask; /* available voltages */ + ++ unsigned timing; /* Current timing */ ++ ++ u32 thread_isr; ++ ++ /* cached registers */ ++ u32 ier; ++ + wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ + unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ + +diff --git a/include/uapi/linux/cec-dev.h b/include/uapi/linux/cec-dev.h +new file mode 100644 +index 000000000000..fb7a41704c77 +--- /dev/null ++++ b/include/uapi/linux/cec-dev.h +@@ -0,0 +1,34 @@ ++#ifndef _UAPI_LINUX_CEC_DEV_H ++#define _UAPI_LINUX_CEC_DEV_H ++ ++#include <linux/ioctl.h> ++#include <linux/types.h> ++ ++#define MAX_MESSAGE_LEN 16 ++ ++enum { ++ HDMICEC_IOC_MAGIC = 'H', ++ /* This is wrong: we pass the argument as a number, not a pointer */ ++ HDMICEC_IOC_O_SETLOGICALADDRESS = _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char), ++ HDMICEC_IOC_SETLOGICALADDRESS = _IO(HDMICEC_IOC_MAGIC, 1), ++ HDMICEC_IOC_STARTDEVICE = _IO(HDMICEC_IOC_MAGIC, 2), ++ HDMICEC_IOC_STOPDEVICE = _IO(HDMICEC_IOC_MAGIC, 3), ++ HDMICEC_IOC_GETPHYADDRESS = _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]), ++}; ++ ++enum { ++ MESSAGE_TYPE_RECEIVE_SUCCESS = 1, ++ MESSAGE_TYPE_NOACK, ++ MESSAGE_TYPE_DISCONNECTED, ++ MESSAGE_TYPE_CONNECTED, ++ MESSAGE_TYPE_SEND_SUCCESS, ++ MESSAGE_TYPE_SEND_ERROR, ++}; ++ ++struct cec_user_event { ++ __u32 event_type; ++ __u32 msg_len; ++ __u8 msg[MAX_MESSAGE_LEN]; ++}; ++ ++#endif +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index ea468ee8fe21..d5d818a86676 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -299,6 +299,7 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ + #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ + #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ ++#define V4L2_PIX_FMT_RGB666 v4l2_fourcc('R', 'G', 'B', 'H') /* 18 RGB-6-6-6 */ + #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ + #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ + #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ +diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c +index 2585ae44e634..a86d84854c7f 100644 +--- a/sound/soc/fsl/imx-pcm-dma.c ++++ b/sound/soc/fsl/imx-pcm-dma.c +@@ -44,7 +44,7 @@ static const struct snd_pcm_hardware imx_pcm_hardware = { + .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = 65535, /* Limited by SDMA engine */ +- .periods_min = 2, ++ .periods_min = 4, + .periods_max = 255, + .fifo_size = 0, + }; diff --git a/target/arm/cubox-i/patches/3.15-rc7/sdma-firmware-cubox-i.patch b/target/arm/cubox-i/patches/3.15/sdma-firmware-cubox-i.patch index 13f94a208..13f94a208 100644 --- a/target/arm/cubox-i/patches/3.15-rc7/sdma-firmware-cubox-i.patch +++ b/target/arm/cubox-i/patches/3.15/sdma-firmware-cubox-i.patch |