From a594f0396e24e51b70795514cc359e3de4982032 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Fri, 5 Dec 2014 22:58:47 -0600 Subject: bump kernel to 3.17.4 --- target/arm/solidrun-imx6/patches/3.16.6/rmk.patch | 7601 --------------------- target/arm/solidrun-imx6/patches/3.17.4/rmk.patch | 7601 +++++++++++++++++++++ 2 files changed, 7601 insertions(+), 7601 deletions(-) delete mode 100644 target/arm/solidrun-imx6/patches/3.16.6/rmk.patch create mode 100644 target/arm/solidrun-imx6/patches/3.17.4/rmk.patch (limited to 'target/arm/solidrun-imx6/patches') diff --git a/target/arm/solidrun-imx6/patches/3.16.6/rmk.patch b/target/arm/solidrun-imx6/patches/3.16.6/rmk.patch deleted file mode 100644 index a0e0e7495..000000000 --- a/target/arm/solidrun-imx6/patches/3.16.6/rmk.patch +++ /dev/null @@ -1,7601 +0,0 @@ -diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts linux-3.16.6/arch/arm/boot/dts/imx6dl-hummingboard.dts ---- linux-3.16.6.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-10-23 12:37:45.114220003 -0500 -@@ -56,15 +56,32 @@ - }; - }; - -+ sound-sgtl5000 { -+ audio-codec = <&sgtl5000>; -+ audio-routing = -+ "MIC_IN", "Mic Jack", -+ "Mic Jack", "Mic Bias", -+ "Headphone Jack", "HP_OUT"; -+ compatible = "fsl,imx-audio-sgtl5000"; -+ model = "On-board Codec"; -+ mux-ext-port = <5>; -+ mux-int-port = <1>; -+ ssi-controller = <&ssi1>; -+ }; -+ - sound-spdif { - compatible = "fsl,imx-audio-spdif"; -- model = "imx-spdif"; -+ model = "On-board SPDIF"; - /* IMX6 doesn't implement this yet */ - spdif-controller = <&spdif>; - spdif-out; - }; - }; - -+&audmux { -+ status = "okay"; -+}; -+ - &can1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hummingboard_flexcan1>; -@@ -81,16 +98,24 @@ - &i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hummingboard_i2c1>; -- -- /* -- * Not fitted on Carrier-1 board... yet - status = "okay"; - -+ /* Pro model */ - rtc: pcf8523@68 { - compatible = "nxp,pcf8523"; - reg = <0x68>; - }; -- */ -+ -+ /* Pro model */ -+ sgtl5000: sgtl5000@0a { -+ clocks = <&clks 201>; -+ compatible = "fsl,sgtl5000"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>; -+ reg = <0x0a>; -+ VDDA-supply = <®_3p3v>; -+ VDDIO-supply = <®_3p3v>; -+ }; - }; - - &i2c2 { -@@ -135,6 +160,16 @@ - >; - }; - -+ pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000 { -+ fsl,pins = < -+ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 /*brk*/ -+ MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 /*ok*/ -+ MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 /*brk*/ -+ MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 /*ok*/ -+ MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 -+ >; -+ }; -+ - pinctrl_hummingboard_spdif: hummingboard-spdif { - fsl,pins = ; - }; -@@ -180,12 +215,19 @@ - status = "okay"; - }; - -+&ssi1 { -+ fsl,mode = "i2s-slave"; -+ status = "okay"; -+}; -+ - &usbh1 { -+ disable-over-current; - vbus-supply = <®_usbh1_vbus>; - status = "okay"; - }; - - &usbotg { -+ disable-over-current; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hummingboard_usbotg_id>; - vbus-supply = <®_usbotg_vbus>; -diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6q-cubox-i.dts linux-3.16.6/arch/arm/boot/dts/imx6q-cubox-i.dts ---- linux-3.16.6.orig/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-10-23 12:26:42.106220014 -0500 -@@ -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.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi ---- linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-10-23 12:34:41.266219992 -0500 -@@ -61,7 +61,7 @@ - - sound-spdif { - compatible = "fsl,imx-audio-spdif"; -- model = "imx-spdif"; -+ model = "Integrated SPDIF"; - /* IMX6 doesn't implement this yet */ - spdif-controller = <&spdif>; - spdif-out; -@@ -130,16 +130,23 @@ - fsl,pins = ; - }; - -+ pinctrl_cubox_i_usbh1: cubox-i-usbh1 { -+ fsl,pins = ; -+ }; -+ - pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus { - fsl,pins = ; - }; - -- pinctrl_cubox_i_usbotg_id: cubox-i-usbotg-id { -+ pinctrl_cubox_i_usbotg: cubox-i-usbotg { - /* -- * The Cubox-i pulls this low, but as it's pointless -+ * The Cubox-i pulls ID low, but as it's pointless - * leaving it as a pull-up, even if it is just 10uA. - */ -- fsl,pins = ; -+ fsl,pins = < -+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 -+ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 -+ >; - }; - - pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus { -@@ -163,6 +170,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 -+ >; -+ }; - }; - }; - -@@ -173,20 +202,24 @@ - }; - - &usbh1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_usbh1>; - vbus-supply = <®_usbh1_vbus>; - status = "okay"; - }; - - &usbotg { - pinctrl-names = "default"; -- pinctrl-0 = <&pinctrl_cubox_i_usbotg_id>; -+ pinctrl-0 = <&pinctrl_cubox_i_usbotg>; - vbus-supply = <®_usbotg_vbus>; - 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.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig ---- linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig 2014-10-23 12:27:10.986220036 -0500 -@@ -0,0 +1,202 @@ -+/* -+ * Copyright (C) 2014 Russell King -+ */ -+#include "imx6qdl-microsom.dtsi" -+#include "imx6qdl-microsom-ar8035.dtsi" -+ -+/ { -+ ir_recv: ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio3 9 1>; -+ pinctrl-names = "default"; -+ 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"; -+ -+ reg_3p3v: 3p3v { -+ compatible = "regulator-fixed"; -+ regulator-name = "3P3V"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ }; -+ -+ reg_usbh1_vbus: usb-h1-vbus { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio1 0 0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>; -+ regulator-name = "usb_h1_vbus"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ reg_usbotg_vbus: usb-otg-vbus { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio3 22 0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>; -+ regulator-name = "usb_otg_vbus"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ }; -+ -+ sound-spdif { -+ compatible = "fsl,imx-audio-spdif"; -+ model = "Integrated SPDIF"; -+ /* IMX6 doesn't implement this yet */ -+ spdif-controller = <&spdif>; -+ spdif-out; -+ }; -+}; -+ -+&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>; -+ -+ status = "okay"; -+ -+ rtc: pcf8523@68 { -+ compatible = "nxp,pcf8523"; -+ reg = <0x68>; -+ }; -+}; -+ -+&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 -+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 -+ >; -+ }; -+ -+ pinctrl_cubox_i_ir: cubox-i-ir { -+ fsl,pins = < -+ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 -+ >; -+ }; -+ -+ pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led { -+ fsl,pins = ; -+ }; -+ -+ pinctrl_cubox_i_spdif: cubox-i-spdif { -+ fsl,pins = ; -+ }; -+ -+ pinctrl_cubox_i_usbh1: cubox-i-usbh1 { -+ fsl,pins = ; -+ }; -+ -+ pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus { -+ fsl,pins = ; -+ }; -+ -+ pinctrl_cubox_i_usbotg: cubox-i-usbotg { -+ /* -+ * The Cubox-i pulls ID low, but as it's pointless -+ * leaving it as a pull-up, even if it is just 10uA. -+ */ -+ fsl,pins = < -+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 -+ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 -+ >; -+ }; -+ -+ pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus { -+ fsl,pins = ; -+ }; -+ -+ pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux { -+ fsl,pins = < -+ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 -+ MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 -+ >; -+ }; -+ -+ pinctrl_cubox_i_usdhc2: cubox-i-usdhc2 { -+ fsl,pins = < -+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 -+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 -+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 -+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 -+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 -+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 -+ >; -+ }; -+ }; -+}; -+ -+&spdif { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_spdif>; -+ status = "okay"; -+}; -+ -+&usbh1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_usbh1>; -+ vbus-supply = <®_usbh1_vbus>; -+ status = "okay"; -+}; -+ -+&usbotg { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_usbotg>; -+ vbus-supply = <®_usbotg_vbus>; -+ status = "okay"; -+}; -+ -+&usdhc2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; -+ vmmc-supply = <®_3p3v>; -+ cd-gpios = <&gpio1 4 0>; -+ status = "okay"; -+}; -diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-3.16.6/arch/arm/boot/dts/imx6qdl-microsom.dtsi ---- linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-10-23 12:34:48.394220240 -0500 -@@ -1,15 +1,95 @@ - /* - * Copyright (C) 2013,2014 Russell King - */ -+#include -+/ { -+ 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_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_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_uart1: microsom-uart1 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; -+ -+ 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_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 -+ >; -+ }; - }; - }; - -@@ -18,3 +98,23 @@ - pinctrl-0 = <&pinctrl_microsom_uart1>; - 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; -+ status = "okay"; -+}; -+ -+/* 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>; -+ status = "okay"; -+}; -diff -Nur linux-3.16.6.orig/arch/arm/mach-imx/clk-imx6q.c linux-3.16.6/arch/arm/mach-imx/clk-imx6q.c ---- linux-3.16.6.orig/arch/arm/mach-imx/clk-imx6q.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/arch/arm/mach-imx/clk-imx6q.c 2014-10-23 12:36:09.214219998 -0500 -@@ -461,6 +461,9 @@ - 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]); -+ - /* - * The gpmi needs 100MHz frequency in the EDO/Sync mode, - * We can not get the 100MHz from the pll2_pfd0_352m. -diff -Nur linux-3.16.6.orig/arch/arm/mach-imx/clk-pllv3.c linux-3.16.6/arch/arm/mach-imx/clk-pllv3.c ---- linux-3.16.6.orig/arch/arm/mach-imx/clk-pllv3.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/arch/arm/mach-imx/clk-pllv3.c 2014-10-23 12:36:01.390219997 -0500 -@@ -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.16.6.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt linux-3.16.6/Documentation/devicetree/bindings/ata/ahci-platform.txt ---- linux-3.16.6.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/Documentation/devicetree/bindings/ata/ahci-platform.txt 2014-10-23 12:15:35.154220017 -0500 -@@ -6,8 +6,6 @@ - Required properties: - - compatible : compatible string, one of: - - "allwinner,sun4i-a10-ahci" -- - "fsl,imx53-ahci" -- - "fsl,imx6q-ahci" - - "hisilicon,hisi-ahci" - - "ibm,476gtr-ahci" - - "marvell,armada-380-ahci" -@@ -22,10 +20,6 @@ - - clocks : a list of phandle + clock specifier pairs - - target-supply : regulator for SATA target power - --"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties: --- clocks : must contain the sata, sata_ref and ahb clocks --- clock-names : must contain "ahb" for the ahb clock -- - Examples: - sata@ffe08000 { - compatible = "snps,spear-ahci"; -diff -Nur linux-3.16.6.orig/Documentation/devicetree/bindings/ata/imx-sata.txt linux-3.16.6/Documentation/devicetree/bindings/ata/imx-sata.txt ---- linux-3.16.6.orig/Documentation/devicetree/bindings/ata/imx-sata.txt 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/Documentation/devicetree/bindings/ata/imx-sata.txt 2014-10-23 12:26:27.434219953 -0500 -@@ -0,0 +1,36 @@ -+* Freescale i.MX AHCI SATA Controller -+ -+The Freescale i.MX SATA controller mostly conforms to the AHCI interface -+with some special extensions at integration level. -+ -+Required properties: -+- compatible : should be one of the following: -+ - "fsl,imx53-ahci" for i.MX53 SATA controller -+ - "fsl,imx6q-ahci" for i.MX6Q SATA controller -+- interrupts : interrupt mapping for SATA IRQ -+- reg : registers mapping -+- clocks : list of clock specifiers, must contain an entry for each -+ required entry in clock-names -+- clock-names : should include "sata", "sata_ref" and "ahb" entries -+ -+Optional properties: -+- fsl,transmit-level-mV : transmit voltage level, in millivolts. -+- fsl,transmit-boost-mdB : transmit boost level, in milli-decibels -+- fsl,transmit-atten-16ths : transmit attenuation, in 16ths -+- fsl,receive-eq-mdB : receive equalisation, in milli-decibels -+ Please refer to the technical documentation or the driver source code -+ for the list of legal values for these options. -+- fsl,no-spread-spectrum : disable spread-spectrum clocking on the SATA -+ link. -+ -+Examples: -+ -+sata@02200000 { -+ compatible = "fsl,imx6q-ahci"; -+ reg = <0x02200000 0x4000>; -+ interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&clks IMX6QDL_CLK_SATA>, -+ <&clks IMX6QDL_CLK_SATA_REF_100M>, -+ <&clks IMX6QDL_CLK_AHB>; -+ clock-names = "sata", "sata_ref", "ahb"; -+}; -diff -Nur linux-3.16.6.orig/Documentation/devicetree/bindings/mmc/mmc.txt linux-3.16.6/Documentation/devicetree/bindings/mmc/mmc.txt ---- linux-3.16.6.orig/Documentation/devicetree/bindings/mmc/mmc.txt 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/Documentation/devicetree/bindings/mmc/mmc.txt 2014-10-23 12:34:18.694220003 -0500 -@@ -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. -@@ -41,6 +43,15 @@ - - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported - - mmc-hs400-1_2v: eMMC HS400 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.16.6.orig/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt linux-3.16.6/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt ---- linux-3.16.6.orig/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt 2014-10-23 12:35:30.946219998 -0500 -@@ -60,8 +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" -- and "lvds666". -+ display interface. Currently supported types: "rgb24", "rgb565", "bgr666", -+ "rgb666" and "lvds666". - - edid: verbatim EDID data block describing attached display. - - ddc: phandle describing the i2c bus handling the display data - channel -diff -Nur linux-3.16.6.orig/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml linux-3.16.6/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml ---- linux-3.16.6.orig/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml 2014-10-23 12:35:23.678220004 -0500 -@@ -279,6 +279,45 @@ - - - -+ -+ V4L2_PIX_FMT_RGB666 -+ 'RGBH' -+ -+ r5 -+ r4 -+ r3 -+ r2 -+ r1 -+ r0 -+ g5 -+ g4 -+ -+ g3 -+ g2 -+ g1 -+ g0 -+ b5 -+ b4 -+ b3 -+ b2 -+ -+ b1 -+ b0 -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - V4L2_PIX_FMT_BGR24 - 'BGR3' -diff -Nur linux-3.16.6.orig/drivers/ata/ahci_imx.c linux-3.16.6/drivers/ata/ahci_imx.c ---- linux-3.16.6.orig/drivers/ata/ahci_imx.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/ata/ahci_imx.c 2014-10-23 12:26:19.770220044 -0500 -@@ -64,6 +64,7 @@ - struct regmap *gpr; - bool no_device; - bool first_time; -+ u32 phy_params; - }; - - static int ahci_imx_hotplug; -@@ -248,14 +249,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); -@@ -369,6 +363,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 }, -+ { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, -+ { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, -+ { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, -+ { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, -+ { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, -+ { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, -+ { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, -+ { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, -+ { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, -+ { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, -+ { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, -+ { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, -+ { 5750, 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; -@@ -410,6 +563,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)) { -@@ -417,6 +572,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.16.6.orig/drivers/ata/ahci_imx.c.orig linux-3.16.6/drivers/ata/ahci_imx.c.orig ---- linux-3.16.6.orig/drivers/ata/ahci_imx.c.orig 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/ata/ahci_imx.c.orig 2014-10-23 12:18:59.602219672 -0500 -@@ -0,0 +1,679 @@ -+/* -+ * copyright (c) 2013 Freescale Semiconductor, Inc. -+ * Freescale IMX AHCI SATA platform driver -+ * -+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ahci.h" -+ -+enum { -+ /* Timer 1-ms Register */ -+ IMX_TIMER1MS = 0x00e0, -+ /* Port0 PHY Control Register */ -+ IMX_P0PHYCR = 0x0178, -+ IMX_P0PHYCR_TEST_PDDQ = 1 << 20, -+ IMX_P0PHYCR_CR_READ = 1 << 19, -+ IMX_P0PHYCR_CR_WRITE = 1 << 18, -+ IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, -+ IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, -+ /* Port0 PHY Status Register */ -+ IMX_P0PHYSR = 0x017c, -+ IMX_P0PHYSR_CR_ACK = 1 << 18, -+ IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, -+ /* Lane0 Output Status Register */ -+ IMX_LANE0_OUT_STAT = 0x2003, -+ IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, -+ /* Clock Reset Register */ -+ IMX_CLOCK_RESET = 0x7f3f, -+ IMX_CLOCK_RESET_RESET = 1 << 0, -+}; -+ -+enum ahci_imx_type { -+ AHCI_IMX53, -+ AHCI_IMX6Q, -+}; -+ -+struct imx_ahci_priv { -+ struct platform_device *ahci_pdev; -+ enum ahci_imx_type type; -+ struct clk *sata_clk; -+ struct clk *sata_ref_clk; -+ struct clk *ahb_clk; -+ struct regmap *gpr; -+ bool no_device; -+ bool first_time; -+ u32 phy_params; -+}; -+ -+static int ahci_imx_hotplug; -+module_param_named(hotplug, ahci_imx_hotplug, int, 0644); -+MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); -+ -+static void ahci_imx_host_stop(struct ata_host *host); -+ -+static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) -+{ -+ int timeout = 10; -+ u32 crval; -+ u32 srval; -+ -+ /* Assert or deassert the bit */ -+ crval = readl(mmio + IMX_P0PHYCR); -+ if (assert) -+ crval |= bit; -+ else -+ crval &= ~bit; -+ writel(crval, mmio + IMX_P0PHYCR); -+ -+ /* Wait for the cr_ack signal */ -+ do { -+ srval = readl(mmio + IMX_P0PHYSR); -+ if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) -+ break; -+ usleep_range(100, 200); -+ } while (--timeout); -+ -+ return timeout ? 0 : -ETIMEDOUT; -+} -+ -+static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) -+{ -+ u32 crval = addr; -+ int ret; -+ -+ /* Supply the address on cr_data_in */ -+ writel(crval, mmio + IMX_P0PHYCR); -+ -+ /* Assert the cr_cap_addr signal */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); -+ if (ret) -+ return ret; -+ -+ /* Deassert cr_cap_addr */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int imx_phy_reg_write(u16 val, void __iomem *mmio) -+{ -+ u32 crval = val; -+ int ret; -+ -+ /* Supply the data on cr_data_in */ -+ writel(crval, mmio + IMX_P0PHYCR); -+ -+ /* Assert the cr_cap_data signal */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); -+ if (ret) -+ return ret; -+ -+ /* Deassert cr_cap_data */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); -+ if (ret) -+ return ret; -+ -+ if (val & IMX_CLOCK_RESET_RESET) { -+ /* -+ * In case we're resetting the phy, it's unable to acknowledge, -+ * so we return immediately here. -+ */ -+ crval |= IMX_P0PHYCR_CR_WRITE; -+ writel(crval, mmio + IMX_P0PHYCR); -+ goto out; -+ } -+ -+ /* Assert the cr_write signal */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); -+ if (ret) -+ return ret; -+ -+ /* Deassert cr_write */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); -+ if (ret) -+ return ret; -+ -+out: -+ return 0; -+} -+ -+static int imx_phy_reg_read(u16 *val, void __iomem *mmio) -+{ -+ int ret; -+ -+ /* Assert the cr_read signal */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); -+ if (ret) -+ return ret; -+ -+ /* Capture the data from cr_data_out[] */ -+ *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; -+ -+ /* Deassert cr_read */ -+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) -+{ -+ void __iomem *mmio = hpriv->mmio; -+ int timeout = 10; -+ u16 val; -+ int ret; -+ -+ /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ -+ ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); -+ if (ret) -+ return ret; -+ ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); -+ if (ret) -+ return ret; -+ -+ /* Wait for PHY RX_PLL to be stable */ -+ do { -+ usleep_range(100, 200); -+ ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); -+ if (ret) -+ return ret; -+ ret = imx_phy_reg_read(&val, mmio); -+ if (ret) -+ return ret; -+ if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) -+ break; -+ } while (--timeout); -+ -+ return timeout ? 0 : -ETIMEDOUT; -+} -+ -+static int imx_sata_enable(struct ahci_host_priv *hpriv) -+{ -+ struct imx_ahci_priv *imxpriv = hpriv->plat_data; -+ struct device *dev = &imxpriv->ahci_pdev->dev; -+ int ret; -+ -+ if (imxpriv->no_device) -+ return 0; -+ -+ if (hpriv->target_pwr) { -+ ret = regulator_enable(hpriv->target_pwr); -+ if (ret) -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(imxpriv->sata_ref_clk); -+ if (ret < 0) -+ goto disable_regulator; -+ -+ if (imxpriv->type == AHCI_IMX6Q) { -+ /* -+ * set PHY Paremeters, two steps to configure the GPR13, -+ * one write for rest of parameters, mask of first write -+ * is 0x07ffffff, and the other one write for setting -+ * the mpll_clk_en. -+ */ -+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, -+ IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | -+ IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | -+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | -+ IMX6Q_GPR13_SATA_SPD_MODE_MASK | -+ IMX6Q_GPR13_SATA_MPLL_SS_EN | -+ IMX6Q_GPR13_SATA_TX_ATTEN_MASK | -+ IMX6Q_GPR13_SATA_TX_BOOST_MASK | -+ IMX6Q_GPR13_SATA_TX_LVL_MASK | -+ IMX6Q_GPR13_SATA_MPLL_CLK_EN | -+ IMX6Q_GPR13_SATA_TX_EDGE_RATE, -+ imxpriv->phy_params); -+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, -+ IMX6Q_GPR13_SATA_MPLL_CLK_EN, -+ IMX6Q_GPR13_SATA_MPLL_CLK_EN); -+ -+ usleep_range(100, 200); -+ -+ ret = imx_sata_phy_reset(hpriv); -+ if (ret) { -+ dev_err(dev, "failed to reset phy: %d\n", ret); -+ goto disable_regulator; -+ } -+ } -+ -+ usleep_range(1000, 2000); -+ -+ return 0; -+ -+disable_regulator: -+ if (hpriv->target_pwr) -+ regulator_disable(hpriv->target_pwr); -+ -+ return ret; -+} -+ -+static void imx_sata_disable(struct ahci_host_priv *hpriv) -+{ -+ struct imx_ahci_priv *imxpriv = hpriv->plat_data; -+ -+ if (imxpriv->no_device) -+ return; -+ -+ if (imxpriv->type == AHCI_IMX6Q) { -+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, -+ IMX6Q_GPR13_SATA_MPLL_CLK_EN, -+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN); -+ } -+ -+ clk_disable_unprepare(imxpriv->sata_ref_clk); -+ -+ if (hpriv->target_pwr) -+ regulator_disable(hpriv->target_pwr); -+} -+ -+static void ahci_imx_error_handler(struct ata_port *ap) -+{ -+ u32 reg_val; -+ struct ata_device *dev; -+ struct ata_host *host = dev_get_drvdata(ap->dev); -+ struct ahci_host_priv *hpriv = host->private_data; -+ void __iomem *mmio = hpriv->mmio; -+ struct imx_ahci_priv *imxpriv = hpriv->plat_data; -+ -+ ahci_error_handler(ap); -+ -+ if (!(imxpriv->first_time) || ahci_imx_hotplug) -+ return; -+ -+ imxpriv->first_time = false; -+ -+ ata_for_each_dev(dev, &ap->link, ENABLED) -+ return; -+ /* -+ * Disable link to save power. An imx ahci port can't be recovered -+ * without full reset once the pddq mode is enabled making it -+ * impossible to use as part of libata LPM. -+ */ -+ reg_val = readl(mmio + IMX_P0PHYCR); -+ 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, -+ unsigned long deadline) -+{ -+ struct ata_port *ap = link->ap; -+ struct ata_host *host = dev_get_drvdata(ap->dev); -+ struct ahci_host_priv *hpriv = host->private_data; -+ struct imx_ahci_priv *imxpriv = hpriv->plat_data; -+ int ret = -EIO; -+ -+ if (imxpriv->type == AHCI_IMX53) -+ ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); -+ else if (imxpriv->type == AHCI_IMX6Q) -+ ret = ahci_ops.softreset(link, class, deadline); -+ -+ return ret; -+} -+ -+static struct ata_port_operations ahci_imx_ops = { -+ .inherits = &ahci_ops, -+ .host_stop = ahci_imx_host_stop, -+ .error_handler = ahci_imx_error_handler, -+ .softreset = ahci_imx_softreset, -+}; -+ -+static const struct ata_port_info ahci_imx_port_info = { -+ .flags = AHCI_FLAG_COMMON, -+ .pio_mask = ATA_PIO4, -+ .udma_mask = ATA_UDMA6, -+ .port_ops = &ahci_imx_ops, -+}; -+ -+static const struct of_device_id imx_ahci_of_match[] = { -+ { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, -+ { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, -+ {}, -+}; -+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; -+}; -+ -+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 }, -+ { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, -+ { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, -+ { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, -+ { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, -+ { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, -+ { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, -+ { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, -+ { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, -+ { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, -+ { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, -+ { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, -+ { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, -+ { 5750, 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, -+ }, -+}; -+ -+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 (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; -+ const struct of_device_id *of_id; -+ struct ahci_host_priv *hpriv; -+ struct imx_ahci_priv *imxpriv; -+ unsigned int reg_val; -+ int ret; -+ -+ of_id = of_match_device(imx_ahci_of_match, dev); -+ if (!of_id) -+ return -EINVAL; -+ -+ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); -+ if (!imxpriv) -+ return -ENOMEM; -+ -+ imxpriv->ahci_pdev = pdev; -+ imxpriv->no_device = false; -+ imxpriv->first_time = true; -+ imxpriv->type = (enum ahci_imx_type)of_id->data; -+ -+ imxpriv->sata_clk = devm_clk_get(dev, "sata"); -+ if (IS_ERR(imxpriv->sata_clk)) { -+ dev_err(dev, "can't get sata clock.\n"); -+ return PTR_ERR(imxpriv->sata_clk); -+ } -+ -+ imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); -+ if (IS_ERR(imxpriv->sata_ref_clk)) { -+ dev_err(dev, "can't get sata_ref clock.\n"); -+ return PTR_ERR(imxpriv->sata_ref_clk); -+ } -+ -+ imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); -+ if (IS_ERR(imxpriv->ahb_clk)) { -+ dev_err(dev, "can't get ahb clock.\n"); -+ return PTR_ERR(imxpriv->ahb_clk); -+ } -+ -+ if (imxpriv->type == AHCI_IMX6Q) { -+ u32 reg_value; -+ -+ imxpriv->gpr = syscon_regmap_lookup_by_compatible( -+ "fsl,imx6q-iomuxc-gpr"); -+ if (IS_ERR(imxpriv->gpr)) { -+ dev_err(dev, -+ "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 | -+ IMX6Q_GPR13_SATA_MPLL_SS_EN | -+ reg_value; -+ } -+ -+ hpriv = ahci_platform_get_resources(pdev); -+ if (IS_ERR(hpriv)) -+ return PTR_ERR(hpriv); -+ -+ hpriv->plat_data = imxpriv; -+ -+ ret = clk_prepare_enable(imxpriv->sata_clk); -+ if (ret) -+ return ret; -+ -+ ret = imx_sata_enable(hpriv); -+ if (ret) -+ goto disable_clk; -+ -+ /* -+ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, -+ * and IP vendor specific register IMX_TIMER1MS. -+ * Configure CAP_SSS (support stagered spin up). -+ * Implement the port0. -+ * Get the ahb clock rate, and configure the TIMER1MS register. -+ */ -+ reg_val = readl(hpriv->mmio + HOST_CAP); -+ if (!(reg_val & HOST_CAP_SSS)) { -+ reg_val |= HOST_CAP_SSS; -+ writel(reg_val, hpriv->mmio + HOST_CAP); -+ } -+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL); -+ if (!(reg_val & 0x1)) { -+ reg_val |= 0x1; -+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL); -+ } -+ -+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; -+ writel(reg_val, hpriv->mmio + IMX_TIMER1MS); -+ -+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, -+ 0, 0, 0); -+ if (ret) -+ goto disable_sata; -+ -+ return 0; -+ -+disable_sata: -+ imx_sata_disable(hpriv); -+disable_clk: -+ clk_disable_unprepare(imxpriv->sata_clk); -+ return ret; -+} -+ -+static void ahci_imx_host_stop(struct ata_host *host) -+{ -+ struct ahci_host_priv *hpriv = host->private_data; -+ struct imx_ahci_priv *imxpriv = hpriv->plat_data; -+ -+ imx_sata_disable(hpriv); -+ clk_disable_unprepare(imxpriv->sata_clk); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int imx_ahci_suspend(struct device *dev) -+{ -+ struct ata_host *host = dev_get_drvdata(dev); -+ struct ahci_host_priv *hpriv = host->private_data; -+ int ret; -+ -+ ret = ahci_platform_suspend_host(dev); -+ if (ret) -+ return ret; -+ -+ imx_sata_disable(hpriv); -+ -+ return 0; -+} -+ -+static int imx_ahci_resume(struct device *dev) -+{ -+ struct ata_host *host = dev_get_drvdata(dev); -+ struct ahci_host_priv *hpriv = host->private_data; -+ int ret; -+ -+ ret = imx_sata_enable(hpriv); -+ if (ret) -+ return ret; -+ -+ return ahci_platform_resume_host(dev); -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume); -+ -+static struct platform_driver imx_ahci_driver = { -+ .probe = imx_ahci_probe, -+ .remove = ata_platform_remove_one, -+ .driver = { -+ .name = "ahci-imx", -+ .owner = THIS_MODULE, -+ .of_match_table = imx_ahci_of_match, -+ .pm = &ahci_imx_pm_ops, -+ }, -+}; -+module_platform_driver(imx_ahci_driver); -+ -+MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver"); -+MODULE_AUTHOR("Richard Zhu "); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("ahci:imx"); -diff -Nur linux-3.16.6.orig/drivers/cec/cec-dev.c linux-3.16.6/drivers/cec/cec-dev.c ---- linux-3.16.6.orig/drivers/cec/cec-dev.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/cec/cec-dev.c 2014-10-23 12:37:18.374219998 -0500 -@@ -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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+MODULE_DESCRIPTION("Generic HDMI CEC driver"); -+MODULE_LICENSE("GPL"); -diff -Nur linux-3.16.6.orig/drivers/cec/Kconfig linux-3.16.6/drivers/cec/Kconfig ---- linux-3.16.6.orig/drivers/cec/Kconfig 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/cec/Kconfig 2014-10-23 12:37:18.350220009 -0500 -@@ -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.16.6.orig/drivers/cec/Makefile linux-3.16.6/drivers/cec/Makefile ---- linux-3.16.6.orig/drivers/cec/Makefile 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/cec/Makefile 2014-10-23 12:37:18.374219998 -0500 -@@ -0,0 +1 @@ -+obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o -diff -Nur linux-3.16.6.orig/drivers/dma/imx-sdma.c linux-3.16.6/drivers/dma/imx-sdma.c ---- linux-3.16.6.orig/drivers/dma/imx-sdma.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/dma/imx-sdma.c 2014-10-23 12:35:52.990220019 -0500 -@@ -255,7 +255,6 @@ - enum dma_slave_buswidth word_size; - unsigned int buf_tail; - unsigned int num_bd; -- unsigned int period_len; - struct sdma_buffer_descriptor *bd; - dma_addr_t bd_phys; - unsigned int pc_from_device, pc_to_device; -@@ -594,12 +593,6 @@ - - static void sdma_handle_channel_loop(struct sdma_channel *sdmac) - { -- if (sdmac->desc.callback) -- sdmac->desc.callback(sdmac->desc.callback_param); --} -- --static void sdma_update_channel_loop(struct sdma_channel *sdmac) --{ - struct sdma_buffer_descriptor *bd; - - /* -@@ -618,6 +611,9 @@ - bd->mode.status |= BD_DONE; - sdmac->buf_tail++; - sdmac->buf_tail %= sdmac->num_bd; -+ -+ if (sdmac->desc.callback) -+ sdmac->desc.callback(sdmac->desc.callback_param); - } - } - -@@ -673,9 +669,6 @@ - int channel = fls(stat) - 1; - struct sdma_channel *sdmac = &sdma->channel[channel]; - -- if (sdmac->flags & IMX_DMA_SG_LOOP) -- sdma_update_channel_loop(sdmac); -- - tasklet_schedule(&sdmac->tasklet); - - __clear_bit(channel, &stat); -@@ -1136,7 +1129,6 @@ - sdmac->status = DMA_IN_PROGRESS; - - sdmac->buf_tail = 0; -- sdmac->period_len = period_len; - - sdmac->flags |= IMX_DMA_SG_LOOP; - sdmac->direction = direction; -@@ -1233,15 +1225,9 @@ - struct dma_tx_state *txstate) - { - struct sdma_channel *sdmac = to_sdma_chan(chan); -- u32 residue; -- -- if (sdmac->flags & IMX_DMA_SG_LOOP) -- residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; -- else -- residue = sdmac->chn_count - sdmac->chn_real_count; - - dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, -- residue); -+ sdmac->chn_count - sdmac->chn_real_count); - - return sdmac->status; - } -diff -Nur linux-3.16.6.orig/drivers/dma/imx-sdma.c.orig linux-3.16.6/drivers/dma/imx-sdma.c.orig ---- linux-3.16.6.orig/drivers/dma/imx-sdma.c.orig 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/dma/imx-sdma.c.orig 2014-10-15 05:05:43.000000000 -0500 -@@ -0,0 +1,1656 @@ -+/* -+ * drivers/dma/imx-sdma.c -+ * -+ * This file contains a driver for the Freescale Smart DMA engine -+ * -+ * Copyright 2010 Sascha Hauer, Pengutronix -+ * -+ * Based on code from Freescale: -+ * -+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. -+ * -+ * The code contained herein is licensed under the GNU General Public -+ * License. You may obtain a copy of the GNU General Public License -+ * Version 2 or later at the following locations: -+ * -+ * http://www.opensource.org/licenses/gpl-license.html -+ * http://www.gnu.org/copyleft/gpl.html -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "dmaengine.h" -+ -+/* SDMA registers */ -+#define SDMA_H_C0PTR 0x000 -+#define SDMA_H_INTR 0x004 -+#define SDMA_H_STATSTOP 0x008 -+#define SDMA_H_START 0x00c -+#define SDMA_H_EVTOVR 0x010 -+#define SDMA_H_DSPOVR 0x014 -+#define SDMA_H_HOSTOVR 0x018 -+#define SDMA_H_EVTPEND 0x01c -+#define SDMA_H_DSPENBL 0x020 -+#define SDMA_H_RESET 0x024 -+#define SDMA_H_EVTERR 0x028 -+#define SDMA_H_INTRMSK 0x02c -+#define SDMA_H_PSW 0x030 -+#define SDMA_H_EVTERRDBG 0x034 -+#define SDMA_H_CONFIG 0x038 -+#define SDMA_ONCE_ENB 0x040 -+#define SDMA_ONCE_DATA 0x044 -+#define SDMA_ONCE_INSTR 0x048 -+#define SDMA_ONCE_STAT 0x04c -+#define SDMA_ONCE_CMD 0x050 -+#define SDMA_EVT_MIRROR 0x054 -+#define SDMA_ILLINSTADDR 0x058 -+#define SDMA_CHN0ADDR 0x05c -+#define SDMA_ONCE_RTB 0x060 -+#define SDMA_XTRIG_CONF1 0x070 -+#define SDMA_XTRIG_CONF2 0x074 -+#define SDMA_CHNENBL0_IMX35 0x200 -+#define SDMA_CHNENBL0_IMX31 0x080 -+#define SDMA_CHNPRI_0 0x100 -+ -+/* -+ * Buffer descriptor status values. -+ */ -+#define BD_DONE 0x01 -+#define BD_WRAP 0x02 -+#define BD_CONT 0x04 -+#define BD_INTR 0x08 -+#define BD_RROR 0x10 -+#define BD_LAST 0x20 -+#define BD_EXTD 0x80 -+ -+/* -+ * Data Node descriptor status values. -+ */ -+#define DND_END_OF_FRAME 0x80 -+#define DND_END_OF_XFER 0x40 -+#define DND_DONE 0x20 -+#define DND_UNUSED 0x01 -+ -+/* -+ * IPCV2 descriptor status values. -+ */ -+#define BD_IPCV2_END_OF_FRAME 0x40 -+ -+#define IPCV2_MAX_NODES 50 -+/* -+ * Error bit set in the CCB status field by the SDMA, -+ * in setbd routine, in case of a transfer error -+ */ -+#define DATA_ERROR 0x10000000 -+ -+/* -+ * Buffer descriptor commands. -+ */ -+#define C0_ADDR 0x01 -+#define C0_LOAD 0x02 -+#define C0_DUMP 0x03 -+#define C0_SETCTX 0x07 -+#define C0_GETCTX 0x03 -+#define C0_SETDM 0x01 -+#define C0_SETPM 0x04 -+#define C0_GETDM 0x02 -+#define C0_GETPM 0x08 -+/* -+ * Change endianness indicator in the BD command field -+ */ -+#define CHANGE_ENDIANNESS 0x80 -+ -+/* -+ * Mode/Count of data node descriptors - IPCv2 -+ */ -+struct sdma_mode_count { -+ u32 count : 16; /* size of the buffer pointed by this BD */ -+ u32 status : 8; /* E,R,I,C,W,D status bits stored here */ -+ u32 command : 8; /* command mostlky used for channel 0 */ -+}; -+ -+/* -+ * Buffer descriptor -+ */ -+struct sdma_buffer_descriptor { -+ struct sdma_mode_count mode; -+ u32 buffer_addr; /* address of the buffer described */ -+ u32 ext_buffer_addr; /* extended buffer address */ -+} __attribute__ ((packed)); -+ -+/** -+ * struct sdma_channel_control - Channel control Block -+ * -+ * @current_bd_ptr current buffer descriptor processed -+ * @base_bd_ptr first element of buffer descriptor array -+ * @unused padding. The SDMA engine expects an array of 128 byte -+ * control blocks -+ */ -+struct sdma_channel_control { -+ u32 current_bd_ptr; -+ u32 base_bd_ptr; -+ u32 unused[2]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct sdma_state_registers - SDMA context for a channel -+ * -+ * @pc: program counter -+ * @t: test bit: status of arithmetic & test instruction -+ * @rpc: return program counter -+ * @sf: source fault while loading data -+ * @spc: loop start program counter -+ * @df: destination fault while storing data -+ * @epc: loop end program counter -+ * @lm: loop mode -+ */ -+struct sdma_state_registers { -+ u32 pc :14; -+ u32 unused1: 1; -+ u32 t : 1; -+ u32 rpc :14; -+ u32 unused0: 1; -+ u32 sf : 1; -+ u32 spc :14; -+ u32 unused2: 1; -+ u32 df : 1; -+ u32 epc :14; -+ u32 lm : 2; -+} __attribute__ ((packed)); -+ -+/** -+ * struct sdma_context_data - sdma context specific to a channel -+ * -+ * @channel_state: channel state bits -+ * @gReg: general registers -+ * @mda: burst dma destination address register -+ * @msa: burst dma source address register -+ * @ms: burst dma status register -+ * @md: burst dma data register -+ * @pda: peripheral dma destination address register -+ * @psa: peripheral dma source address register -+ * @ps: peripheral dma status register -+ * @pd: peripheral dma data register -+ * @ca: CRC polynomial register -+ * @cs: CRC accumulator register -+ * @dda: dedicated core destination address register -+ * @dsa: dedicated core source address register -+ * @ds: dedicated core status register -+ * @dd: dedicated core data register -+ */ -+struct sdma_context_data { -+ struct sdma_state_registers channel_state; -+ u32 gReg[8]; -+ u32 mda; -+ u32 msa; -+ u32 ms; -+ u32 md; -+ u32 pda; -+ u32 psa; -+ u32 ps; -+ u32 pd; -+ u32 ca; -+ u32 cs; -+ u32 dda; -+ u32 dsa; -+ u32 ds; -+ u32 dd; -+ u32 scratch0; -+ u32 scratch1; -+ u32 scratch2; -+ u32 scratch3; -+ u32 scratch4; -+ u32 scratch5; -+ u32 scratch6; -+ u32 scratch7; -+} __attribute__ ((packed)); -+ -+#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor)) -+ -+struct sdma_engine; -+ -+/** -+ * struct sdma_channel - housekeeping for a SDMA channel -+ * -+ * @sdma pointer to the SDMA engine for this channel -+ * @channel the channel number, matches dmaengine chan_id + 1 -+ * @direction transfer type. Needed for setting SDMA script -+ * @peripheral_type Peripheral type. Needed for setting SDMA script -+ * @event_id0 aka dma request line -+ * @event_id1 for channels that use 2 events -+ * @word_size peripheral access size -+ * @buf_tail ID of the buffer that was processed -+ * @num_bd max NUM_BD. number of descriptors currently handling -+ */ -+struct sdma_channel { -+ struct sdma_engine *sdma; -+ unsigned int channel; -+ enum dma_transfer_direction direction; -+ enum sdma_peripheral_type peripheral_type; -+ unsigned int event_id0; -+ unsigned int event_id1; -+ enum dma_slave_buswidth word_size; -+ unsigned int buf_tail; -+ unsigned int num_bd; -+ unsigned int period_len; -+ struct sdma_buffer_descriptor *bd; -+ dma_addr_t bd_phys; -+ unsigned int pc_from_device, pc_to_device; -+ unsigned long flags; -+ dma_addr_t per_address; -+ unsigned long event_mask[2]; -+ unsigned long watermark_level; -+ u32 shp_addr, per_addr; -+ struct dma_chan chan; -+ spinlock_t lock; -+ struct dma_async_tx_descriptor desc; -+ enum dma_status status; -+ unsigned int chn_count; -+ unsigned int chn_real_count; -+ struct tasklet_struct tasklet; -+}; -+ -+#define IMX_DMA_SG_LOOP BIT(0) -+ -+#define MAX_DMA_CHANNELS 32 -+#define MXC_SDMA_DEFAULT_PRIORITY 1 -+#define MXC_SDMA_MIN_PRIORITY 1 -+#define MXC_SDMA_MAX_PRIORITY 7 -+ -+#define SDMA_FIRMWARE_MAGIC 0x414d4453 -+ -+/** -+ * struct sdma_firmware_header - Layout of the firmware image -+ * -+ * @magic "SDMA" -+ * @version_major increased whenever layout of struct sdma_script_start_addrs -+ * changes. -+ * @version_minor firmware minor version (for binary compatible changes) -+ * @script_addrs_start offset of struct sdma_script_start_addrs in this image -+ * @num_script_addrs Number of script addresses in this image -+ * @ram_code_start offset of SDMA ram image in this firmware image -+ * @ram_code_size size of SDMA ram image -+ * @script_addrs Stores the start address of the SDMA scripts -+ * (in SDMA memory space) -+ */ -+struct sdma_firmware_header { -+ u32 magic; -+ u32 version_major; -+ u32 version_minor; -+ u32 script_addrs_start; -+ u32 num_script_addrs; -+ u32 ram_code_start; -+ u32 ram_code_size; -+}; -+ -+struct sdma_driver_data { -+ int chnenbl0; -+ int num_events; -+ struct sdma_script_start_addrs *script_addrs; -+}; -+ -+struct sdma_engine { -+ struct device *dev; -+ struct device_dma_parameters dma_parms; -+ struct sdma_channel channel[MAX_DMA_CHANNELS]; -+ struct sdma_channel_control *channel_control; -+ void __iomem *regs; -+ struct sdma_context_data *context; -+ dma_addr_t context_phys; -+ struct dma_device dma_device; -+ struct clk *clk_ipg; -+ struct clk *clk_ahb; -+ spinlock_t channel_0_lock; -+ u32 script_number; -+ struct sdma_script_start_addrs *script_addrs; -+ const struct sdma_driver_data *drvdata; -+}; -+ -+static struct sdma_driver_data sdma_imx31 = { -+ .chnenbl0 = SDMA_CHNENBL0_IMX31, -+ .num_events = 32, -+}; -+ -+static struct sdma_script_start_addrs sdma_script_imx25 = { -+ .ap_2_ap_addr = 729, -+ .uart_2_mcu_addr = 904, -+ .per_2_app_addr = 1255, -+ .mcu_2_app_addr = 834, -+ .uartsh_2_mcu_addr = 1120, -+ .per_2_shp_addr = 1329, -+ .mcu_2_shp_addr = 1048, -+ .ata_2_mcu_addr = 1560, -+ .mcu_2_ata_addr = 1479, -+ .app_2_per_addr = 1189, -+ .app_2_mcu_addr = 770, -+ .shp_2_per_addr = 1407, -+ .shp_2_mcu_addr = 979, -+}; -+ -+static struct sdma_driver_data sdma_imx25 = { -+ .chnenbl0 = SDMA_CHNENBL0_IMX35, -+ .num_events = 48, -+ .script_addrs = &sdma_script_imx25, -+}; -+ -+static struct sdma_driver_data sdma_imx35 = { -+ .chnenbl0 = SDMA_CHNENBL0_IMX35, -+ .num_events = 48, -+}; -+ -+static struct sdma_script_start_addrs sdma_script_imx51 = { -+ .ap_2_ap_addr = 642, -+ .uart_2_mcu_addr = 817, -+ .mcu_2_app_addr = 747, -+ .mcu_2_shp_addr = 961, -+ .ata_2_mcu_addr = 1473, -+ .mcu_2_ata_addr = 1392, -+ .app_2_per_addr = 1033, -+ .app_2_mcu_addr = 683, -+ .shp_2_per_addr = 1251, -+ .shp_2_mcu_addr = 892, -+}; -+ -+static struct sdma_driver_data sdma_imx51 = { -+ .chnenbl0 = SDMA_CHNENBL0_IMX35, -+ .num_events = 48, -+ .script_addrs = &sdma_script_imx51, -+}; -+ -+static struct sdma_script_start_addrs sdma_script_imx53 = { -+ .ap_2_ap_addr = 642, -+ .app_2_mcu_addr = 683, -+ .mcu_2_app_addr = 747, -+ .uart_2_mcu_addr = 817, -+ .shp_2_mcu_addr = 891, -+ .mcu_2_shp_addr = 960, -+ .uartsh_2_mcu_addr = 1032, -+ .spdif_2_mcu_addr = 1100, -+ .mcu_2_spdif_addr = 1134, -+ .firi_2_mcu_addr = 1193, -+ .mcu_2_firi_addr = 1290, -+}; -+ -+static struct sdma_driver_data sdma_imx53 = { -+ .chnenbl0 = SDMA_CHNENBL0_IMX35, -+ .num_events = 48, -+ .script_addrs = &sdma_script_imx53, -+}; -+ -+static struct sdma_script_start_addrs sdma_script_imx6q = { -+ .ap_2_ap_addr = 642, -+ .uart_2_mcu_addr = 817, -+ .mcu_2_app_addr = 747, -+ .per_2_per_addr = 6331, -+ .uartsh_2_mcu_addr = 1032, -+ .mcu_2_shp_addr = 960, -+ .app_2_mcu_addr = 683, -+ .shp_2_mcu_addr = 891, -+ .spdif_2_mcu_addr = 1100, -+ .mcu_2_spdif_addr = 1134, -+}; -+ -+static struct sdma_driver_data sdma_imx6q = { -+ .chnenbl0 = SDMA_CHNENBL0_IMX35, -+ .num_events = 48, -+ .script_addrs = &sdma_script_imx6q, -+}; -+ -+static struct platform_device_id sdma_devtypes[] = { -+ { -+ .name = "imx25-sdma", -+ .driver_data = (unsigned long)&sdma_imx25, -+ }, { -+ .name = "imx31-sdma", -+ .driver_data = (unsigned long)&sdma_imx31, -+ }, { -+ .name = "imx35-sdma", -+ .driver_data = (unsigned long)&sdma_imx35, -+ }, { -+ .name = "imx51-sdma", -+ .driver_data = (unsigned long)&sdma_imx51, -+ }, { -+ .name = "imx53-sdma", -+ .driver_data = (unsigned long)&sdma_imx53, -+ }, { -+ .name = "imx6q-sdma", -+ .driver_data = (unsigned long)&sdma_imx6q, -+ }, { -+ /* sentinel */ -+ } -+}; -+MODULE_DEVICE_TABLE(platform, sdma_devtypes); -+ -+static const struct of_device_id sdma_dt_ids[] = { -+ { .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, }, -+ { .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, }, -+ { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, }, -+ { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, }, -+ { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, }, -+ { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, sdma_dt_ids); -+ -+#define SDMA_H_CONFIG_DSPDMA BIT(12) /* indicates if the DSPDMA is used */ -+#define SDMA_H_CONFIG_RTD_PINS BIT(11) /* indicates if Real-Time Debug pins are enabled */ -+#define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq /core freq = 2 or 1 */ -+#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/ -+ -+static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event) -+{ -+ u32 chnenbl0 = sdma->drvdata->chnenbl0; -+ return chnenbl0 + event * 4; -+} -+ -+static int sdma_config_ownership(struct sdma_channel *sdmac, -+ bool event_override, bool mcu_override, bool dsp_override) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ unsigned long evt, mcu, dsp; -+ -+ if (event_override && mcu_override && dsp_override) -+ return -EINVAL; -+ -+ evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR); -+ mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR); -+ dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR); -+ -+ if (dsp_override) -+ __clear_bit(channel, &dsp); -+ else -+ __set_bit(channel, &dsp); -+ -+ if (event_override) -+ __clear_bit(channel, &evt); -+ else -+ __set_bit(channel, &evt); -+ -+ if (mcu_override) -+ __clear_bit(channel, &mcu); -+ else -+ __set_bit(channel, &mcu); -+ -+ writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR); -+ writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR); -+ writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR); -+ -+ return 0; -+} -+ -+static void sdma_enable_channel(struct sdma_engine *sdma, int channel) -+{ -+ writel(BIT(channel), sdma->regs + SDMA_H_START); -+} -+ -+/* -+ * sdma_run_channel0 - run a channel and wait till it's done -+ */ -+static int sdma_run_channel0(struct sdma_engine *sdma) -+{ -+ int ret; -+ unsigned long timeout = 500; -+ -+ sdma_enable_channel(sdma, 0); -+ -+ while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) { -+ if (timeout-- <= 0) -+ break; -+ udelay(1); -+ } -+ -+ if (ret) { -+ /* Clear the interrupt status */ -+ writel_relaxed(ret, sdma->regs + SDMA_H_INTR); -+ } else { -+ dev_err(sdma->dev, "Timeout waiting for CH0 ready\n"); -+ } -+ -+ return ret ? 0 : -ETIMEDOUT; -+} -+ -+static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, -+ u32 address) -+{ -+ struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; -+ void *buf_virt; -+ dma_addr_t buf_phys; -+ int ret; -+ unsigned long flags; -+ -+ buf_virt = dma_alloc_coherent(NULL, -+ size, -+ &buf_phys, GFP_KERNEL); -+ if (!buf_virt) { -+ return -ENOMEM; -+ } -+ -+ spin_lock_irqsave(&sdma->channel_0_lock, flags); -+ -+ bd0->mode.command = C0_SETPM; -+ bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; -+ bd0->mode.count = size / 2; -+ bd0->buffer_addr = buf_phys; -+ bd0->ext_buffer_addr = address; -+ -+ memcpy(buf_virt, buf, size); -+ -+ ret = sdma_run_channel0(sdma); -+ -+ spin_unlock_irqrestore(&sdma->channel_0_lock, flags); -+ -+ dma_free_coherent(NULL, size, buf_virt, buf_phys); -+ -+ return ret; -+} -+ -+static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ unsigned long val; -+ u32 chnenbl = chnenbl_ofs(sdma, event); -+ -+ val = readl_relaxed(sdma->regs + chnenbl); -+ __set_bit(channel, &val); -+ writel_relaxed(val, sdma->regs + chnenbl); -+} -+ -+static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ u32 chnenbl = chnenbl_ofs(sdma, event); -+ unsigned long val; -+ -+ val = readl_relaxed(sdma->regs + chnenbl); -+ __clear_bit(channel, &val); -+ writel_relaxed(val, sdma->regs + chnenbl); -+} -+ -+static void sdma_handle_channel_loop(struct sdma_channel *sdmac) -+{ -+ if (sdmac->desc.callback) -+ sdmac->desc.callback(sdmac->desc.callback_param); -+} -+ -+static void sdma_update_channel_loop(struct sdma_channel *sdmac) -+{ -+ struct sdma_buffer_descriptor *bd; -+ -+ /* -+ * loop mode. Iterate over descriptors, re-setup them and -+ * call callback function. -+ */ -+ while (1) { -+ bd = &sdmac->bd[sdmac->buf_tail]; -+ -+ if (bd->mode.status & BD_DONE) -+ break; -+ -+ if (bd->mode.status & BD_RROR) -+ sdmac->status = DMA_ERROR; -+ -+ bd->mode.status |= BD_DONE; -+ sdmac->buf_tail++; -+ sdmac->buf_tail %= sdmac->num_bd; -+ } -+} -+ -+static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) -+{ -+ struct sdma_buffer_descriptor *bd; -+ int i, error = 0; -+ -+ sdmac->chn_real_count = 0; -+ /* -+ * non loop mode. Iterate over all descriptors, collect -+ * errors and call callback function -+ */ -+ for (i = 0; i < sdmac->num_bd; i++) { -+ bd = &sdmac->bd[i]; -+ -+ if (bd->mode.status & (BD_DONE | BD_RROR)) -+ error = -EIO; -+ sdmac->chn_real_count += bd->mode.count; -+ } -+ -+ if (error) -+ sdmac->status = DMA_ERROR; -+ else -+ sdmac->status = DMA_COMPLETE; -+ -+ dma_cookie_complete(&sdmac->desc); -+ if (sdmac->desc.callback) -+ sdmac->desc.callback(sdmac->desc.callback_param); -+} -+ -+static void sdma_tasklet(unsigned long data) -+{ -+ struct sdma_channel *sdmac = (struct sdma_channel *) data; -+ -+ if (sdmac->flags & IMX_DMA_SG_LOOP) -+ sdma_handle_channel_loop(sdmac); -+ else -+ mxc_sdma_handle_channel_normal(sdmac); -+} -+ -+static irqreturn_t sdma_int_handler(int irq, void *dev_id) -+{ -+ struct sdma_engine *sdma = dev_id; -+ unsigned long stat; -+ -+ stat = readl_relaxed(sdma->regs + SDMA_H_INTR); -+ /* not interested in channel 0 interrupts */ -+ stat &= ~1; -+ writel_relaxed(stat, sdma->regs + SDMA_H_INTR); -+ -+ while (stat) { -+ int channel = fls(stat) - 1; -+ struct sdma_channel *sdmac = &sdma->channel[channel]; -+ -+ if (sdmac->flags & IMX_DMA_SG_LOOP) -+ sdma_update_channel_loop(sdmac); -+ -+ tasklet_schedule(&sdmac->tasklet); -+ -+ __clear_bit(channel, &stat); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * sets the pc of SDMA script according to the peripheral type -+ */ -+static void sdma_get_pc(struct sdma_channel *sdmac, -+ enum sdma_peripheral_type peripheral_type) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int per_2_emi = 0, emi_2_per = 0; -+ /* -+ * These are needed once we start to support transfers between -+ * two peripherals or memory-to-memory transfers -+ */ -+ int per_2_per = 0, emi_2_emi = 0; -+ -+ sdmac->pc_from_device = 0; -+ sdmac->pc_to_device = 0; -+ -+ switch (peripheral_type) { -+ case IMX_DMATYPE_MEMORY: -+ emi_2_emi = sdma->script_addrs->ap_2_ap_addr; -+ break; -+ case IMX_DMATYPE_DSP: -+ emi_2_per = sdma->script_addrs->bp_2_ap_addr; -+ per_2_emi = sdma->script_addrs->ap_2_bp_addr; -+ break; -+ case IMX_DMATYPE_FIRI: -+ per_2_emi = sdma->script_addrs->firi_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_firi_addr; -+ break; -+ case IMX_DMATYPE_UART: -+ per_2_emi = sdma->script_addrs->uart_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_app_addr; -+ break; -+ case IMX_DMATYPE_UART_SP: -+ per_2_emi = sdma->script_addrs->uartsh_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_shp_addr; -+ break; -+ case IMX_DMATYPE_ATA: -+ per_2_emi = sdma->script_addrs->ata_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_ata_addr; -+ break; -+ case IMX_DMATYPE_CSPI: -+ case IMX_DMATYPE_EXT: -+ case IMX_DMATYPE_SSI: -+ per_2_emi = sdma->script_addrs->app_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_app_addr; -+ break; -+ case IMX_DMATYPE_SSI_DUAL: -+ per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; -+ break; -+ case IMX_DMATYPE_SSI_SP: -+ case IMX_DMATYPE_MMC: -+ case IMX_DMATYPE_SDHC: -+ case IMX_DMATYPE_CSPI_SP: -+ case IMX_DMATYPE_ESAI: -+ case IMX_DMATYPE_MSHC_SP: -+ per_2_emi = sdma->script_addrs->shp_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_shp_addr; -+ break; -+ case IMX_DMATYPE_ASRC: -+ per_2_emi = sdma->script_addrs->asrc_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->asrc_2_mcu_addr; -+ per_2_per = sdma->script_addrs->per_2_per_addr; -+ break; -+ case IMX_DMATYPE_MSHC: -+ per_2_emi = sdma->script_addrs->mshc_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_mshc_addr; -+ break; -+ case IMX_DMATYPE_CCM: -+ per_2_emi = sdma->script_addrs->dptc_dvfs_addr; -+ break; -+ case IMX_DMATYPE_SPDIF: -+ per_2_emi = sdma->script_addrs->spdif_2_mcu_addr; -+ emi_2_per = sdma->script_addrs->mcu_2_spdif_addr; -+ break; -+ case IMX_DMATYPE_IPU_MEMORY: -+ emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; -+ break; -+ default: -+ break; -+ } -+ -+ sdmac->pc_from_device = per_2_emi; -+ sdmac->pc_to_device = emi_2_per; -+} -+ -+static int sdma_load_context(struct sdma_channel *sdmac) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ int load_address; -+ struct sdma_context_data *context = sdma->context; -+ struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; -+ int ret; -+ unsigned long flags; -+ -+ if (sdmac->direction == DMA_DEV_TO_MEM) { -+ load_address = sdmac->pc_from_device; -+ } else { -+ load_address = sdmac->pc_to_device; -+ } -+ -+ if (load_address < 0) -+ return load_address; -+ -+ dev_dbg(sdma->dev, "load_address = %d\n", load_address); -+ dev_dbg(sdma->dev, "wml = 0x%08x\n", (u32)sdmac->watermark_level); -+ dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr); -+ dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr); -+ dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]); -+ dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]); -+ -+ spin_lock_irqsave(&sdma->channel_0_lock, flags); -+ -+ memset(context, 0, sizeof(*context)); -+ context->channel_state.pc = load_address; -+ -+ /* Send by context the event mask,base address for peripheral -+ * and watermark level -+ */ -+ context->gReg[0] = sdmac->event_mask[1]; -+ context->gReg[1] = sdmac->event_mask[0]; -+ context->gReg[2] = sdmac->per_addr; -+ context->gReg[6] = sdmac->shp_addr; -+ context->gReg[7] = sdmac->watermark_level; -+ -+ bd0->mode.command = C0_SETDM; -+ bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; -+ bd0->mode.count = sizeof(*context) / 4; -+ bd0->buffer_addr = sdma->context_phys; -+ bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel; -+ ret = sdma_run_channel0(sdma); -+ -+ spin_unlock_irqrestore(&sdma->channel_0_lock, flags); -+ -+ return ret; -+} -+ -+static void sdma_disable_channel(struct sdma_channel *sdmac) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ -+ writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP); -+ sdmac->status = DMA_ERROR; -+} -+ -+static int sdma_config_channel(struct sdma_channel *sdmac) -+{ -+ int ret; -+ -+ sdma_disable_channel(sdmac); -+ -+ sdmac->event_mask[0] = 0; -+ sdmac->event_mask[1] = 0; -+ sdmac->shp_addr = 0; -+ sdmac->per_addr = 0; -+ -+ if (sdmac->event_id0) { -+ if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events) -+ return -EINVAL; -+ sdma_event_enable(sdmac, sdmac->event_id0); -+ } -+ -+ switch (sdmac->peripheral_type) { -+ case IMX_DMATYPE_DSP: -+ sdma_config_ownership(sdmac, false, true, true); -+ break; -+ case IMX_DMATYPE_MEMORY: -+ sdma_config_ownership(sdmac, false, true, false); -+ break; -+ default: -+ sdma_config_ownership(sdmac, true, true, false); -+ break; -+ } -+ -+ sdma_get_pc(sdmac, sdmac->peripheral_type); -+ -+ if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && -+ (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { -+ /* Handle multiple event channels differently */ -+ if (sdmac->event_id1) { -+ sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32); -+ if (sdmac->event_id1 > 31) -+ __set_bit(31, &sdmac->watermark_level); -+ sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32); -+ if (sdmac->event_id0 > 31) -+ __set_bit(30, &sdmac->watermark_level); -+ } else { -+ __set_bit(sdmac->event_id0, sdmac->event_mask); -+ } -+ /* Watermark Level */ -+ sdmac->watermark_level |= sdmac->watermark_level; -+ /* Address */ -+ sdmac->shp_addr = sdmac->per_address; -+ } else { -+ sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ -+ } -+ -+ ret = sdma_load_context(sdmac); -+ -+ return ret; -+} -+ -+static int sdma_set_channel_priority(struct sdma_channel *sdmac, -+ unsigned int priority) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ -+ if (priority < MXC_SDMA_MIN_PRIORITY -+ || priority > MXC_SDMA_MAX_PRIORITY) { -+ return -EINVAL; -+ } -+ -+ writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel); -+ -+ return 0; -+} -+ -+static int sdma_request_channel(struct sdma_channel *sdmac) -+{ -+ struct sdma_engine *sdma = sdmac->sdma; -+ int channel = sdmac->channel; -+ int ret = -EBUSY; -+ -+ sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL); -+ if (!sdmac->bd) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ memset(sdmac->bd, 0, PAGE_SIZE); -+ -+ sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys; -+ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; -+ -+ sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY); -+ return 0; -+out: -+ -+ return ret; -+} -+ -+static struct sdma_channel *to_sdma_chan(struct dma_chan *chan) -+{ -+ return container_of(chan, struct sdma_channel, chan); -+} -+ -+static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx) -+{ -+ unsigned long flags; -+ struct sdma_channel *sdmac = to_sdma_chan(tx->chan); -+ dma_cookie_t cookie; -+ -+ spin_lock_irqsave(&sdmac->lock, flags); -+ -+ cookie = dma_cookie_assign(tx); -+ -+ spin_unlock_irqrestore(&sdmac->lock, flags); -+ -+ return cookie; -+} -+ -+static int sdma_alloc_chan_resources(struct dma_chan *chan) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ struct imx_dma_data *data = chan->private; -+ int prio, ret; -+ -+ if (!data) -+ return -EINVAL; -+ -+ switch (data->priority) { -+ case DMA_PRIO_HIGH: -+ prio = 3; -+ break; -+ case DMA_PRIO_MEDIUM: -+ prio = 2; -+ break; -+ case DMA_PRIO_LOW: -+ default: -+ prio = 1; -+ break; -+ } -+ -+ sdmac->peripheral_type = data->peripheral_type; -+ sdmac->event_id0 = data->dma_request; -+ -+ clk_enable(sdmac->sdma->clk_ipg); -+ clk_enable(sdmac->sdma->clk_ahb); -+ -+ ret = sdma_request_channel(sdmac); -+ if (ret) -+ return ret; -+ -+ ret = sdma_set_channel_priority(sdmac, prio); -+ if (ret) -+ return ret; -+ -+ dma_async_tx_descriptor_init(&sdmac->desc, chan); -+ sdmac->desc.tx_submit = sdma_tx_submit; -+ /* txd.flags will be overwritten in prep funcs */ -+ sdmac->desc.flags = DMA_CTRL_ACK; -+ -+ return 0; -+} -+ -+static void sdma_free_chan_resources(struct dma_chan *chan) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ struct sdma_engine *sdma = sdmac->sdma; -+ -+ sdma_disable_channel(sdmac); -+ -+ if (sdmac->event_id0) -+ sdma_event_disable(sdmac, sdmac->event_id0); -+ if (sdmac->event_id1) -+ sdma_event_disable(sdmac, sdmac->event_id1); -+ -+ sdmac->event_id0 = 0; -+ sdmac->event_id1 = 0; -+ -+ sdma_set_channel_priority(sdmac, 0); -+ -+ dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); -+ -+ clk_disable(sdma->clk_ipg); -+ clk_disable(sdma->clk_ahb); -+} -+ -+static struct dma_async_tx_descriptor *sdma_prep_slave_sg( -+ struct dma_chan *chan, struct scatterlist *sgl, -+ unsigned int sg_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ struct sdma_engine *sdma = sdmac->sdma; -+ int ret, i, count; -+ int channel = sdmac->channel; -+ struct scatterlist *sg; -+ -+ if (sdmac->status == DMA_IN_PROGRESS) -+ return NULL; -+ sdmac->status = DMA_IN_PROGRESS; -+ -+ sdmac->flags = 0; -+ -+ sdmac->buf_tail = 0; -+ -+ dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", -+ sg_len, channel); -+ -+ sdmac->direction = direction; -+ ret = sdma_load_context(sdmac); -+ if (ret) -+ goto err_out; -+ -+ if (sg_len > NUM_BD) { -+ dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", -+ channel, sg_len, NUM_BD); -+ ret = -EINVAL; -+ goto err_out; -+ } -+ -+ sdmac->chn_count = 0; -+ for_each_sg(sgl, sg, sg_len, i) { -+ struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; -+ int param; -+ -+ bd->buffer_addr = sg->dma_address; -+ -+ count = sg_dma_len(sg); -+ -+ if (count > 0xffff) { -+ dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n", -+ channel, count, 0xffff); -+ ret = -EINVAL; -+ goto err_out; -+ } -+ -+ bd->mode.count = count; -+ sdmac->chn_count += count; -+ -+ if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) { -+ ret = -EINVAL; -+ goto err_out; -+ } -+ -+ switch (sdmac->word_size) { -+ case DMA_SLAVE_BUSWIDTH_4_BYTES: -+ bd->mode.command = 0; -+ if (count & 3 || sg->dma_address & 3) -+ return NULL; -+ break; -+ case DMA_SLAVE_BUSWIDTH_2_BYTES: -+ bd->mode.command = 2; -+ if (count & 1 || sg->dma_address & 1) -+ return NULL; -+ break; -+ case DMA_SLAVE_BUSWIDTH_1_BYTE: -+ bd->mode.command = 1; -+ break; -+ default: -+ return NULL; -+ } -+ -+ param = BD_DONE | BD_EXTD | BD_CONT; -+ -+ if (i + 1 == sg_len) { -+ param |= BD_INTR; -+ param |= BD_LAST; -+ param &= ~BD_CONT; -+ } -+ -+ dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n", -+ i, count, (u64)sg->dma_address, -+ param & BD_WRAP ? "wrap" : "", -+ param & BD_INTR ? " intr" : ""); -+ -+ bd->mode.status = param; -+ } -+ -+ sdmac->num_bd = sg_len; -+ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; -+ -+ return &sdmac->desc; -+err_out: -+ sdmac->status = DMA_ERROR; -+ return NULL; -+} -+ -+static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( -+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, -+ size_t period_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ struct sdma_engine *sdma = sdmac->sdma; -+ int num_periods = buf_len / period_len; -+ int channel = sdmac->channel; -+ int ret, i = 0, buf = 0; -+ -+ dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); -+ -+ if (sdmac->status == DMA_IN_PROGRESS) -+ return NULL; -+ -+ sdmac->status = DMA_IN_PROGRESS; -+ -+ sdmac->buf_tail = 0; -+ sdmac->period_len = period_len; -+ -+ sdmac->flags |= IMX_DMA_SG_LOOP; -+ sdmac->direction = direction; -+ ret = sdma_load_context(sdmac); -+ if (ret) -+ goto err_out; -+ -+ if (num_periods > NUM_BD) { -+ dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", -+ channel, num_periods, NUM_BD); -+ goto err_out; -+ } -+ -+ if (period_len > 0xffff) { -+ dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n", -+ channel, period_len, 0xffff); -+ goto err_out; -+ } -+ -+ while (buf < buf_len) { -+ struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; -+ int param; -+ -+ bd->buffer_addr = dma_addr; -+ -+ bd->mode.count = period_len; -+ -+ if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) -+ goto err_out; -+ if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES) -+ bd->mode.command = 0; -+ else -+ bd->mode.command = sdmac->word_size; -+ -+ param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR; -+ if (i + 1 == num_periods) -+ param |= BD_WRAP; -+ -+ dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n", -+ i, period_len, (u64)dma_addr, -+ param & BD_WRAP ? "wrap" : "", -+ param & BD_INTR ? " intr" : ""); -+ -+ bd->mode.status = param; -+ -+ dma_addr += period_len; -+ buf += period_len; -+ -+ i++; -+ } -+ -+ sdmac->num_bd = num_periods; -+ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; -+ -+ return &sdmac->desc; -+err_out: -+ sdmac->status = DMA_ERROR; -+ return NULL; -+} -+ -+static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, -+ unsigned long arg) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ struct dma_slave_config *dmaengine_cfg = (void *)arg; -+ -+ switch (cmd) { -+ case DMA_TERMINATE_ALL: -+ sdma_disable_channel(sdmac); -+ return 0; -+ case DMA_SLAVE_CONFIG: -+ if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { -+ sdmac->per_address = dmaengine_cfg->src_addr; -+ sdmac->watermark_level = dmaengine_cfg->src_maxburst * -+ dmaengine_cfg->src_addr_width; -+ sdmac->word_size = dmaengine_cfg->src_addr_width; -+ } else { -+ sdmac->per_address = dmaengine_cfg->dst_addr; -+ sdmac->watermark_level = dmaengine_cfg->dst_maxburst * -+ dmaengine_cfg->dst_addr_width; -+ sdmac->word_size = dmaengine_cfg->dst_addr_width; -+ } -+ sdmac->direction = dmaengine_cfg->direction; -+ return sdma_config_channel(sdmac); -+ default: -+ return -ENOSYS; -+ } -+ -+ return -EINVAL; -+} -+ -+static enum dma_status sdma_tx_status(struct dma_chan *chan, -+ dma_cookie_t cookie, -+ struct dma_tx_state *txstate) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ u32 residue; -+ -+ if (sdmac->flags & IMX_DMA_SG_LOOP) -+ residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; -+ else -+ residue = sdmac->chn_count - sdmac->chn_real_count; -+ -+ dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, -+ residue); -+ -+ return sdmac->status; -+} -+ -+static void sdma_issue_pending(struct dma_chan *chan) -+{ -+ struct sdma_channel *sdmac = to_sdma_chan(chan); -+ struct sdma_engine *sdma = sdmac->sdma; -+ -+ if (sdmac->status == DMA_IN_PROGRESS) -+ sdma_enable_channel(sdma, sdmac->channel); -+} -+ -+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 -+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 -+ -+static void sdma_add_scripts(struct sdma_engine *sdma, -+ const struct sdma_script_start_addrs *addr) -+{ -+ s32 *addr_arr = (u32 *)addr; -+ s32 *saddr_arr = (u32 *)sdma->script_addrs; -+ int i; -+ -+ /* use the default firmware in ROM if missing external firmware */ -+ if (!sdma->script_number) -+ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; -+ -+ for (i = 0; i < sdma->script_number; i++) -+ if (addr_arr[i] > 0) -+ saddr_arr[i] = addr_arr[i]; -+} -+ -+static void sdma_load_firmware(const struct firmware *fw, void *context) -+{ -+ struct sdma_engine *sdma = context; -+ const struct sdma_firmware_header *header; -+ const struct sdma_script_start_addrs *addr; -+ unsigned short *ram_code; -+ -+ if (!fw) { -+ dev_err(sdma->dev, "firmware not found\n"); -+ return; -+ } -+ -+ if (fw->size < sizeof(*header)) -+ goto err_firmware; -+ -+ header = (struct sdma_firmware_header *)fw->data; -+ -+ if (header->magic != SDMA_FIRMWARE_MAGIC) -+ goto err_firmware; -+ if (header->ram_code_start + header->ram_code_size > fw->size) -+ goto err_firmware; -+ switch (header->version_major) { -+ case 1: -+ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; -+ break; -+ case 2: -+ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; -+ break; -+ default: -+ dev_err(sdma->dev, "unknown firmware version\n"); -+ goto err_firmware; -+ } -+ -+ addr = (void *)header + header->script_addrs_start; -+ ram_code = (void *)header + header->ram_code_start; -+ -+ clk_enable(sdma->clk_ipg); -+ clk_enable(sdma->clk_ahb); -+ /* download the RAM image for SDMA */ -+ sdma_load_script(sdma, ram_code, -+ header->ram_code_size, -+ addr->ram_code_start_addr); -+ clk_disable(sdma->clk_ipg); -+ clk_disable(sdma->clk_ahb); -+ -+ sdma_add_scripts(sdma, addr); -+ -+ dev_info(sdma->dev, "loaded firmware %d.%d\n", -+ header->version_major, -+ header->version_minor); -+ -+err_firmware: -+ release_firmware(fw); -+} -+ -+static int __init sdma_get_firmware(struct sdma_engine *sdma, -+ const char *fw_name) -+{ -+ int ret; -+ -+ ret = request_firmware_nowait(THIS_MODULE, -+ FW_ACTION_HOTPLUG, fw_name, sdma->dev, -+ GFP_KERNEL, sdma, sdma_load_firmware); -+ -+ return ret; -+} -+ -+static int __init sdma_init(struct sdma_engine *sdma) -+{ -+ int i, ret; -+ dma_addr_t ccb_phys; -+ -+ clk_enable(sdma->clk_ipg); -+ clk_enable(sdma->clk_ahb); -+ -+ /* Be sure SDMA has not started yet */ -+ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); -+ -+ sdma->channel_control = dma_alloc_coherent(NULL, -+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) + -+ sizeof(struct sdma_context_data), -+ &ccb_phys, GFP_KERNEL); -+ -+ if (!sdma->channel_control) { -+ ret = -ENOMEM; -+ goto err_dma_alloc; -+ } -+ -+ sdma->context = (void *)sdma->channel_control + -+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); -+ sdma->context_phys = ccb_phys + -+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); -+ -+ /* Zero-out the CCB structures array just allocated */ -+ memset(sdma->channel_control, 0, -+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control)); -+ -+ /* disable all channels */ -+ for (i = 0; i < sdma->drvdata->num_events; i++) -+ writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i)); -+ -+ /* All channels have priority 0 */ -+ for (i = 0; i < MAX_DMA_CHANNELS; i++) -+ writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4); -+ -+ ret = sdma_request_channel(&sdma->channel[0]); -+ if (ret) -+ goto err_dma_alloc; -+ -+ sdma_config_ownership(&sdma->channel[0], false, true, false); -+ -+ /* Set Command Channel (Channel Zero) */ -+ writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR); -+ -+ /* Set bits of CONFIG register but with static context switching */ -+ /* FIXME: Check whether to set ACR bit depending on clock ratios */ -+ writel_relaxed(0, sdma->regs + SDMA_H_CONFIG); -+ -+ writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR); -+ -+ /* Set bits of CONFIG register with given context switching mode */ -+ writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG); -+ -+ /* Initializes channel's priorities */ -+ sdma_set_channel_priority(&sdma->channel[0], 7); -+ -+ clk_disable(sdma->clk_ipg); -+ clk_disable(sdma->clk_ahb); -+ -+ return 0; -+ -+err_dma_alloc: -+ clk_disable(sdma->clk_ipg); -+ clk_disable(sdma->clk_ahb); -+ dev_err(sdma->dev, "initialisation failed with %d\n", ret); -+ return ret; -+} -+ -+static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param) -+{ -+ struct imx_dma_data *data = fn_param; -+ -+ if (!imx_dma_is_general_purpose(chan)) -+ return false; -+ -+ chan->private = data; -+ -+ return true; -+} -+ -+static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, -+ struct of_dma *ofdma) -+{ -+ struct sdma_engine *sdma = ofdma->of_dma_data; -+ dma_cap_mask_t mask = sdma->dma_device.cap_mask; -+ struct imx_dma_data data; -+ -+ if (dma_spec->args_count != 3) -+ return NULL; -+ -+ data.dma_request = dma_spec->args[0]; -+ data.peripheral_type = dma_spec->args[1]; -+ data.priority = dma_spec->args[2]; -+ -+ return dma_request_channel(mask, sdma_filter_fn, &data); -+} -+ -+static int __init sdma_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *of_id = -+ of_match_device(sdma_dt_ids, &pdev->dev); -+ struct device_node *np = pdev->dev.of_node; -+ const char *fw_name; -+ int ret; -+ int irq; -+ struct resource *iores; -+ struct sdma_platform_data *pdata = dev_get_platdata(&pdev->dev); -+ int i; -+ struct sdma_engine *sdma; -+ s32 *saddr_arr; -+ const struct sdma_driver_data *drvdata = NULL; -+ -+ if (of_id) -+ drvdata = of_id->data; -+ else if (pdev->id_entry) -+ drvdata = (void *)pdev->id_entry->driver_data; -+ -+ if (!drvdata) { -+ dev_err(&pdev->dev, "unable to find driver data\n"); -+ return -EINVAL; -+ } -+ -+ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); -+ if (ret) -+ return ret; -+ -+ sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); -+ if (!sdma) -+ return -ENOMEM; -+ -+ spin_lock_init(&sdma->channel_0_lock); -+ -+ sdma->dev = &pdev->dev; -+ sdma->drvdata = drvdata; -+ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_irq(pdev, 0); -+ if (!iores || irq < 0) { -+ ret = -EINVAL; -+ goto err_irq; -+ } -+ -+ if (!request_mem_region(iores->start, resource_size(iores), pdev->name)) { -+ ret = -EBUSY; -+ goto err_request_region; -+ } -+ -+ sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); -+ if (IS_ERR(sdma->clk_ipg)) { -+ ret = PTR_ERR(sdma->clk_ipg); -+ goto err_clk; -+ } -+ -+ sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); -+ if (IS_ERR(sdma->clk_ahb)) { -+ ret = PTR_ERR(sdma->clk_ahb); -+ goto err_clk; -+ } -+ -+ clk_prepare(sdma->clk_ipg); -+ clk_prepare(sdma->clk_ahb); -+ -+ sdma->regs = ioremap(iores->start, resource_size(iores)); -+ if (!sdma->regs) { -+ ret = -ENOMEM; -+ goto err_ioremap; -+ } -+ -+ ret = request_irq(irq, sdma_int_handler, 0, "sdma", sdma); -+ if (ret) -+ goto err_request_irq; -+ -+ sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL); -+ if (!sdma->script_addrs) { -+ ret = -ENOMEM; -+ goto err_alloc; -+ } -+ -+ /* initially no scripts available */ -+ saddr_arr = (s32 *)sdma->script_addrs; -+ for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) -+ saddr_arr[i] = -EINVAL; -+ -+ dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask); -+ dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask); -+ -+ INIT_LIST_HEAD(&sdma->dma_device.channels); -+ /* Initialize channel parameters */ -+ for (i = 0; i < MAX_DMA_CHANNELS; i++) { -+ struct sdma_channel *sdmac = &sdma->channel[i]; -+ -+ sdmac->sdma = sdma; -+ spin_lock_init(&sdmac->lock); -+ -+ sdmac->chan.device = &sdma->dma_device; -+ dma_cookie_init(&sdmac->chan); -+ sdmac->channel = i; -+ -+ tasklet_init(&sdmac->tasklet, sdma_tasklet, -+ (unsigned long) sdmac); -+ /* -+ * Add the channel to the DMAC list. Do not add channel 0 though -+ * because we need it internally in the SDMA driver. This also means -+ * that channel 0 in dmaengine counting matches sdma channel 1. -+ */ -+ if (i) -+ list_add_tail(&sdmac->chan.device_node, -+ &sdma->dma_device.channels); -+ } -+ -+ ret = sdma_init(sdma); -+ if (ret) -+ goto err_init; -+ -+ if (sdma->drvdata->script_addrs) -+ sdma_add_scripts(sdma, sdma->drvdata->script_addrs); -+ if (pdata && pdata->script_addrs) -+ sdma_add_scripts(sdma, pdata->script_addrs); -+ -+ if (pdata) { -+ ret = sdma_get_firmware(sdma, pdata->fw_name); -+ if (ret) -+ dev_warn(&pdev->dev, "failed to get firmware from platform data\n"); -+ } else { -+ /* -+ * Because that device tree does not encode ROM script address, -+ * the RAM script in firmware is mandatory for device tree -+ * probe, otherwise it fails. -+ */ -+ ret = of_property_read_string(np, "fsl,sdma-ram-script-name", -+ &fw_name); -+ if (ret) -+ dev_warn(&pdev->dev, "failed to get firmware name\n"); -+ else { -+ ret = sdma_get_firmware(sdma, fw_name); -+ if (ret) -+ dev_warn(&pdev->dev, "failed to get firmware from device tree\n"); -+ } -+ } -+ -+ sdma->dma_device.dev = &pdev->dev; -+ -+ sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; -+ sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources; -+ sdma->dma_device.device_tx_status = sdma_tx_status; -+ sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; -+ sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; -+ sdma->dma_device.device_control = sdma_control; -+ sdma->dma_device.device_issue_pending = sdma_issue_pending; -+ sdma->dma_device.dev->dma_parms = &sdma->dma_parms; -+ dma_set_max_seg_size(sdma->dma_device.dev, 65535); -+ -+ ret = dma_async_device_register(&sdma->dma_device); -+ if (ret) { -+ dev_err(&pdev->dev, "unable to register\n"); -+ goto err_init; -+ } -+ -+ if (np) { -+ ret = of_dma_controller_register(np, sdma_xlate, sdma); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to register controller\n"); -+ goto err_register; -+ } -+ } -+ -+ dev_info(sdma->dev, "initialized\n"); -+ -+ return 0; -+ -+err_register: -+ dma_async_device_unregister(&sdma->dma_device); -+err_init: -+ kfree(sdma->script_addrs); -+err_alloc: -+ free_irq(irq, sdma); -+err_request_irq: -+ iounmap(sdma->regs); -+err_ioremap: -+err_clk: -+ release_mem_region(iores->start, resource_size(iores)); -+err_request_region: -+err_irq: -+ kfree(sdma); -+ return ret; -+} -+ -+static int sdma_remove(struct platform_device *pdev) -+{ -+ return -EBUSY; -+} -+ -+static struct platform_driver sdma_driver = { -+ .driver = { -+ .name = "imx-sdma", -+ .of_match_table = sdma_dt_ids, -+ }, -+ .id_table = sdma_devtypes, -+ .remove = sdma_remove, -+}; -+ -+static int __init sdma_module_init(void) -+{ -+ return platform_driver_probe(&sdma_driver, sdma_probe); -+} -+module_init(sdma_module_init); -+ -+MODULE_AUTHOR("Sascha Hauer, Pengutronix "); -+MODULE_DESCRIPTION("i.MX SDMA driver"); -+MODULE_LICENSE("GPL"); -diff -Nur linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-dc.c linux-3.16.6/drivers/gpu/ipu-v3/ipu-dc.c ---- linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-dc.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/gpu/ipu-v3/ipu-dc.c 2014-10-23 12:35:30.966220009 -0500 -@@ -93,6 +93,7 @@ - IPU_DC_MAP_BGR666, - IPU_DC_MAP_LVDS666, - IPU_DC_MAP_BGR24, -+ IPU_DC_MAP_RGB666, - }; - - struct ipu_dc { -@@ -161,6 +162,8 @@ - return IPU_DC_MAP_LVDS666; - case V4L2_PIX_FMT_BGR24: - return IPU_DC_MAP_BGR24; -+ case V4L2_PIX_FMT_RGB666: -+ return IPU_DC_MAP_RGB666; - default: - return -EINVAL; - } -@@ -452,6 +455,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.16.6.orig/drivers/gpu/ipu-v3/ipu-di.c linux-3.16.6/drivers/gpu/ipu-v3/ipu-di.c ---- linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-di.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/gpu/ipu-v3/ipu-di.c 2014-10-23 12:35:38.078220007 -0500 -@@ -595,7 +595,7 @@ - } - } - -- if (sig->clk_pol) -+ if (sig->clk_pol == CLK_POL_POSEDGE) - di_gen |= DI_GEN_POLARITY_DISP_CLK; - - ipu_di_write(di, di_gen, DI_GENERAL); -@@ -606,7 +606,7 @@ - reg = ipu_di_read(di, DI_POL); - reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); - -- if (sig->enable_pol) -+ if (sig->enable_pol == ENABLE_POL_HIGH) - reg |= DI_POL_DRDY_POLARITY_15; - if (sig->data_pol) - reg |= DI_POL_DRDY_DATA_POLARITY; -diff -Nur linux-3.16.6.orig/drivers/Kconfig linux-3.16.6/drivers/Kconfig ---- linux-3.16.6.orig/drivers/Kconfig 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/Kconfig 2014-10-23 12:37:18.314220004 -0500 -@@ -176,4 +176,6 @@ - - source "drivers/mcb/Kconfig" - -+source "drivers/cec/Kconfig" -+ - endmenu -diff -Nur linux-3.16.6.orig/drivers/Makefile linux-3.16.6/drivers/Makefile ---- linux-3.16.6.orig/drivers/Makefile 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/Makefile 2014-10-23 12:37:18.350220009 -0500 -@@ -158,3 +158,4 @@ - obj-$(CONFIG_FMC) += fmc/ - obj-$(CONFIG_POWERCAP) += powercap/ - obj-$(CONFIG_MCB) += mcb/ -+obj-$(CONFIG_CEC) += cec/ -diff -Nur linux-3.16.6.orig/drivers/mmc/core/core.c linux-3.16.6/drivers/mmc/core/core.c ---- linux-3.16.6.orig/drivers/mmc/core/core.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/mmc/core/core.c 2014-10-23 12:34:18.710219997 -0500 -@@ -13,11 +13,13 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -1515,6 +1517,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. -@@ -1531,6 +1570,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.16.6.orig/drivers/mmc/core/host.c linux-3.16.6/drivers/mmc/core/host.c ---- linux-3.16.6.orig/drivers/mmc/core/host.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/mmc/core/host.c 2014-10-23 12:34:34.134220000 -0500 -@@ -12,14 +12,18 @@ - * MMC host class device management - */ - -+#include -+#include - #include - #include -+#include - #include - #include - #include - #include - #include - #include -+#include - #include - #include - -@@ -461,6 +465,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 -@@ -540,6 +604,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.16.6.orig/drivers/mmc/host/dw_mmc.c linux-3.16.6/drivers/mmc/host/dw_mmc.c ---- linux-3.16.6.orig/drivers/mmc/host/dw_mmc.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/mmc/host/dw_mmc.c 2014-10-23 12:34:26.238219996 -0500 -@@ -2049,6 +2049,8 @@ - if (!mmc) - return -ENOMEM; - -+ mmc_of_parse(mmc); -+ - slot = mmc_priv(mmc); - slot->id = id; - slot->mmc = mmc; -diff -Nur linux-3.16.6.orig/drivers/mmc/host/Kconfig linux-3.16.6/drivers/mmc/host/Kconfig ---- linux-3.16.6.orig/drivers/mmc/host/Kconfig 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/mmc/host/Kconfig 2014-10-23 12:34:04.318220041 -0500 -@@ -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 || MACH_DOVE -- depends on MMC_SDHCI_PLTFM -+ depends on (ARCH_DOVE || MACH_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,8 @@ - - config MMC_SDHCI_PXAV3 - tristate "Marvell MMP2 SD Host Controller support (PXAV3)" -- depends on CLKDEV_LOOKUP -- depends on MMC_SDHCI_PLTFM -+ depends on CLKDEV_LOOKUP && HAS_DMA -+ select MMC_SDHCI_PLTFM - default CPU_MMP2 - help - This selects the Marvell(R) PXAV3 SD Host Controller. -@@ -227,8 +229,8 @@ - - config MMC_SDHCI_PXAV2 - tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" -- depends on CLKDEV_LOOKUP -- depends on MMC_SDHCI_PLTFM -+ depends on CLKDEV_LOOKUP && HAS_DMA -+ select MMC_SDHCI_PLTFM - default CPU_PXA910 - help - This selects the Marvell(R) PXAV2 SD Host Controller. -@@ -239,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 -@@ -261,8 +264,8 @@ - - config MMC_SDHCI_BCM_KONA - tristate "SDHCI support on Broadcom KONA platform" -- depends on ARCH_BCM_MOBILE -- depends on MMC_SDHCI_PLTFM -+ depends on ARCH_BCM_MOBILE && HAS_DMA -+ select MMC_SDHCI_PLTFM - help - This selects the Broadcom Kona Secure Digital Host Controller - Interface(SDHCI) support. -@@ -272,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.16.6.orig/drivers/mmc/host/sdhci.c linux-3.16.6/drivers/mmc/host/sdhci.c ---- linux-3.16.6.orig/drivers/mmc/host/sdhci.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/mmc/host/sdhci.c 2014-10-23 12:34:10.650220104 -0500 -@@ -1530,7 +1530,6 @@ - host->ops->set_clock(host, host->clock); - } - -- - /* Reset SD Clock Enable */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; -@@ -1763,9 +1762,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) -diff -Nur linux-3.16.6.orig/drivers/regulator/anatop-regulator.c linux-3.16.6/drivers/regulator/anatop-regulator.c ---- linux-3.16.6.orig/drivers/regulator/anatop-regulator.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/regulator/anatop-regulator.c 2014-10-23 12:36:22.798219997 -0500 -@@ -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.16.6.orig/drivers/regulator/core.c linux-3.16.6/drivers/regulator/core.c ---- linux-3.16.6.orig/drivers/regulator/core.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/regulator/core.c 2014-10-23 12:36:22.802220004 -0500 -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -77,7 +78,7 @@ - */ - struct regulator_enable_gpio { - struct list_head list; -- int gpio; -+ struct gpio_desc *gpiod; - u32 enable_count; /* a number of enabled shared GPIO */ - u32 request_count; /* a number of requested shared GPIO */ - unsigned int ena_gpio_invert:1; -@@ -1660,10 +1661,13 @@ - const struct regulator_config *config) - { - struct regulator_enable_gpio *pin; -+ struct gpio_desc *gpiod; - int ret; - -+ gpiod = gpio_to_desc(config->ena_gpio); -+ - list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { -- if (pin->gpio == config->ena_gpio) { -+ if (pin->gpiod == gpiod) { - rdev_dbg(rdev, "GPIO %d is already used\n", - config->ena_gpio); - goto update_ena_gpio_to_rdev; -@@ -1682,7 +1686,7 @@ - return -ENOMEM; - } - -- pin->gpio = config->ena_gpio; -+ pin->gpiod = gpiod; - pin->ena_gpio_invert = config->ena_gpio_invert; - list_add(&pin->list, ®ulator_ena_gpio_list); - -@@ -1701,10 +1705,10 @@ - - /* Free the GPIO only in case of no use */ - list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { -- if (pin->gpio == rdev->ena_pin->gpio) { -+ if (pin->gpiod == rdev->ena_pin->gpiod) { - if (pin->request_count <= 1) { - pin->request_count = 0; -- gpio_free(pin->gpio); -+ gpiod_put(pin->gpiod); - list_del(&pin->list); - kfree(pin); - } else { -@@ -1732,8 +1736,8 @@ - if (enable) { - /* Enable GPIO at initial use */ - if (pin->enable_count == 0) -- gpio_set_value_cansleep(pin->gpio, -- !pin->ena_gpio_invert); -+ gpiod_set_value_cansleep(pin->gpiod, -+ !pin->ena_gpio_invert); - - pin->enable_count++; - } else { -@@ -1744,8 +1748,8 @@ - - /* Disable GPIO if not used */ - if (pin->enable_count <= 1) { -- gpio_set_value_cansleep(pin->gpio, -- pin->ena_gpio_invert); -+ gpiod_set_value_cansleep(pin->gpiod, -+ pin->ena_gpio_invert); - pin->enable_count = 0; - } - } -@@ -3470,7 +3474,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.16.6.orig/drivers/regulator/dummy.c linux-3.16.6/drivers/regulator/dummy.c ---- linux-3.16.6.orig/drivers/regulator/dummy.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/regulator/dummy.c 2014-10-23 12:36:22.810220006 -0500 -@@ -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.16.6.orig/drivers/regulator/fixed.c linux-3.16.6/drivers/regulator/fixed.c ---- linux-3.16.6.orig/drivers/regulator/fixed.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/regulator/fixed.c 2014-10-23 12:36:22.810220006 -0500 -@@ -156,9 +156,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.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.c linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.c ---- linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.c 2014-10-23 12:37:30.178219970 -0500 -@@ -0,0 +1,88 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include "drm-ddc-connector.h" -+ -+enum drm_connector_status -+drm_ddc_connector_always_connected(struct drm_connector *connector, bool force) -+{ -+ return connector_status_connected; -+} -+EXPORT_SYMBOL_GPL(drm_ddc_connector_always_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); -+ -+void drm_ddc_connector_destroy(struct drm_connector *connector) -+{ -+ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); -+ -+ pr_info("%s: %p\n", __func__, ddc_conn); -+ -+ drm_sysfs_connector_remove(connector); -+ drm_connector_cleanup(connector); -+ if (ddc_conn->ddc) -+ i2c_put_adapter(ddc_conn->ddc); -+ kfree(ddc_conn); -+} -+EXPORT_SYMBOL_GPL(drm_ddc_connector_destroy); -+ -+void drm_ddc_connector_add(struct drm_device *drm, -+ struct drm_ddc_connector *ddc_conn, -+ struct drm_connector_funcs *funcs, int connector_type) -+{ -+ drm_connector_init(drm, &ddc_conn->connector, funcs, connector_type); -+} -+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 = kzalloc(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) { -+ kfree(ddc_conn); -+ return ERR_PTR(-EPROBE_DEFER); -+ } -+ } -+ -+ return ddc_conn; -+} -+EXPORT_SYMBOL_GPL(drm_ddc_connector_create); -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("Generic DRM DDC connector module"); -+MODULE_LICENSE("GPL v2"); -diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.h linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.h ---- linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.h 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.h 2014-10-23 12:37:30.178219970 -0500 -@@ -0,0 +1,31 @@ -+#ifndef DRM_DDC_CONNECTOR_H -+#define DRM_DDC_CONNECTOR_H -+ -+#include -+ -+struct drm_ddc_connector { -+ struct i2c_adapter *ddc; -+ struct drm_connector connector; -+ void *private; -+}; -+ -+#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector) -+ -+enum drm_connector_status drm_ddc_connector_always_connected( -+ struct drm_connector *connector, bool force); -+int drm_ddc_connector_get_modes(struct drm_connector *connector); -+void drm_ddc_connector_add(struct drm_device *drm, -+ struct drm_ddc_connector *ddc_conn, -+ struct drm_connector_funcs *funcs, int connector_type); -+void drm_ddc_connector_destroy(struct drm_connector *connector); -+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.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.c ---- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.c 2014-10-23 12:37:11.394219951 -0500 -@@ -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 -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#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); -+ synchronize_irq(dw->data.irq); -+} -+ -+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); -+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); -+ -+ 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 "); -+MODULE_LICENSE("GPL"); -diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.h ---- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.h 2014-10-23 12:36:44.258220010 -0500 -@@ -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.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.c ---- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.c 2014-10-23 12:37:23.890220362 -0500 -@@ -0,0 +1,207 @@ -+/* 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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); -+ -+ platform_set_drvdata(pdev, cec); -+ -+ /* -+ * 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 "); -+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.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.h ---- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h 1969-12-31 18:00:00.000000000 -0600 -+++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.h 2014-10-23 12:37:23.890220362 -0500 -@@ -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.16.6.orig/drivers/staging/imx-drm/imx-drm-core.c linux-3.16.6/drivers/staging/imx-drm/imx-drm-core.c ---- linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm-core.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/staging/imx-drm/imx-drm-core.c 2014-10-23 12:37:37.690220197 -0500 -@@ -115,8 +115,7 @@ - helper = &imx_crtc->imx_drm_helper_funcs; - if (helper->set_interface_pix_fmt) - return helper->set_interface_pix_fmt(encoder->crtc, -- encoder->encoder_type, interface_pix_fmt, -- hsync_pin, vsync_pin); -+ interface_pix_fmt, hsync_pin, vsync_pin); - return 0; - } - EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); -diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm.h linux-3.16.6/drivers/staging/imx-drm/imx-drm.h ---- linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm.h 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/staging/imx-drm/imx-drm.h 2014-10-23 12:37:37.690220197 -0500 -@@ -17,7 +17,7 @@ - struct imx_drm_crtc_helper_funcs { - int (*enable_vblank)(struct drm_crtc *crtc); - void (*disable_vblank)(struct drm_crtc *crtc); -- int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type, -+ int (*set_interface_pix_fmt)(struct drm_crtc *crtc, - u32 pix_fmt, int hsync_pin, int vsync_pin); - const struct drm_crtc_helper_funcs *crtc_helper_funcs; - const struct drm_crtc_funcs *crtc_funcs; -diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-hdmi.c linux-3.16.6/drivers/staging/imx-drm/imx-hdmi.c ---- linux-3.16.6.orig/drivers/staging/imx-drm/imx-hdmi.c 2014-10-15 05:05:43.000000000 -0500 -+++ linux-3.16.6/drivers/staging/imx-drm/imx-hdmi.c 2014-10-23 12:37:30.178219970 -0500 -@@ -29,6 +29,9 @@ - #include - #include ++ ++ V4L2_PIX_FMT_RGB666 ++ 'RGBH' ++ ++ r5 ++ r4 ++ r3 ++ r2 ++ r1 ++ r0 ++ g5 ++ g4 ++ ++ g3 ++ g2 ++ g1 ++ g0 ++ b5 ++ b4 ++ b3 ++ b2 ++ ++ b1 ++ b0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + V4L2_PIX_FMT_BGR24 + 'BGR3' +diff -Nur linux-3.16.6.orig/drivers/ata/ahci_imx.c linux-3.16.6/drivers/ata/ahci_imx.c +--- linux-3.16.6.orig/drivers/ata/ahci_imx.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/ata/ahci_imx.c 2014-10-23 12:26:19.770220044 -0500 +@@ -64,6 +64,7 @@ + struct regmap *gpr; + bool no_device; + bool first_time; ++ u32 phy_params; + }; + + static int ahci_imx_hotplug; +@@ -248,14 +249,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); +@@ -369,6 +363,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 }, ++ { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, ++ { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, ++ { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, ++ { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, ++ { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, ++ { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, ++ { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, ++ { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, ++ { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, ++ { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, ++ { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, ++ { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, ++ { 5750, 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; +@@ -410,6 +563,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)) { +@@ -417,6 +572,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.16.6.orig/drivers/ata/ahci_imx.c.orig linux-3.16.6/drivers/ata/ahci_imx.c.orig +--- linux-3.16.6.orig/drivers/ata/ahci_imx.c.orig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/ata/ahci_imx.c.orig 2014-10-23 12:18:59.602219672 -0500 +@@ -0,0 +1,679 @@ ++/* ++ * copyright (c) 2013 Freescale Semiconductor, Inc. ++ * Freescale IMX AHCI SATA platform driver ++ * ++ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++enum { ++ /* Timer 1-ms Register */ ++ IMX_TIMER1MS = 0x00e0, ++ /* Port0 PHY Control Register */ ++ IMX_P0PHYCR = 0x0178, ++ IMX_P0PHYCR_TEST_PDDQ = 1 << 20, ++ IMX_P0PHYCR_CR_READ = 1 << 19, ++ IMX_P0PHYCR_CR_WRITE = 1 << 18, ++ IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, ++ IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, ++ /* Port0 PHY Status Register */ ++ IMX_P0PHYSR = 0x017c, ++ IMX_P0PHYSR_CR_ACK = 1 << 18, ++ IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, ++ /* Lane0 Output Status Register */ ++ IMX_LANE0_OUT_STAT = 0x2003, ++ IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, ++ /* Clock Reset Register */ ++ IMX_CLOCK_RESET = 0x7f3f, ++ IMX_CLOCK_RESET_RESET = 1 << 0, ++}; ++ ++enum ahci_imx_type { ++ AHCI_IMX53, ++ AHCI_IMX6Q, ++}; ++ ++struct imx_ahci_priv { ++ struct platform_device *ahci_pdev; ++ enum ahci_imx_type type; ++ struct clk *sata_clk; ++ struct clk *sata_ref_clk; ++ struct clk *ahb_clk; ++ struct regmap *gpr; ++ bool no_device; ++ bool first_time; ++ u32 phy_params; ++}; ++ ++static int ahci_imx_hotplug; ++module_param_named(hotplug, ahci_imx_hotplug, int, 0644); ++MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); ++ ++static void ahci_imx_host_stop(struct ata_host *host); ++ ++static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) ++{ ++ int timeout = 10; ++ u32 crval; ++ u32 srval; ++ ++ /* Assert or deassert the bit */ ++ crval = readl(mmio + IMX_P0PHYCR); ++ if (assert) ++ crval |= bit; ++ else ++ crval &= ~bit; ++ writel(crval, mmio + IMX_P0PHYCR); ++ ++ /* Wait for the cr_ack signal */ ++ do { ++ srval = readl(mmio + IMX_P0PHYSR); ++ if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) ++ break; ++ usleep_range(100, 200); ++ } while (--timeout); ++ ++ return timeout ? 0 : -ETIMEDOUT; ++} ++ ++static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) ++{ ++ u32 crval = addr; ++ int ret; ++ ++ /* Supply the address on cr_data_in */ ++ writel(crval, mmio + IMX_P0PHYCR); ++ ++ /* Assert the cr_cap_addr signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); ++ if (ret) ++ return ret; ++ ++ /* Deassert cr_cap_addr */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int imx_phy_reg_write(u16 val, void __iomem *mmio) ++{ ++ u32 crval = val; ++ int ret; ++ ++ /* Supply the data on cr_data_in */ ++ writel(crval, mmio + IMX_P0PHYCR); ++ ++ /* Assert the cr_cap_data signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); ++ if (ret) ++ return ret; ++ ++ /* Deassert cr_cap_data */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); ++ if (ret) ++ return ret; ++ ++ if (val & IMX_CLOCK_RESET_RESET) { ++ /* ++ * In case we're resetting the phy, it's unable to acknowledge, ++ * so we return immediately here. ++ */ ++ crval |= IMX_P0PHYCR_CR_WRITE; ++ writel(crval, mmio + IMX_P0PHYCR); ++ goto out; ++ } ++ ++ /* Assert the cr_write signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); ++ if (ret) ++ return ret; ++ ++ /* Deassert cr_write */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); ++ if (ret) ++ return ret; ++ ++out: ++ return 0; ++} ++ ++static int imx_phy_reg_read(u16 *val, void __iomem *mmio) ++{ ++ int ret; ++ ++ /* Assert the cr_read signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); ++ if (ret) ++ return ret; ++ ++ /* Capture the data from cr_data_out[] */ ++ *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; ++ ++ /* Deassert cr_read */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) ++{ ++ void __iomem *mmio = hpriv->mmio; ++ int timeout = 10; ++ u16 val; ++ int ret; ++ ++ /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ ++ ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); ++ if (ret) ++ return ret; ++ ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); ++ if (ret) ++ return ret; ++ ++ /* Wait for PHY RX_PLL to be stable */ ++ do { ++ usleep_range(100, 200); ++ ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); ++ if (ret) ++ return ret; ++ ret = imx_phy_reg_read(&val, mmio); ++ if (ret) ++ return ret; ++ if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) ++ break; ++ } while (--timeout); ++ ++ return timeout ? 0 : -ETIMEDOUT; ++} ++ ++static int imx_sata_enable(struct ahci_host_priv *hpriv) ++{ ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ struct device *dev = &imxpriv->ahci_pdev->dev; ++ int ret; ++ ++ if (imxpriv->no_device) ++ return 0; ++ ++ if (hpriv->target_pwr) { ++ ret = regulator_enable(hpriv->target_pwr); ++ if (ret) ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(imxpriv->sata_ref_clk); ++ if (ret < 0) ++ goto disable_regulator; ++ ++ if (imxpriv->type == AHCI_IMX6Q) { ++ /* ++ * set PHY Paremeters, two steps to configure the GPR13, ++ * one write for rest of parameters, mask of first write ++ * is 0x07ffffff, and the other one write for setting ++ * the mpll_clk_en. ++ */ ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | ++ IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | ++ IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | ++ IMX6Q_GPR13_SATA_SPD_MODE_MASK | ++ IMX6Q_GPR13_SATA_MPLL_SS_EN | ++ IMX6Q_GPR13_SATA_TX_ATTEN_MASK | ++ IMX6Q_GPR13_SATA_TX_BOOST_MASK | ++ IMX6Q_GPR13_SATA_TX_LVL_MASK | ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN | ++ IMX6Q_GPR13_SATA_TX_EDGE_RATE, ++ imxpriv->phy_params); ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ ++ usleep_range(100, 200); ++ ++ ret = imx_sata_phy_reset(hpriv); ++ if (ret) { ++ dev_err(dev, "failed to reset phy: %d\n", ret); ++ goto disable_regulator; ++ } ++ } ++ ++ usleep_range(1000, 2000); ++ ++ return 0; ++ ++disable_regulator: ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); ++ ++ return ret; ++} ++ ++static void imx_sata_disable(struct ahci_host_priv *hpriv) ++{ ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ ++ if (imxpriv->no_device) ++ return; ++ ++ if (imxpriv->type == AHCI_IMX6Q) { ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ !IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ } ++ ++ clk_disable_unprepare(imxpriv->sata_ref_clk); ++ ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); ++} ++ ++static void ahci_imx_error_handler(struct ata_port *ap) ++{ ++ u32 reg_val; ++ struct ata_device *dev; ++ struct ata_host *host = dev_get_drvdata(ap->dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ void __iomem *mmio = hpriv->mmio; ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ ++ ahci_error_handler(ap); ++ ++ if (!(imxpriv->first_time) || ahci_imx_hotplug) ++ return; ++ ++ imxpriv->first_time = false; ++ ++ ata_for_each_dev(dev, &ap->link, ENABLED) ++ return; ++ /* ++ * Disable link to save power. An imx ahci port can't be recovered ++ * without full reset once the pddq mode is enabled making it ++ * impossible to use as part of libata LPM. ++ */ ++ reg_val = readl(mmio + IMX_P0PHYCR); ++ 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, ++ unsigned long deadline) ++{ ++ struct ata_port *ap = link->ap; ++ struct ata_host *host = dev_get_drvdata(ap->dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ int ret = -EIO; ++ ++ if (imxpriv->type == AHCI_IMX53) ++ ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); ++ else if (imxpriv->type == AHCI_IMX6Q) ++ ret = ahci_ops.softreset(link, class, deadline); ++ ++ return ret; ++} ++ ++static struct ata_port_operations ahci_imx_ops = { ++ .inherits = &ahci_ops, ++ .host_stop = ahci_imx_host_stop, ++ .error_handler = ahci_imx_error_handler, ++ .softreset = ahci_imx_softreset, ++}; ++ ++static const struct ata_port_info ahci_imx_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_imx_ops, ++}; ++ ++static const struct of_device_id imx_ahci_of_match[] = { ++ { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, ++ { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, ++ {}, ++}; ++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; ++}; ++ ++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 }, ++ { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, ++ { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, ++ { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, ++ { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, ++ { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, ++ { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, ++ { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, ++ { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, ++ { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, ++ { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, ++ { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, ++ { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, ++ { 5750, 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, ++ }, ++}; ++ ++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 (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; ++ const struct of_device_id *of_id; ++ struct ahci_host_priv *hpriv; ++ struct imx_ahci_priv *imxpriv; ++ unsigned int reg_val; ++ int ret; ++ ++ of_id = of_match_device(imx_ahci_of_match, dev); ++ if (!of_id) ++ return -EINVAL; ++ ++ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); ++ if (!imxpriv) ++ return -ENOMEM; ++ ++ imxpriv->ahci_pdev = pdev; ++ imxpriv->no_device = false; ++ imxpriv->first_time = true; ++ imxpriv->type = (enum ahci_imx_type)of_id->data; ++ ++ imxpriv->sata_clk = devm_clk_get(dev, "sata"); ++ if (IS_ERR(imxpriv->sata_clk)) { ++ dev_err(dev, "can't get sata clock.\n"); ++ return PTR_ERR(imxpriv->sata_clk); ++ } ++ ++ imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); ++ if (IS_ERR(imxpriv->sata_ref_clk)) { ++ dev_err(dev, "can't get sata_ref clock.\n"); ++ return PTR_ERR(imxpriv->sata_ref_clk); ++ } ++ ++ imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); ++ if (IS_ERR(imxpriv->ahb_clk)) { ++ dev_err(dev, "can't get ahb clock.\n"); ++ return PTR_ERR(imxpriv->ahb_clk); ++ } ++ ++ if (imxpriv->type == AHCI_IMX6Q) { ++ u32 reg_value; ++ ++ imxpriv->gpr = syscon_regmap_lookup_by_compatible( ++ "fsl,imx6q-iomuxc-gpr"); ++ if (IS_ERR(imxpriv->gpr)) { ++ dev_err(dev, ++ "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 | ++ IMX6Q_GPR13_SATA_MPLL_SS_EN | ++ reg_value; ++ } ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ hpriv->plat_data = imxpriv; ++ ++ ret = clk_prepare_enable(imxpriv->sata_clk); ++ if (ret) ++ return ret; ++ ++ ret = imx_sata_enable(hpriv); ++ if (ret) ++ goto disable_clk; ++ ++ /* ++ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, ++ * and IP vendor specific register IMX_TIMER1MS. ++ * Configure CAP_SSS (support stagered spin up). ++ * Implement the port0. ++ * Get the ahb clock rate, and configure the TIMER1MS register. ++ */ ++ reg_val = readl(hpriv->mmio + HOST_CAP); ++ if (!(reg_val & HOST_CAP_SSS)) { ++ reg_val |= HOST_CAP_SSS; ++ writel(reg_val, hpriv->mmio + HOST_CAP); ++ } ++ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL); ++ if (!(reg_val & 0x1)) { ++ reg_val |= 0x1; ++ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL); ++ } ++ ++ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; ++ writel(reg_val, hpriv->mmio + IMX_TIMER1MS); ++ ++ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, ++ 0, 0, 0); ++ if (ret) ++ goto disable_sata; ++ ++ return 0; ++ ++disable_sata: ++ imx_sata_disable(hpriv); ++disable_clk: ++ clk_disable_unprepare(imxpriv->sata_clk); ++ return ret; ++} ++ ++static void ahci_imx_host_stop(struct ata_host *host) ++{ ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ ++ imx_sata_disable(hpriv); ++ clk_disable_unprepare(imxpriv->sata_clk); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int imx_ahci_suspend(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int ret; ++ ++ ret = ahci_platform_suspend_host(dev); ++ if (ret) ++ return ret; ++ ++ imx_sata_disable(hpriv); ++ ++ return 0; ++} ++ ++static int imx_ahci_resume(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int ret; ++ ++ ret = imx_sata_enable(hpriv); ++ if (ret) ++ return ret; ++ ++ return ahci_platform_resume_host(dev); ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume); ++ ++static struct platform_driver imx_ahci_driver = { ++ .probe = imx_ahci_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "ahci-imx", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_ahci_of_match, ++ .pm = &ahci_imx_pm_ops, ++ }, ++}; ++module_platform_driver(imx_ahci_driver); ++ ++MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver"); ++MODULE_AUTHOR("Richard Zhu "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ahci:imx"); +diff -Nur linux-3.16.6.orig/drivers/cec/cec-dev.c linux-3.16.6/drivers/cec/cec-dev.c +--- linux-3.16.6.orig/drivers/cec/cec-dev.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/cec/cec-dev.c 2014-10-23 12:37:18.374219998 -0500 +@@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 "); ++MODULE_DESCRIPTION("Generic HDMI CEC driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.16.6.orig/drivers/cec/Kconfig linux-3.16.6/drivers/cec/Kconfig +--- linux-3.16.6.orig/drivers/cec/Kconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/cec/Kconfig 2014-10-23 12:37:18.350220009 -0500 +@@ -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.16.6.orig/drivers/cec/Makefile linux-3.16.6/drivers/cec/Makefile +--- linux-3.16.6.orig/drivers/cec/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/cec/Makefile 2014-10-23 12:37:18.374219998 -0500 +@@ -0,0 +1 @@ ++obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o +diff -Nur linux-3.16.6.orig/drivers/dma/imx-sdma.c linux-3.16.6/drivers/dma/imx-sdma.c +--- linux-3.16.6.orig/drivers/dma/imx-sdma.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/dma/imx-sdma.c 2014-10-23 12:35:52.990220019 -0500 +@@ -255,7 +255,6 @@ + enum dma_slave_buswidth word_size; + unsigned int buf_tail; + unsigned int num_bd; +- unsigned int period_len; + struct sdma_buffer_descriptor *bd; + dma_addr_t bd_phys; + unsigned int pc_from_device, pc_to_device; +@@ -594,12 +593,6 @@ + + static void sdma_handle_channel_loop(struct sdma_channel *sdmac) + { +- if (sdmac->desc.callback) +- sdmac->desc.callback(sdmac->desc.callback_param); +-} +- +-static void sdma_update_channel_loop(struct sdma_channel *sdmac) +-{ + struct sdma_buffer_descriptor *bd; + + /* +@@ -618,6 +611,9 @@ + bd->mode.status |= BD_DONE; + sdmac->buf_tail++; + sdmac->buf_tail %= sdmac->num_bd; ++ ++ if (sdmac->desc.callback) ++ sdmac->desc.callback(sdmac->desc.callback_param); + } + } + +@@ -673,9 +669,6 @@ + int channel = fls(stat) - 1; + struct sdma_channel *sdmac = &sdma->channel[channel]; + +- if (sdmac->flags & IMX_DMA_SG_LOOP) +- sdma_update_channel_loop(sdmac); +- + tasklet_schedule(&sdmac->tasklet); + + __clear_bit(channel, &stat); +@@ -1136,7 +1129,6 @@ + sdmac->status = DMA_IN_PROGRESS; + + sdmac->buf_tail = 0; +- sdmac->period_len = period_len; + + sdmac->flags |= IMX_DMA_SG_LOOP; + sdmac->direction = direction; +@@ -1233,15 +1225,9 @@ + struct dma_tx_state *txstate) + { + struct sdma_channel *sdmac = to_sdma_chan(chan); +- u32 residue; +- +- if (sdmac->flags & IMX_DMA_SG_LOOP) +- residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; +- else +- residue = sdmac->chn_count - sdmac->chn_real_count; + + dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, +- residue); ++ sdmac->chn_count - sdmac->chn_real_count); + + return sdmac->status; + } +diff -Nur linux-3.16.6.orig/drivers/dma/imx-sdma.c.orig linux-3.16.6/drivers/dma/imx-sdma.c.orig +--- linux-3.16.6.orig/drivers/dma/imx-sdma.c.orig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/dma/imx-sdma.c.orig 2014-10-15 05:05:43.000000000 -0500 +@@ -0,0 +1,1656 @@ ++/* ++ * drivers/dma/imx-sdma.c ++ * ++ * This file contains a driver for the Freescale Smart DMA engine ++ * ++ * Copyright 2010 Sascha Hauer, Pengutronix ++ * ++ * Based on code from Freescale: ++ * ++ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "dmaengine.h" ++ ++/* SDMA registers */ ++#define SDMA_H_C0PTR 0x000 ++#define SDMA_H_INTR 0x004 ++#define SDMA_H_STATSTOP 0x008 ++#define SDMA_H_START 0x00c ++#define SDMA_H_EVTOVR 0x010 ++#define SDMA_H_DSPOVR 0x014 ++#define SDMA_H_HOSTOVR 0x018 ++#define SDMA_H_EVTPEND 0x01c ++#define SDMA_H_DSPENBL 0x020 ++#define SDMA_H_RESET 0x024 ++#define SDMA_H_EVTERR 0x028 ++#define SDMA_H_INTRMSK 0x02c ++#define SDMA_H_PSW 0x030 ++#define SDMA_H_EVTERRDBG 0x034 ++#define SDMA_H_CONFIG 0x038 ++#define SDMA_ONCE_ENB 0x040 ++#define SDMA_ONCE_DATA 0x044 ++#define SDMA_ONCE_INSTR 0x048 ++#define SDMA_ONCE_STAT 0x04c ++#define SDMA_ONCE_CMD 0x050 ++#define SDMA_EVT_MIRROR 0x054 ++#define SDMA_ILLINSTADDR 0x058 ++#define SDMA_CHN0ADDR 0x05c ++#define SDMA_ONCE_RTB 0x060 ++#define SDMA_XTRIG_CONF1 0x070 ++#define SDMA_XTRIG_CONF2 0x074 ++#define SDMA_CHNENBL0_IMX35 0x200 ++#define SDMA_CHNENBL0_IMX31 0x080 ++#define SDMA_CHNPRI_0 0x100 ++ ++/* ++ * Buffer descriptor status values. ++ */ ++#define BD_DONE 0x01 ++#define BD_WRAP 0x02 ++#define BD_CONT 0x04 ++#define BD_INTR 0x08 ++#define BD_RROR 0x10 ++#define BD_LAST 0x20 ++#define BD_EXTD 0x80 ++ ++/* ++ * Data Node descriptor status values. ++ */ ++#define DND_END_OF_FRAME 0x80 ++#define DND_END_OF_XFER 0x40 ++#define DND_DONE 0x20 ++#define DND_UNUSED 0x01 ++ ++/* ++ * IPCV2 descriptor status values. ++ */ ++#define BD_IPCV2_END_OF_FRAME 0x40 ++ ++#define IPCV2_MAX_NODES 50 ++/* ++ * Error bit set in the CCB status field by the SDMA, ++ * in setbd routine, in case of a transfer error ++ */ ++#define DATA_ERROR 0x10000000 ++ ++/* ++ * Buffer descriptor commands. ++ */ ++#define C0_ADDR 0x01 ++#define C0_LOAD 0x02 ++#define C0_DUMP 0x03 ++#define C0_SETCTX 0x07 ++#define C0_GETCTX 0x03 ++#define C0_SETDM 0x01 ++#define C0_SETPM 0x04 ++#define C0_GETDM 0x02 ++#define C0_GETPM 0x08 ++/* ++ * Change endianness indicator in the BD command field ++ */ ++#define CHANGE_ENDIANNESS 0x80 ++ ++/* ++ * Mode/Count of data node descriptors - IPCv2 ++ */ ++struct sdma_mode_count { ++ u32 count : 16; /* size of the buffer pointed by this BD */ ++ u32 status : 8; /* E,R,I,C,W,D status bits stored here */ ++ u32 command : 8; /* command mostlky used for channel 0 */ ++}; ++ ++/* ++ * Buffer descriptor ++ */ ++struct sdma_buffer_descriptor { ++ struct sdma_mode_count mode; ++ u32 buffer_addr; /* address of the buffer described */ ++ u32 ext_buffer_addr; /* extended buffer address */ ++} __attribute__ ((packed)); ++ ++/** ++ * struct sdma_channel_control - Channel control Block ++ * ++ * @current_bd_ptr current buffer descriptor processed ++ * @base_bd_ptr first element of buffer descriptor array ++ * @unused padding. The SDMA engine expects an array of 128 byte ++ * control blocks ++ */ ++struct sdma_channel_control { ++ u32 current_bd_ptr; ++ u32 base_bd_ptr; ++ u32 unused[2]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct sdma_state_registers - SDMA context for a channel ++ * ++ * @pc: program counter ++ * @t: test bit: status of arithmetic & test instruction ++ * @rpc: return program counter ++ * @sf: source fault while loading data ++ * @spc: loop start program counter ++ * @df: destination fault while storing data ++ * @epc: loop end program counter ++ * @lm: loop mode ++ */ ++struct sdma_state_registers { ++ u32 pc :14; ++ u32 unused1: 1; ++ u32 t : 1; ++ u32 rpc :14; ++ u32 unused0: 1; ++ u32 sf : 1; ++ u32 spc :14; ++ u32 unused2: 1; ++ u32 df : 1; ++ u32 epc :14; ++ u32 lm : 2; ++} __attribute__ ((packed)); ++ ++/** ++ * struct sdma_context_data - sdma context specific to a channel ++ * ++ * @channel_state: channel state bits ++ * @gReg: general registers ++ * @mda: burst dma destination address register ++ * @msa: burst dma source address register ++ * @ms: burst dma status register ++ * @md: burst dma data register ++ * @pda: peripheral dma destination address register ++ * @psa: peripheral dma source address register ++ * @ps: peripheral dma status register ++ * @pd: peripheral dma data register ++ * @ca: CRC polynomial register ++ * @cs: CRC accumulator register ++ * @dda: dedicated core destination address register ++ * @dsa: dedicated core source address register ++ * @ds: dedicated core status register ++ * @dd: dedicated core data register ++ */ ++struct sdma_context_data { ++ struct sdma_state_registers channel_state; ++ u32 gReg[8]; ++ u32 mda; ++ u32 msa; ++ u32 ms; ++ u32 md; ++ u32 pda; ++ u32 psa; ++ u32 ps; ++ u32 pd; ++ u32 ca; ++ u32 cs; ++ u32 dda; ++ u32 dsa; ++ u32 ds; ++ u32 dd; ++ u32 scratch0; ++ u32 scratch1; ++ u32 scratch2; ++ u32 scratch3; ++ u32 scratch4; ++ u32 scratch5; ++ u32 scratch6; ++ u32 scratch7; ++} __attribute__ ((packed)); ++ ++#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor)) ++ ++struct sdma_engine; ++ ++/** ++ * struct sdma_channel - housekeeping for a SDMA channel ++ * ++ * @sdma pointer to the SDMA engine for this channel ++ * @channel the channel number, matches dmaengine chan_id + 1 ++ * @direction transfer type. Needed for setting SDMA script ++ * @peripheral_type Peripheral type. Needed for setting SDMA script ++ * @event_id0 aka dma request line ++ * @event_id1 for channels that use 2 events ++ * @word_size peripheral access size ++ * @buf_tail ID of the buffer that was processed ++ * @num_bd max NUM_BD. number of descriptors currently handling ++ */ ++struct sdma_channel { ++ struct sdma_engine *sdma; ++ unsigned int channel; ++ enum dma_transfer_direction direction; ++ enum sdma_peripheral_type peripheral_type; ++ unsigned int event_id0; ++ unsigned int event_id1; ++ enum dma_slave_buswidth word_size; ++ unsigned int buf_tail; ++ unsigned int num_bd; ++ unsigned int period_len; ++ struct sdma_buffer_descriptor *bd; ++ dma_addr_t bd_phys; ++ unsigned int pc_from_device, pc_to_device; ++ unsigned long flags; ++ dma_addr_t per_address; ++ unsigned long event_mask[2]; ++ unsigned long watermark_level; ++ u32 shp_addr, per_addr; ++ struct dma_chan chan; ++ spinlock_t lock; ++ struct dma_async_tx_descriptor desc; ++ enum dma_status status; ++ unsigned int chn_count; ++ unsigned int chn_real_count; ++ struct tasklet_struct tasklet; ++}; ++ ++#define IMX_DMA_SG_LOOP BIT(0) ++ ++#define MAX_DMA_CHANNELS 32 ++#define MXC_SDMA_DEFAULT_PRIORITY 1 ++#define MXC_SDMA_MIN_PRIORITY 1 ++#define MXC_SDMA_MAX_PRIORITY 7 ++ ++#define SDMA_FIRMWARE_MAGIC 0x414d4453 ++ ++/** ++ * struct sdma_firmware_header - Layout of the firmware image ++ * ++ * @magic "SDMA" ++ * @version_major increased whenever layout of struct sdma_script_start_addrs ++ * changes. ++ * @version_minor firmware minor version (for binary compatible changes) ++ * @script_addrs_start offset of struct sdma_script_start_addrs in this image ++ * @num_script_addrs Number of script addresses in this image ++ * @ram_code_start offset of SDMA ram image in this firmware image ++ * @ram_code_size size of SDMA ram image ++ * @script_addrs Stores the start address of the SDMA scripts ++ * (in SDMA memory space) ++ */ ++struct sdma_firmware_header { ++ u32 magic; ++ u32 version_major; ++ u32 version_minor; ++ u32 script_addrs_start; ++ u32 num_script_addrs; ++ u32 ram_code_start; ++ u32 ram_code_size; ++}; ++ ++struct sdma_driver_data { ++ int chnenbl0; ++ int num_events; ++ struct sdma_script_start_addrs *script_addrs; ++}; ++ ++struct sdma_engine { ++ struct device *dev; ++ struct device_dma_parameters dma_parms; ++ struct sdma_channel channel[MAX_DMA_CHANNELS]; ++ struct sdma_channel_control *channel_control; ++ void __iomem *regs; ++ struct sdma_context_data *context; ++ dma_addr_t context_phys; ++ struct dma_device dma_device; ++ struct clk *clk_ipg; ++ struct clk *clk_ahb; ++ spinlock_t channel_0_lock; ++ u32 script_number; ++ struct sdma_script_start_addrs *script_addrs; ++ const struct sdma_driver_data *drvdata; ++}; ++ ++static struct sdma_driver_data sdma_imx31 = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX31, ++ .num_events = 32, ++}; ++ ++static struct sdma_script_start_addrs sdma_script_imx25 = { ++ .ap_2_ap_addr = 729, ++ .uart_2_mcu_addr = 904, ++ .per_2_app_addr = 1255, ++ .mcu_2_app_addr = 834, ++ .uartsh_2_mcu_addr = 1120, ++ .per_2_shp_addr = 1329, ++ .mcu_2_shp_addr = 1048, ++ .ata_2_mcu_addr = 1560, ++ .mcu_2_ata_addr = 1479, ++ .app_2_per_addr = 1189, ++ .app_2_mcu_addr = 770, ++ .shp_2_per_addr = 1407, ++ .shp_2_mcu_addr = 979, ++}; ++ ++static struct sdma_driver_data sdma_imx25 = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX35, ++ .num_events = 48, ++ .script_addrs = &sdma_script_imx25, ++}; ++ ++static struct sdma_driver_data sdma_imx35 = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX35, ++ .num_events = 48, ++}; ++ ++static struct sdma_script_start_addrs sdma_script_imx51 = { ++ .ap_2_ap_addr = 642, ++ .uart_2_mcu_addr = 817, ++ .mcu_2_app_addr = 747, ++ .mcu_2_shp_addr = 961, ++ .ata_2_mcu_addr = 1473, ++ .mcu_2_ata_addr = 1392, ++ .app_2_per_addr = 1033, ++ .app_2_mcu_addr = 683, ++ .shp_2_per_addr = 1251, ++ .shp_2_mcu_addr = 892, ++}; ++ ++static struct sdma_driver_data sdma_imx51 = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX35, ++ .num_events = 48, ++ .script_addrs = &sdma_script_imx51, ++}; ++ ++static struct sdma_script_start_addrs sdma_script_imx53 = { ++ .ap_2_ap_addr = 642, ++ .app_2_mcu_addr = 683, ++ .mcu_2_app_addr = 747, ++ .uart_2_mcu_addr = 817, ++ .shp_2_mcu_addr = 891, ++ .mcu_2_shp_addr = 960, ++ .uartsh_2_mcu_addr = 1032, ++ .spdif_2_mcu_addr = 1100, ++ .mcu_2_spdif_addr = 1134, ++ .firi_2_mcu_addr = 1193, ++ .mcu_2_firi_addr = 1290, ++}; ++ ++static struct sdma_driver_data sdma_imx53 = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX35, ++ .num_events = 48, ++ .script_addrs = &sdma_script_imx53, ++}; ++ ++static struct sdma_script_start_addrs sdma_script_imx6q = { ++ .ap_2_ap_addr = 642, ++ .uart_2_mcu_addr = 817, ++ .mcu_2_app_addr = 747, ++ .per_2_per_addr = 6331, ++ .uartsh_2_mcu_addr = 1032, ++ .mcu_2_shp_addr = 960, ++ .app_2_mcu_addr = 683, ++ .shp_2_mcu_addr = 891, ++ .spdif_2_mcu_addr = 1100, ++ .mcu_2_spdif_addr = 1134, ++}; ++ ++static struct sdma_driver_data sdma_imx6q = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX35, ++ .num_events = 48, ++ .script_addrs = &sdma_script_imx6q, ++}; ++ ++static struct platform_device_id sdma_devtypes[] = { ++ { ++ .name = "imx25-sdma", ++ .driver_data = (unsigned long)&sdma_imx25, ++ }, { ++ .name = "imx31-sdma", ++ .driver_data = (unsigned long)&sdma_imx31, ++ }, { ++ .name = "imx35-sdma", ++ .driver_data = (unsigned long)&sdma_imx35, ++ }, { ++ .name = "imx51-sdma", ++ .driver_data = (unsigned long)&sdma_imx51, ++ }, { ++ .name = "imx53-sdma", ++ .driver_data = (unsigned long)&sdma_imx53, ++ }, { ++ .name = "imx6q-sdma", ++ .driver_data = (unsigned long)&sdma_imx6q, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(platform, sdma_devtypes); ++ ++static const struct of_device_id sdma_dt_ids[] = { ++ { .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, }, ++ { .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, }, ++ { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, }, ++ { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, }, ++ { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, }, ++ { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, sdma_dt_ids); ++ ++#define SDMA_H_CONFIG_DSPDMA BIT(12) /* indicates if the DSPDMA is used */ ++#define SDMA_H_CONFIG_RTD_PINS BIT(11) /* indicates if Real-Time Debug pins are enabled */ ++#define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq /core freq = 2 or 1 */ ++#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/ ++ ++static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event) ++{ ++ u32 chnenbl0 = sdma->drvdata->chnenbl0; ++ return chnenbl0 + event * 4; ++} ++ ++static int sdma_config_ownership(struct sdma_channel *sdmac, ++ bool event_override, bool mcu_override, bool dsp_override) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ unsigned long evt, mcu, dsp; ++ ++ if (event_override && mcu_override && dsp_override) ++ return -EINVAL; ++ ++ evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR); ++ mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR); ++ dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR); ++ ++ if (dsp_override) ++ __clear_bit(channel, &dsp); ++ else ++ __set_bit(channel, &dsp); ++ ++ if (event_override) ++ __clear_bit(channel, &evt); ++ else ++ __set_bit(channel, &evt); ++ ++ if (mcu_override) ++ __clear_bit(channel, &mcu); ++ else ++ __set_bit(channel, &mcu); ++ ++ writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR); ++ writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR); ++ writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR); ++ ++ return 0; ++} ++ ++static void sdma_enable_channel(struct sdma_engine *sdma, int channel) ++{ ++ writel(BIT(channel), sdma->regs + SDMA_H_START); ++} ++ ++/* ++ * sdma_run_channel0 - run a channel and wait till it's done ++ */ ++static int sdma_run_channel0(struct sdma_engine *sdma) ++{ ++ int ret; ++ unsigned long timeout = 500; ++ ++ sdma_enable_channel(sdma, 0); ++ ++ while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) { ++ if (timeout-- <= 0) ++ break; ++ udelay(1); ++ } ++ ++ if (ret) { ++ /* Clear the interrupt status */ ++ writel_relaxed(ret, sdma->regs + SDMA_H_INTR); ++ } else { ++ dev_err(sdma->dev, "Timeout waiting for CH0 ready\n"); ++ } ++ ++ return ret ? 0 : -ETIMEDOUT; ++} ++ ++static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, ++ u32 address) ++{ ++ struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; ++ void *buf_virt; ++ dma_addr_t buf_phys; ++ int ret; ++ unsigned long flags; ++ ++ buf_virt = dma_alloc_coherent(NULL, ++ size, ++ &buf_phys, GFP_KERNEL); ++ if (!buf_virt) { ++ return -ENOMEM; ++ } ++ ++ spin_lock_irqsave(&sdma->channel_0_lock, flags); ++ ++ bd0->mode.command = C0_SETPM; ++ bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; ++ bd0->mode.count = size / 2; ++ bd0->buffer_addr = buf_phys; ++ bd0->ext_buffer_addr = address; ++ ++ memcpy(buf_virt, buf, size); ++ ++ ret = sdma_run_channel0(sdma); ++ ++ spin_unlock_irqrestore(&sdma->channel_0_lock, flags); ++ ++ dma_free_coherent(NULL, size, buf_virt, buf_phys); ++ ++ return ret; ++} ++ ++static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ unsigned long val; ++ u32 chnenbl = chnenbl_ofs(sdma, event); ++ ++ val = readl_relaxed(sdma->regs + chnenbl); ++ __set_bit(channel, &val); ++ writel_relaxed(val, sdma->regs + chnenbl); ++} ++ ++static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ u32 chnenbl = chnenbl_ofs(sdma, event); ++ unsigned long val; ++ ++ val = readl_relaxed(sdma->regs + chnenbl); ++ __clear_bit(channel, &val); ++ writel_relaxed(val, sdma->regs + chnenbl); ++} ++ ++static void sdma_handle_channel_loop(struct sdma_channel *sdmac) ++{ ++ if (sdmac->desc.callback) ++ sdmac->desc.callback(sdmac->desc.callback_param); ++} ++ ++static void sdma_update_channel_loop(struct sdma_channel *sdmac) ++{ ++ struct sdma_buffer_descriptor *bd; ++ ++ /* ++ * loop mode. Iterate over descriptors, re-setup them and ++ * call callback function. ++ */ ++ while (1) { ++ bd = &sdmac->bd[sdmac->buf_tail]; ++ ++ if (bd->mode.status & BD_DONE) ++ break; ++ ++ if (bd->mode.status & BD_RROR) ++ sdmac->status = DMA_ERROR; ++ ++ bd->mode.status |= BD_DONE; ++ sdmac->buf_tail++; ++ sdmac->buf_tail %= sdmac->num_bd; ++ } ++} ++ ++static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) ++{ ++ struct sdma_buffer_descriptor *bd; ++ int i, error = 0; ++ ++ sdmac->chn_real_count = 0; ++ /* ++ * non loop mode. Iterate over all descriptors, collect ++ * errors and call callback function ++ */ ++ for (i = 0; i < sdmac->num_bd; i++) { ++ bd = &sdmac->bd[i]; ++ ++ if (bd->mode.status & (BD_DONE | BD_RROR)) ++ error = -EIO; ++ sdmac->chn_real_count += bd->mode.count; ++ } ++ ++ if (error) ++ sdmac->status = DMA_ERROR; ++ else ++ sdmac->status = DMA_COMPLETE; ++ ++ dma_cookie_complete(&sdmac->desc); ++ if (sdmac->desc.callback) ++ sdmac->desc.callback(sdmac->desc.callback_param); ++} ++ ++static void sdma_tasklet(unsigned long data) ++{ ++ struct sdma_channel *sdmac = (struct sdma_channel *) data; ++ ++ if (sdmac->flags & IMX_DMA_SG_LOOP) ++ sdma_handle_channel_loop(sdmac); ++ else ++ mxc_sdma_handle_channel_normal(sdmac); ++} ++ ++static irqreturn_t sdma_int_handler(int irq, void *dev_id) ++{ ++ struct sdma_engine *sdma = dev_id; ++ unsigned long stat; ++ ++ stat = readl_relaxed(sdma->regs + SDMA_H_INTR); ++ /* not interested in channel 0 interrupts */ ++ stat &= ~1; ++ writel_relaxed(stat, sdma->regs + SDMA_H_INTR); ++ ++ while (stat) { ++ int channel = fls(stat) - 1; ++ struct sdma_channel *sdmac = &sdma->channel[channel]; ++ ++ if (sdmac->flags & IMX_DMA_SG_LOOP) ++ sdma_update_channel_loop(sdmac); ++ ++ tasklet_schedule(&sdmac->tasklet); ++ ++ __clear_bit(channel, &stat); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * sets the pc of SDMA script according to the peripheral type ++ */ ++static void sdma_get_pc(struct sdma_channel *sdmac, ++ enum sdma_peripheral_type peripheral_type) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int per_2_emi = 0, emi_2_per = 0; ++ /* ++ * These are needed once we start to support transfers between ++ * two peripherals or memory-to-memory transfers ++ */ ++ int per_2_per = 0, emi_2_emi = 0; ++ ++ sdmac->pc_from_device = 0; ++ sdmac->pc_to_device = 0; ++ ++ switch (peripheral_type) { ++ case IMX_DMATYPE_MEMORY: ++ emi_2_emi = sdma->script_addrs->ap_2_ap_addr; ++ break; ++ case IMX_DMATYPE_DSP: ++ emi_2_per = sdma->script_addrs->bp_2_ap_addr; ++ per_2_emi = sdma->script_addrs->ap_2_bp_addr; ++ break; ++ case IMX_DMATYPE_FIRI: ++ per_2_emi = sdma->script_addrs->firi_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_firi_addr; ++ break; ++ case IMX_DMATYPE_UART: ++ per_2_emi = sdma->script_addrs->uart_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_app_addr; ++ break; ++ case IMX_DMATYPE_UART_SP: ++ per_2_emi = sdma->script_addrs->uartsh_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_shp_addr; ++ break; ++ case IMX_DMATYPE_ATA: ++ per_2_emi = sdma->script_addrs->ata_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_ata_addr; ++ break; ++ case IMX_DMATYPE_CSPI: ++ case IMX_DMATYPE_EXT: ++ case IMX_DMATYPE_SSI: ++ per_2_emi = sdma->script_addrs->app_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_app_addr; ++ break; ++ case IMX_DMATYPE_SSI_DUAL: ++ per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; ++ break; ++ case IMX_DMATYPE_SSI_SP: ++ case IMX_DMATYPE_MMC: ++ case IMX_DMATYPE_SDHC: ++ case IMX_DMATYPE_CSPI_SP: ++ case IMX_DMATYPE_ESAI: ++ case IMX_DMATYPE_MSHC_SP: ++ per_2_emi = sdma->script_addrs->shp_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_shp_addr; ++ break; ++ case IMX_DMATYPE_ASRC: ++ per_2_emi = sdma->script_addrs->asrc_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->asrc_2_mcu_addr; ++ per_2_per = sdma->script_addrs->per_2_per_addr; ++ break; ++ case IMX_DMATYPE_MSHC: ++ per_2_emi = sdma->script_addrs->mshc_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_mshc_addr; ++ break; ++ case IMX_DMATYPE_CCM: ++ per_2_emi = sdma->script_addrs->dptc_dvfs_addr; ++ break; ++ case IMX_DMATYPE_SPDIF: ++ per_2_emi = sdma->script_addrs->spdif_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_spdif_addr; ++ break; ++ case IMX_DMATYPE_IPU_MEMORY: ++ emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; ++ break; ++ default: ++ break; ++ } ++ ++ sdmac->pc_from_device = per_2_emi; ++ sdmac->pc_to_device = emi_2_per; ++} ++ ++static int sdma_load_context(struct sdma_channel *sdmac) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ int load_address; ++ struct sdma_context_data *context = sdma->context; ++ struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; ++ int ret; ++ unsigned long flags; ++ ++ if (sdmac->direction == DMA_DEV_TO_MEM) { ++ load_address = sdmac->pc_from_device; ++ } else { ++ load_address = sdmac->pc_to_device; ++ } ++ ++ if (load_address < 0) ++ return load_address; ++ ++ dev_dbg(sdma->dev, "load_address = %d\n", load_address); ++ dev_dbg(sdma->dev, "wml = 0x%08x\n", (u32)sdmac->watermark_level); ++ dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr); ++ dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr); ++ dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]); ++ dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]); ++ ++ spin_lock_irqsave(&sdma->channel_0_lock, flags); ++ ++ memset(context, 0, sizeof(*context)); ++ context->channel_state.pc = load_address; ++ ++ /* Send by context the event mask,base address for peripheral ++ * and watermark level ++ */ ++ context->gReg[0] = sdmac->event_mask[1]; ++ context->gReg[1] = sdmac->event_mask[0]; ++ context->gReg[2] = sdmac->per_addr; ++ context->gReg[6] = sdmac->shp_addr; ++ context->gReg[7] = sdmac->watermark_level; ++ ++ bd0->mode.command = C0_SETDM; ++ bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; ++ bd0->mode.count = sizeof(*context) / 4; ++ bd0->buffer_addr = sdma->context_phys; ++ bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel; ++ ret = sdma_run_channel0(sdma); ++ ++ spin_unlock_irqrestore(&sdma->channel_0_lock, flags); ++ ++ return ret; ++} ++ ++static void sdma_disable_channel(struct sdma_channel *sdmac) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ ++ writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP); ++ sdmac->status = DMA_ERROR; ++} ++ ++static int sdma_config_channel(struct sdma_channel *sdmac) ++{ ++ int ret; ++ ++ sdma_disable_channel(sdmac); ++ ++ sdmac->event_mask[0] = 0; ++ sdmac->event_mask[1] = 0; ++ sdmac->shp_addr = 0; ++ sdmac->per_addr = 0; ++ ++ if (sdmac->event_id0) { ++ if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events) ++ return -EINVAL; ++ sdma_event_enable(sdmac, sdmac->event_id0); ++ } ++ ++ switch (sdmac->peripheral_type) { ++ case IMX_DMATYPE_DSP: ++ sdma_config_ownership(sdmac, false, true, true); ++ break; ++ case IMX_DMATYPE_MEMORY: ++ sdma_config_ownership(sdmac, false, true, false); ++ break; ++ default: ++ sdma_config_ownership(sdmac, true, true, false); ++ break; ++ } ++ ++ sdma_get_pc(sdmac, sdmac->peripheral_type); ++ ++ if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && ++ (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { ++ /* Handle multiple event channels differently */ ++ if (sdmac->event_id1) { ++ sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32); ++ if (sdmac->event_id1 > 31) ++ __set_bit(31, &sdmac->watermark_level); ++ sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32); ++ if (sdmac->event_id0 > 31) ++ __set_bit(30, &sdmac->watermark_level); ++ } else { ++ __set_bit(sdmac->event_id0, sdmac->event_mask); ++ } ++ /* Watermark Level */ ++ sdmac->watermark_level |= sdmac->watermark_level; ++ /* Address */ ++ sdmac->shp_addr = sdmac->per_address; ++ } else { ++ sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ ++ } ++ ++ ret = sdma_load_context(sdmac); ++ ++ return ret; ++} ++ ++static int sdma_set_channel_priority(struct sdma_channel *sdmac, ++ unsigned int priority) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ ++ if (priority < MXC_SDMA_MIN_PRIORITY ++ || priority > MXC_SDMA_MAX_PRIORITY) { ++ return -EINVAL; ++ } ++ ++ writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel); ++ ++ return 0; ++} ++ ++static int sdma_request_channel(struct sdma_channel *sdmac) ++{ ++ struct sdma_engine *sdma = sdmac->sdma; ++ int channel = sdmac->channel; ++ int ret = -EBUSY; ++ ++ sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL); ++ if (!sdmac->bd) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memset(sdmac->bd, 0, PAGE_SIZE); ++ ++ sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys; ++ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; ++ ++ sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY); ++ return 0; ++out: ++ ++ return ret; ++} ++ ++static struct sdma_channel *to_sdma_chan(struct dma_chan *chan) ++{ ++ return container_of(chan, struct sdma_channel, chan); ++} ++ ++static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx) ++{ ++ unsigned long flags; ++ struct sdma_channel *sdmac = to_sdma_chan(tx->chan); ++ dma_cookie_t cookie; ++ ++ spin_lock_irqsave(&sdmac->lock, flags); ++ ++ cookie = dma_cookie_assign(tx); ++ ++ spin_unlock_irqrestore(&sdmac->lock, flags); ++ ++ return cookie; ++} ++ ++static int sdma_alloc_chan_resources(struct dma_chan *chan) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct imx_dma_data *data = chan->private; ++ int prio, ret; ++ ++ if (!data) ++ return -EINVAL; ++ ++ switch (data->priority) { ++ case DMA_PRIO_HIGH: ++ prio = 3; ++ break; ++ case DMA_PRIO_MEDIUM: ++ prio = 2; ++ break; ++ case DMA_PRIO_LOW: ++ default: ++ prio = 1; ++ break; ++ } ++ ++ sdmac->peripheral_type = data->peripheral_type; ++ sdmac->event_id0 = data->dma_request; ++ ++ clk_enable(sdmac->sdma->clk_ipg); ++ clk_enable(sdmac->sdma->clk_ahb); ++ ++ ret = sdma_request_channel(sdmac); ++ if (ret) ++ return ret; ++ ++ ret = sdma_set_channel_priority(sdmac, prio); ++ if (ret) ++ return ret; ++ ++ dma_async_tx_descriptor_init(&sdmac->desc, chan); ++ sdmac->desc.tx_submit = sdma_tx_submit; ++ /* txd.flags will be overwritten in prep funcs */ ++ sdmac->desc.flags = DMA_CTRL_ACK; ++ ++ return 0; ++} ++ ++static void sdma_free_chan_resources(struct dma_chan *chan) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct sdma_engine *sdma = sdmac->sdma; ++ ++ sdma_disable_channel(sdmac); ++ ++ if (sdmac->event_id0) ++ sdma_event_disable(sdmac, sdmac->event_id0); ++ if (sdmac->event_id1) ++ sdma_event_disable(sdmac, sdmac->event_id1); ++ ++ sdmac->event_id0 = 0; ++ sdmac->event_id1 = 0; ++ ++ sdma_set_channel_priority(sdmac, 0); ++ ++ dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); ++ ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++} ++ ++static struct dma_async_tx_descriptor *sdma_prep_slave_sg( ++ struct dma_chan *chan, struct scatterlist *sgl, ++ unsigned int sg_len, enum dma_transfer_direction direction, ++ unsigned long flags, void *context) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct sdma_engine *sdma = sdmac->sdma; ++ int ret, i, count; ++ int channel = sdmac->channel; ++ struct scatterlist *sg; ++ ++ if (sdmac->status == DMA_IN_PROGRESS) ++ return NULL; ++ sdmac->status = DMA_IN_PROGRESS; ++ ++ sdmac->flags = 0; ++ ++ sdmac->buf_tail = 0; ++ ++ dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", ++ sg_len, channel); ++ ++ sdmac->direction = direction; ++ ret = sdma_load_context(sdmac); ++ if (ret) ++ goto err_out; ++ ++ if (sg_len > NUM_BD) { ++ dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", ++ channel, sg_len, NUM_BD); ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ sdmac->chn_count = 0; ++ for_each_sg(sgl, sg, sg_len, i) { ++ struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; ++ int param; ++ ++ bd->buffer_addr = sg->dma_address; ++ ++ count = sg_dma_len(sg); ++ ++ if (count > 0xffff) { ++ dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n", ++ channel, count, 0xffff); ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ bd->mode.count = count; ++ sdmac->chn_count += count; ++ ++ if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) { ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ switch (sdmac->word_size) { ++ case DMA_SLAVE_BUSWIDTH_4_BYTES: ++ bd->mode.command = 0; ++ if (count & 3 || sg->dma_address & 3) ++ return NULL; ++ break; ++ case DMA_SLAVE_BUSWIDTH_2_BYTES: ++ bd->mode.command = 2; ++ if (count & 1 || sg->dma_address & 1) ++ return NULL; ++ break; ++ case DMA_SLAVE_BUSWIDTH_1_BYTE: ++ bd->mode.command = 1; ++ break; ++ default: ++ return NULL; ++ } ++ ++ param = BD_DONE | BD_EXTD | BD_CONT; ++ ++ if (i + 1 == sg_len) { ++ param |= BD_INTR; ++ param |= BD_LAST; ++ param &= ~BD_CONT; ++ } ++ ++ dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n", ++ i, count, (u64)sg->dma_address, ++ param & BD_WRAP ? "wrap" : "", ++ param & BD_INTR ? " intr" : ""); ++ ++ bd->mode.status = param; ++ } ++ ++ sdmac->num_bd = sg_len; ++ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; ++ ++ return &sdmac->desc; ++err_out: ++ sdmac->status = DMA_ERROR; ++ return NULL; ++} ++ ++static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( ++ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, ++ size_t period_len, enum dma_transfer_direction direction, ++ unsigned long flags, void *context) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct sdma_engine *sdma = sdmac->sdma; ++ int num_periods = buf_len / period_len; ++ int channel = sdmac->channel; ++ int ret, i = 0, buf = 0; ++ ++ dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); ++ ++ if (sdmac->status == DMA_IN_PROGRESS) ++ return NULL; ++ ++ sdmac->status = DMA_IN_PROGRESS; ++ ++ sdmac->buf_tail = 0; ++ sdmac->period_len = period_len; ++ ++ sdmac->flags |= IMX_DMA_SG_LOOP; ++ sdmac->direction = direction; ++ ret = sdma_load_context(sdmac); ++ if (ret) ++ goto err_out; ++ ++ if (num_periods > NUM_BD) { ++ dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", ++ channel, num_periods, NUM_BD); ++ goto err_out; ++ } ++ ++ if (period_len > 0xffff) { ++ dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n", ++ channel, period_len, 0xffff); ++ goto err_out; ++ } ++ ++ while (buf < buf_len) { ++ struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; ++ int param; ++ ++ bd->buffer_addr = dma_addr; ++ ++ bd->mode.count = period_len; ++ ++ if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) ++ goto err_out; ++ if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES) ++ bd->mode.command = 0; ++ else ++ bd->mode.command = sdmac->word_size; ++ ++ param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR; ++ if (i + 1 == num_periods) ++ param |= BD_WRAP; ++ ++ dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n", ++ i, period_len, (u64)dma_addr, ++ param & BD_WRAP ? "wrap" : "", ++ param & BD_INTR ? " intr" : ""); ++ ++ bd->mode.status = param; ++ ++ dma_addr += period_len; ++ buf += period_len; ++ ++ i++; ++ } ++ ++ sdmac->num_bd = num_periods; ++ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; ++ ++ return &sdmac->desc; ++err_out: ++ sdmac->status = DMA_ERROR; ++ return NULL; ++} ++ ++static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, ++ unsigned long arg) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct dma_slave_config *dmaengine_cfg = (void *)arg; ++ ++ switch (cmd) { ++ case DMA_TERMINATE_ALL: ++ sdma_disable_channel(sdmac); ++ return 0; ++ case DMA_SLAVE_CONFIG: ++ if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { ++ sdmac->per_address = dmaengine_cfg->src_addr; ++ sdmac->watermark_level = dmaengine_cfg->src_maxburst * ++ dmaengine_cfg->src_addr_width; ++ sdmac->word_size = dmaengine_cfg->src_addr_width; ++ } else { ++ sdmac->per_address = dmaengine_cfg->dst_addr; ++ sdmac->watermark_level = dmaengine_cfg->dst_maxburst * ++ dmaengine_cfg->dst_addr_width; ++ sdmac->word_size = dmaengine_cfg->dst_addr_width; ++ } ++ sdmac->direction = dmaengine_cfg->direction; ++ return sdma_config_channel(sdmac); ++ default: ++ return -ENOSYS; ++ } ++ ++ return -EINVAL; ++} ++ ++static enum dma_status sdma_tx_status(struct dma_chan *chan, ++ dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ u32 residue; ++ ++ if (sdmac->flags & IMX_DMA_SG_LOOP) ++ residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; ++ else ++ residue = sdmac->chn_count - sdmac->chn_real_count; ++ ++ dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, ++ residue); ++ ++ return sdmac->status; ++} ++ ++static void sdma_issue_pending(struct dma_chan *chan) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct sdma_engine *sdma = sdmac->sdma; ++ ++ if (sdmac->status == DMA_IN_PROGRESS) ++ sdma_enable_channel(sdma, sdmac->channel); ++} ++ ++#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 ++#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 ++ ++static void sdma_add_scripts(struct sdma_engine *sdma, ++ const struct sdma_script_start_addrs *addr) ++{ ++ s32 *addr_arr = (u32 *)addr; ++ s32 *saddr_arr = (u32 *)sdma->script_addrs; ++ int i; ++ ++ /* use the default firmware in ROM if missing external firmware */ ++ if (!sdma->script_number) ++ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; ++ ++ for (i = 0; i < sdma->script_number; i++) ++ if (addr_arr[i] > 0) ++ saddr_arr[i] = addr_arr[i]; ++} ++ ++static void sdma_load_firmware(const struct firmware *fw, void *context) ++{ ++ struct sdma_engine *sdma = context; ++ const struct sdma_firmware_header *header; ++ const struct sdma_script_start_addrs *addr; ++ unsigned short *ram_code; ++ ++ if (!fw) { ++ dev_err(sdma->dev, "firmware not found\n"); ++ return; ++ } ++ ++ if (fw->size < sizeof(*header)) ++ goto err_firmware; ++ ++ header = (struct sdma_firmware_header *)fw->data; ++ ++ if (header->magic != SDMA_FIRMWARE_MAGIC) ++ goto err_firmware; ++ if (header->ram_code_start + header->ram_code_size > fw->size) ++ goto err_firmware; ++ switch (header->version_major) { ++ case 1: ++ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; ++ break; ++ case 2: ++ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; ++ break; ++ default: ++ dev_err(sdma->dev, "unknown firmware version\n"); ++ goto err_firmware; ++ } ++ ++ addr = (void *)header + header->script_addrs_start; ++ ram_code = (void *)header + header->ram_code_start; ++ ++ clk_enable(sdma->clk_ipg); ++ clk_enable(sdma->clk_ahb); ++ /* download the RAM image for SDMA */ ++ sdma_load_script(sdma, ram_code, ++ header->ram_code_size, ++ addr->ram_code_start_addr); ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++ ++ sdma_add_scripts(sdma, addr); ++ ++ dev_info(sdma->dev, "loaded firmware %d.%d\n", ++ header->version_major, ++ header->version_minor); ++ ++err_firmware: ++ release_firmware(fw); ++} ++ ++static int __init sdma_get_firmware(struct sdma_engine *sdma, ++ const char *fw_name) ++{ ++ int ret; ++ ++ ret = request_firmware_nowait(THIS_MODULE, ++ FW_ACTION_HOTPLUG, fw_name, sdma->dev, ++ GFP_KERNEL, sdma, sdma_load_firmware); ++ ++ return ret; ++} ++ ++static int __init sdma_init(struct sdma_engine *sdma) ++{ ++ int i, ret; ++ dma_addr_t ccb_phys; ++ ++ clk_enable(sdma->clk_ipg); ++ clk_enable(sdma->clk_ahb); ++ ++ /* Be sure SDMA has not started yet */ ++ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); ++ ++ sdma->channel_control = dma_alloc_coherent(NULL, ++ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) + ++ sizeof(struct sdma_context_data), ++ &ccb_phys, GFP_KERNEL); ++ ++ if (!sdma->channel_control) { ++ ret = -ENOMEM; ++ goto err_dma_alloc; ++ } ++ ++ sdma->context = (void *)sdma->channel_control + ++ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); ++ sdma->context_phys = ccb_phys + ++ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); ++ ++ /* Zero-out the CCB structures array just allocated */ ++ memset(sdma->channel_control, 0, ++ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control)); ++ ++ /* disable all channels */ ++ for (i = 0; i < sdma->drvdata->num_events; i++) ++ writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i)); ++ ++ /* All channels have priority 0 */ ++ for (i = 0; i < MAX_DMA_CHANNELS; i++) ++ writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4); ++ ++ ret = sdma_request_channel(&sdma->channel[0]); ++ if (ret) ++ goto err_dma_alloc; ++ ++ sdma_config_ownership(&sdma->channel[0], false, true, false); ++ ++ /* Set Command Channel (Channel Zero) */ ++ writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR); ++ ++ /* Set bits of CONFIG register but with static context switching */ ++ /* FIXME: Check whether to set ACR bit depending on clock ratios */ ++ writel_relaxed(0, sdma->regs + SDMA_H_CONFIG); ++ ++ writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR); ++ ++ /* Set bits of CONFIG register with given context switching mode */ ++ writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG); ++ ++ /* Initializes channel's priorities */ ++ sdma_set_channel_priority(&sdma->channel[0], 7); ++ ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++ ++ return 0; ++ ++err_dma_alloc: ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++ dev_err(sdma->dev, "initialisation failed with %d\n", ret); ++ return ret; ++} ++ ++static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param) ++{ ++ struct imx_dma_data *data = fn_param; ++ ++ if (!imx_dma_is_general_purpose(chan)) ++ return false; ++ ++ chan->private = data; ++ ++ return true; ++} ++ ++static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, ++ struct of_dma *ofdma) ++{ ++ struct sdma_engine *sdma = ofdma->of_dma_data; ++ dma_cap_mask_t mask = sdma->dma_device.cap_mask; ++ struct imx_dma_data data; ++ ++ if (dma_spec->args_count != 3) ++ return NULL; ++ ++ data.dma_request = dma_spec->args[0]; ++ data.peripheral_type = dma_spec->args[1]; ++ data.priority = dma_spec->args[2]; ++ ++ return dma_request_channel(mask, sdma_filter_fn, &data); ++} ++ ++static int __init sdma_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *of_id = ++ of_match_device(sdma_dt_ids, &pdev->dev); ++ struct device_node *np = pdev->dev.of_node; ++ const char *fw_name; ++ int ret; ++ int irq; ++ struct resource *iores; ++ struct sdma_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ int i; ++ struct sdma_engine *sdma; ++ s32 *saddr_arr; ++ const struct sdma_driver_data *drvdata = NULL; ++ ++ if (of_id) ++ drvdata = of_id->data; ++ else if (pdev->id_entry) ++ drvdata = (void *)pdev->id_entry->driver_data; ++ ++ if (!drvdata) { ++ dev_err(&pdev->dev, "unable to find driver data\n"); ++ return -EINVAL; ++ } ++ ++ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); ++ if (ret) ++ return ret; ++ ++ sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); ++ if (!sdma) ++ return -ENOMEM; ++ ++ spin_lock_init(&sdma->channel_0_lock); ++ ++ sdma->dev = &pdev->dev; ++ sdma->drvdata = drvdata; ++ ++ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!iores || irq < 0) { ++ ret = -EINVAL; ++ goto err_irq; ++ } ++ ++ if (!request_mem_region(iores->start, resource_size(iores), pdev->name)) { ++ ret = -EBUSY; ++ goto err_request_region; ++ } ++ ++ sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); ++ if (IS_ERR(sdma->clk_ipg)) { ++ ret = PTR_ERR(sdma->clk_ipg); ++ goto err_clk; ++ } ++ ++ sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(sdma->clk_ahb)) { ++ ret = PTR_ERR(sdma->clk_ahb); ++ goto err_clk; ++ } ++ ++ clk_prepare(sdma->clk_ipg); ++ clk_prepare(sdma->clk_ahb); ++ ++ sdma->regs = ioremap(iores->start, resource_size(iores)); ++ if (!sdma->regs) { ++ ret = -ENOMEM; ++ goto err_ioremap; ++ } ++ ++ ret = request_irq(irq, sdma_int_handler, 0, "sdma", sdma); ++ if (ret) ++ goto err_request_irq; ++ ++ sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL); ++ if (!sdma->script_addrs) { ++ ret = -ENOMEM; ++ goto err_alloc; ++ } ++ ++ /* initially no scripts available */ ++ saddr_arr = (s32 *)sdma->script_addrs; ++ for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) ++ saddr_arr[i] = -EINVAL; ++ ++ dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask); ++ dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask); ++ ++ INIT_LIST_HEAD(&sdma->dma_device.channels); ++ /* Initialize channel parameters */ ++ for (i = 0; i < MAX_DMA_CHANNELS; i++) { ++ struct sdma_channel *sdmac = &sdma->channel[i]; ++ ++ sdmac->sdma = sdma; ++ spin_lock_init(&sdmac->lock); ++ ++ sdmac->chan.device = &sdma->dma_device; ++ dma_cookie_init(&sdmac->chan); ++ sdmac->channel = i; ++ ++ tasklet_init(&sdmac->tasklet, sdma_tasklet, ++ (unsigned long) sdmac); ++ /* ++ * Add the channel to the DMAC list. Do not add channel 0 though ++ * because we need it internally in the SDMA driver. This also means ++ * that channel 0 in dmaengine counting matches sdma channel 1. ++ */ ++ if (i) ++ list_add_tail(&sdmac->chan.device_node, ++ &sdma->dma_device.channels); ++ } ++ ++ ret = sdma_init(sdma); ++ if (ret) ++ goto err_init; ++ ++ if (sdma->drvdata->script_addrs) ++ sdma_add_scripts(sdma, sdma->drvdata->script_addrs); ++ if (pdata && pdata->script_addrs) ++ sdma_add_scripts(sdma, pdata->script_addrs); ++ ++ if (pdata) { ++ ret = sdma_get_firmware(sdma, pdata->fw_name); ++ if (ret) ++ dev_warn(&pdev->dev, "failed to get firmware from platform data\n"); ++ } else { ++ /* ++ * Because that device tree does not encode ROM script address, ++ * the RAM script in firmware is mandatory for device tree ++ * probe, otherwise it fails. ++ */ ++ ret = of_property_read_string(np, "fsl,sdma-ram-script-name", ++ &fw_name); ++ if (ret) ++ dev_warn(&pdev->dev, "failed to get firmware name\n"); ++ else { ++ ret = sdma_get_firmware(sdma, fw_name); ++ if (ret) ++ dev_warn(&pdev->dev, "failed to get firmware from device tree\n"); ++ } ++ } ++ ++ sdma->dma_device.dev = &pdev->dev; ++ ++ sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; ++ sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources; ++ sdma->dma_device.device_tx_status = sdma_tx_status; ++ sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; ++ sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; ++ sdma->dma_device.device_control = sdma_control; ++ sdma->dma_device.device_issue_pending = sdma_issue_pending; ++ sdma->dma_device.dev->dma_parms = &sdma->dma_parms; ++ dma_set_max_seg_size(sdma->dma_device.dev, 65535); ++ ++ ret = dma_async_device_register(&sdma->dma_device); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register\n"); ++ goto err_init; ++ } ++ ++ if (np) { ++ ret = of_dma_controller_register(np, sdma_xlate, sdma); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register controller\n"); ++ goto err_register; ++ } ++ } ++ ++ dev_info(sdma->dev, "initialized\n"); ++ ++ return 0; ++ ++err_register: ++ dma_async_device_unregister(&sdma->dma_device); ++err_init: ++ kfree(sdma->script_addrs); ++err_alloc: ++ free_irq(irq, sdma); ++err_request_irq: ++ iounmap(sdma->regs); ++err_ioremap: ++err_clk: ++ release_mem_region(iores->start, resource_size(iores)); ++err_request_region: ++err_irq: ++ kfree(sdma); ++ return ret; ++} ++ ++static int sdma_remove(struct platform_device *pdev) ++{ ++ return -EBUSY; ++} ++ ++static struct platform_driver sdma_driver = { ++ .driver = { ++ .name = "imx-sdma", ++ .of_match_table = sdma_dt_ids, ++ }, ++ .id_table = sdma_devtypes, ++ .remove = sdma_remove, ++}; ++ ++static int __init sdma_module_init(void) ++{ ++ return platform_driver_probe(&sdma_driver, sdma_probe); ++} ++module_init(sdma_module_init); ++ ++MODULE_AUTHOR("Sascha Hauer, Pengutronix "); ++MODULE_DESCRIPTION("i.MX SDMA driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-dc.c linux-3.16.6/drivers/gpu/ipu-v3/ipu-dc.c +--- linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-dc.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/gpu/ipu-v3/ipu-dc.c 2014-10-23 12:35:30.966220009 -0500 +@@ -93,6 +93,7 @@ + IPU_DC_MAP_BGR666, + IPU_DC_MAP_LVDS666, + IPU_DC_MAP_BGR24, ++ IPU_DC_MAP_RGB666, + }; + + struct ipu_dc { +@@ -161,6 +162,8 @@ + return IPU_DC_MAP_LVDS666; + case V4L2_PIX_FMT_BGR24: + return IPU_DC_MAP_BGR24; ++ case V4L2_PIX_FMT_RGB666: ++ return IPU_DC_MAP_RGB666; + default: + return -EINVAL; + } +@@ -452,6 +455,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.16.6.orig/drivers/gpu/ipu-v3/ipu-di.c linux-3.16.6/drivers/gpu/ipu-v3/ipu-di.c +--- linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-di.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/gpu/ipu-v3/ipu-di.c 2014-10-23 12:35:38.078220007 -0500 +@@ -595,7 +595,7 @@ + } + } + +- if (sig->clk_pol) ++ if (sig->clk_pol == CLK_POL_POSEDGE) + di_gen |= DI_GEN_POLARITY_DISP_CLK; + + ipu_di_write(di, di_gen, DI_GENERAL); +@@ -606,7 +606,7 @@ + reg = ipu_di_read(di, DI_POL); + reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); + +- if (sig->enable_pol) ++ if (sig->enable_pol == ENABLE_POL_HIGH) + reg |= DI_POL_DRDY_POLARITY_15; + if (sig->data_pol) + reg |= DI_POL_DRDY_DATA_POLARITY; +diff -Nur linux-3.16.6.orig/drivers/Kconfig linux-3.16.6/drivers/Kconfig +--- linux-3.16.6.orig/drivers/Kconfig 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/Kconfig 2014-10-23 12:37:18.314220004 -0500 +@@ -176,4 +176,6 @@ + + source "drivers/mcb/Kconfig" + ++source "drivers/cec/Kconfig" ++ + endmenu +diff -Nur linux-3.16.6.orig/drivers/Makefile linux-3.16.6/drivers/Makefile +--- linux-3.16.6.orig/drivers/Makefile 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/Makefile 2014-10-23 12:37:18.350220009 -0500 +@@ -158,3 +158,4 @@ + obj-$(CONFIG_FMC) += fmc/ + obj-$(CONFIG_POWERCAP) += powercap/ + obj-$(CONFIG_MCB) += mcb/ ++obj-$(CONFIG_CEC) += cec/ +diff -Nur linux-3.16.6.orig/drivers/mmc/core/core.c linux-3.16.6/drivers/mmc/core/core.c +--- linux-3.16.6.orig/drivers/mmc/core/core.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/mmc/core/core.c 2014-10-23 12:34:18.710219997 -0500 +@@ -13,11 +13,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -1515,6 +1517,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. +@@ -1531,6 +1570,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.16.6.orig/drivers/mmc/core/host.c linux-3.16.6/drivers/mmc/core/host.c +--- linux-3.16.6.orig/drivers/mmc/core/host.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/mmc/core/host.c 2014-10-23 12:34:34.134220000 -0500 +@@ -12,14 +12,18 @@ + * MMC host class device management + */ + ++#include ++#include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + #include + #include + +@@ -461,6 +465,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 +@@ -540,6 +604,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.16.6.orig/drivers/mmc/host/dw_mmc.c linux-3.16.6/drivers/mmc/host/dw_mmc.c +--- linux-3.16.6.orig/drivers/mmc/host/dw_mmc.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/mmc/host/dw_mmc.c 2014-10-23 12:34:26.238219996 -0500 +@@ -2049,6 +2049,8 @@ + if (!mmc) + return -ENOMEM; + ++ mmc_of_parse(mmc); ++ + slot = mmc_priv(mmc); + slot->id = id; + slot->mmc = mmc; +diff -Nur linux-3.16.6.orig/drivers/mmc/host/Kconfig linux-3.16.6/drivers/mmc/host/Kconfig +--- linux-3.16.6.orig/drivers/mmc/host/Kconfig 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/mmc/host/Kconfig 2014-10-23 12:34:04.318220041 -0500 +@@ -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 || MACH_DOVE +- depends on MMC_SDHCI_PLTFM ++ depends on (ARCH_DOVE || MACH_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,8 @@ + + config MMC_SDHCI_PXAV3 + tristate "Marvell MMP2 SD Host Controller support (PXAV3)" +- depends on CLKDEV_LOOKUP +- depends on MMC_SDHCI_PLTFM ++ depends on CLKDEV_LOOKUP && HAS_DMA ++ select MMC_SDHCI_PLTFM + default CPU_MMP2 + help + This selects the Marvell(R) PXAV3 SD Host Controller. +@@ -227,8 +229,8 @@ + + config MMC_SDHCI_PXAV2 + tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" +- depends on CLKDEV_LOOKUP +- depends on MMC_SDHCI_PLTFM ++ depends on CLKDEV_LOOKUP && HAS_DMA ++ select MMC_SDHCI_PLTFM + default CPU_PXA910 + help + This selects the Marvell(R) PXAV2 SD Host Controller. +@@ -239,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 +@@ -261,8 +264,8 @@ + + config MMC_SDHCI_BCM_KONA + tristate "SDHCI support on Broadcom KONA platform" +- depends on ARCH_BCM_MOBILE +- depends on MMC_SDHCI_PLTFM ++ depends on ARCH_BCM_MOBILE && HAS_DMA ++ select MMC_SDHCI_PLTFM + help + This selects the Broadcom Kona Secure Digital Host Controller + Interface(SDHCI) support. +@@ -272,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.16.6.orig/drivers/mmc/host/sdhci.c linux-3.16.6/drivers/mmc/host/sdhci.c +--- linux-3.16.6.orig/drivers/mmc/host/sdhci.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/mmc/host/sdhci.c 2014-10-23 12:34:10.650220104 -0500 +@@ -1530,7 +1530,6 @@ + host->ops->set_clock(host, host->clock); + } + +- + /* Reset SD Clock Enable */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; +@@ -1763,9 +1762,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) +diff -Nur linux-3.16.6.orig/drivers/regulator/anatop-regulator.c linux-3.16.6/drivers/regulator/anatop-regulator.c +--- linux-3.16.6.orig/drivers/regulator/anatop-regulator.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/regulator/anatop-regulator.c 2014-10-23 12:36:22.798219997 -0500 +@@ -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.16.6.orig/drivers/regulator/core.c linux-3.16.6/drivers/regulator/core.c +--- linux-3.16.6.orig/drivers/regulator/core.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/regulator/core.c 2014-10-23 12:36:22.802220004 -0500 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -77,7 +78,7 @@ + */ + struct regulator_enable_gpio { + struct list_head list; +- int gpio; ++ struct gpio_desc *gpiod; + u32 enable_count; /* a number of enabled shared GPIO */ + u32 request_count; /* a number of requested shared GPIO */ + unsigned int ena_gpio_invert:1; +@@ -1660,10 +1661,13 @@ + const struct regulator_config *config) + { + struct regulator_enable_gpio *pin; ++ struct gpio_desc *gpiod; + int ret; + ++ gpiod = gpio_to_desc(config->ena_gpio); ++ + list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { +- if (pin->gpio == config->ena_gpio) { ++ if (pin->gpiod == gpiod) { + rdev_dbg(rdev, "GPIO %d is already used\n", + config->ena_gpio); + goto update_ena_gpio_to_rdev; +@@ -1682,7 +1686,7 @@ + return -ENOMEM; + } + +- pin->gpio = config->ena_gpio; ++ pin->gpiod = gpiod; + pin->ena_gpio_invert = config->ena_gpio_invert; + list_add(&pin->list, ®ulator_ena_gpio_list); + +@@ -1701,10 +1705,10 @@ + + /* Free the GPIO only in case of no use */ + list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { +- if (pin->gpio == rdev->ena_pin->gpio) { ++ if (pin->gpiod == rdev->ena_pin->gpiod) { + if (pin->request_count <= 1) { + pin->request_count = 0; +- gpio_free(pin->gpio); ++ gpiod_put(pin->gpiod); + list_del(&pin->list); + kfree(pin); + } else { +@@ -1732,8 +1736,8 @@ + if (enable) { + /* Enable GPIO at initial use */ + if (pin->enable_count == 0) +- gpio_set_value_cansleep(pin->gpio, +- !pin->ena_gpio_invert); ++ gpiod_set_value_cansleep(pin->gpiod, ++ !pin->ena_gpio_invert); + + pin->enable_count++; + } else { +@@ -1744,8 +1748,8 @@ + + /* Disable GPIO if not used */ + if (pin->enable_count <= 1) { +- gpio_set_value_cansleep(pin->gpio, +- pin->ena_gpio_invert); ++ gpiod_set_value_cansleep(pin->gpiod, ++ pin->ena_gpio_invert); + pin->enable_count = 0; + } + } +@@ -3470,7 +3474,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.16.6.orig/drivers/regulator/dummy.c linux-3.16.6/drivers/regulator/dummy.c +--- linux-3.16.6.orig/drivers/regulator/dummy.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/regulator/dummy.c 2014-10-23 12:36:22.810220006 -0500 +@@ -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.16.6.orig/drivers/regulator/fixed.c linux-3.16.6/drivers/regulator/fixed.c +--- linux-3.16.6.orig/drivers/regulator/fixed.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/regulator/fixed.c 2014-10-23 12:36:22.810220006 -0500 +@@ -156,9 +156,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.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.c linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.c +--- linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.c 2014-10-23 12:37:30.178219970 -0500 +@@ -0,0 +1,88 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include "drm-ddc-connector.h" ++ ++enum drm_connector_status ++drm_ddc_connector_always_connected(struct drm_connector *connector, bool force) ++{ ++ return connector_status_connected; ++} ++EXPORT_SYMBOL_GPL(drm_ddc_connector_always_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); ++ ++void drm_ddc_connector_destroy(struct drm_connector *connector) ++{ ++ struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector); ++ ++ pr_info("%s: %p\n", __func__, ddc_conn); ++ ++ drm_sysfs_connector_remove(connector); ++ drm_connector_cleanup(connector); ++ if (ddc_conn->ddc) ++ i2c_put_adapter(ddc_conn->ddc); ++ kfree(ddc_conn); ++} ++EXPORT_SYMBOL_GPL(drm_ddc_connector_destroy); ++ ++void drm_ddc_connector_add(struct drm_device *drm, ++ struct drm_ddc_connector *ddc_conn, ++ struct drm_connector_funcs *funcs, int connector_type) ++{ ++ drm_connector_init(drm, &ddc_conn->connector, funcs, connector_type); ++} ++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 = kzalloc(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) { ++ kfree(ddc_conn); ++ return ERR_PTR(-EPROBE_DEFER); ++ } ++ } ++ ++ return ddc_conn; ++} ++EXPORT_SYMBOL_GPL(drm_ddc_connector_create); ++ ++MODULE_AUTHOR("Russell King "); ++MODULE_DESCRIPTION("Generic DRM DDC connector module"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.h linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.h +--- linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.h 2014-10-23 12:37:30.178219970 -0500 +@@ -0,0 +1,31 @@ ++#ifndef DRM_DDC_CONNECTOR_H ++#define DRM_DDC_CONNECTOR_H ++ ++#include ++ ++struct drm_ddc_connector { ++ struct i2c_adapter *ddc; ++ struct drm_connector connector; ++ void *private; ++}; ++ ++#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector) ++ ++enum drm_connector_status drm_ddc_connector_always_connected( ++ struct drm_connector *connector, bool force); ++int drm_ddc_connector_get_modes(struct drm_connector *connector); ++void drm_ddc_connector_add(struct drm_device *drm, ++ struct drm_ddc_connector *ddc_conn, ++ struct drm_connector_funcs *funcs, int connector_type); ++void drm_ddc_connector_destroy(struct drm_connector *connector); ++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.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.c +--- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.c 2014-10-23 12:37:11.394219951 -0500 +@@ -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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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); ++ synchronize_irq(dw->data.irq); ++} ++ ++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); ++ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); ++ ++ 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 "); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.h +--- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.h 2014-10-23 12:36:44.258220010 -0500 +@@ -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.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.c +--- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.c 2014-10-23 12:37:23.890220362 -0500 +@@ -0,0 +1,207 @@ ++/* 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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); ++ ++ platform_set_drvdata(pdev, cec); ++ ++ /* ++ * 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 "); ++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.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.h +--- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.h 2014-10-23 12:37:23.890220362 -0500 +@@ -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.16.6.orig/drivers/staging/imx-drm/imx-drm-core.c linux-3.16.6/drivers/staging/imx-drm/imx-drm-core.c +--- linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm-core.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/staging/imx-drm/imx-drm-core.c 2014-10-23 12:37:37.690220197 -0500 +@@ -115,8 +115,7 @@ + helper = &imx_crtc->imx_drm_helper_funcs; + if (helper->set_interface_pix_fmt) + return helper->set_interface_pix_fmt(encoder->crtc, +- encoder->encoder_type, interface_pix_fmt, +- hsync_pin, vsync_pin); ++ interface_pix_fmt, hsync_pin, vsync_pin); + return 0; + } + EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); +diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm.h linux-3.16.6/drivers/staging/imx-drm/imx-drm.h +--- linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm.h 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/staging/imx-drm/imx-drm.h 2014-10-23 12:37:37.690220197 -0500 +@@ -17,7 +17,7 @@ + struct imx_drm_crtc_helper_funcs { + int (*enable_vblank)(struct drm_crtc *crtc); + void (*disable_vblank)(struct drm_crtc *crtc); +- int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type, ++ int (*set_interface_pix_fmt)(struct drm_crtc *crtc, + u32 pix_fmt, int hsync_pin, int vsync_pin); + const struct drm_crtc_helper_funcs *crtc_helper_funcs; + const struct drm_crtc_funcs *crtc_funcs; +diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-hdmi.c linux-3.16.6/drivers/staging/imx-drm/imx-hdmi.c +--- linux-3.16.6.orig/drivers/staging/imx-drm/imx-hdmi.c 2014-10-15 05:05:43.000000000 -0500 ++++ linux-3.16.6/drivers/staging/imx-drm/imx-hdmi.c 2014-10-23 12:37:30.178219970 -0500 +@@ -29,6 +29,9 @@ + #include + #include