summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/boot/dts/Makefile2
-rw-r--r--arch/arm/boot/dts/vf-colibri-dual-eth.dtsi91
-rw-r--r--arch/arm/boot/dts/vf-colibri-eval-v3.dtsi179
-rw-r--r--arch/arm/boot/dts/vf-colibri.dtsi205
-rw-r--r--arch/arm/boot/dts/vf500-colibri-dual-eth.dts17
-rw-r--r--arch/arm/boot/dts/vf500-colibri-eval-v3.dts4
-rw-r--r--arch/arm/boot/dts/vf500-colibri.dtsi45
-rw-r--r--arch/arm/boot/dts/vf500.dtsi10
-rw-r--r--arch/arm/boot/dts/vf610-colibri-dual-eth.dts17
-rw-r--r--arch/arm/boot/dts/vf610-colibri.dtsi84
-rw-r--r--arch/arm/boot/dts/vf610-cosmic.dts2
-rw-r--r--arch/arm/boot/dts/vf610-pinfunc.h2
-rw-r--r--arch/arm/boot/dts/vf610-twr.dts111
-rw-r--r--arch/arm/boot/dts/vfxxx.dtsi200
-rw-r--r--arch/arm/configs/colibri_vf_defconfig317
-rw-r--r--arch/arm/mach-imx/Makefile5
-rw-r--r--arch/arm/mach-imx/clk-gate2.c7
-rw-r--r--arch/arm/mach-imx/clk-vf610.c115
-rw-r--r--arch/arm/mach-imx/clk.h13
-rw-r--r--arch/arm/mach-imx/common.h11
-rw-r--r--arch/arm/mach-imx/mach-vf610.c8
-rw-r--r--arch/arm/mach-imx/pm-vf610.c661
-rw-r--r--arch/arm/mach-imx/suspend-vf610.S448
-rw-r--r--arch/arm/mach-imx/vf610_sema4.c314
24 files changed, 2827 insertions, 41 deletions
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 992736b5229b..ff9f6564d057 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -319,6 +319,8 @@ dtb-$(CONFIG_SOC_LS1021A) += \
dtb-$(CONFIG_SOC_VF610) += \
vf500-colibri-eval-v3.dtb \
vf610-colibri-eval-v3.dtb \
+ vf500-colibri-dual-eth.dtb \
+ vf610-colibri-dual-eth.dtb \
vf610-cosmic.dtb \
vf610-twr.dtb
dtb-$(CONFIG_ARCH_MXS) += \
diff --git a/arch/arm/boot/dts/vf-colibri-dual-eth.dtsi b/arch/arm/boot/dts/vf-colibri-dual-eth.dtsi
new file mode 100644
index 000000000000..8fed7304276a
--- /dev/null
+++ b/arch/arm/boot/dts/vf-colibri-dual-eth.dtsi
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/ {
+ chosen {
+ bootargs = "console=ttyLP0,115200";
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ ethernet0 = &fec0;
+ ethernet1 = &fec1;
+ };
+};
+
+&fec0 {
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec0>;
+ status = "okay";
+};
+
+&fec1 {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&iomuxc {
+ vf610-colibri {
+ pinctrl_fec0: fec0grp {
+ fsl,pins = <
+ VF610_PAD_PTA9__RMII_CLKOUT 0x30d2
+ VF610_PAD_PTC0__ENET_RMII0_MDC 0x30d2
+ VF610_PAD_PTC1__ENET_RMII0_MDIO 0x30d3
+ VF610_PAD_PTC2__ENET_RMII0_CRS 0x30d1
+ VF610_PAD_PTC3__ENET_RMII0_RXD1 0x30d1
+ VF610_PAD_PTC4__ENET_RMII0_RXD0 0x30d1
+ VF610_PAD_PTC5__ENET_RMII0_RXER 0x30d1
+ VF610_PAD_PTC6__ENET_RMII0_TXD1 0x30d2
+ VF610_PAD_PTC7__ENET_RMII0_TXD0 0x30d2
+ VF610_PAD_PTC8__ENET_RMII0_TXEN 0x30d2
+ /* Disable pads multiplexed with PTC7/PTC6 */
+ VF610_PAD_PTB0__GPIO_22 0x0000
+ VF610_PAD_PTB9__GPIO_31 0x0000
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ VF610_PAD_PTA20__UART3_TX 0x21a2
+ VF610_PAD_PTA21__UART3_RX 0x21a1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ VF610_PAD_PTA28__UART4_TX 0x21a2
+ VF610_PAD_PTA29__UART4_RX 0x21a1
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
index 606753eb72c8..a1adb069cf44 100644
--- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Toradex AG
+ * Copyright 2014-2015 Toradex AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -7,9 +7,12 @@
* (at your option) any later version.
*/
+#include <dt-bindings/input/input.h>
+
/ {
chosen {
bootargs = "console=ttyLP0,115200";
+ stdout-path = "serial0:115200n8";
};
clk16m: clk16m {
@@ -18,11 +21,23 @@
clock-frequency = <16000000>;
};
- regulators {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <0>;
+ bl_on {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_bl_on>;
+ compatible = "gpio-backlight";
+ gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+ default-on;
+ };
+
+ extcon_usbc_det: usbc_det {
+ compatible = "linux,extcon-usb-gpio";
+ debounce = <25>;
+ id-gpio = <&gpio3 6 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbc_det>;
+ };
+ regulators {
sys_5v0_reg: regulator@0 {
compatible = "regulator-fixed";
reg = <0>;
@@ -45,6 +60,20 @@
vin-supply = <&sys_5v0_reg>;
};
};
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpiokeys>;
+
+ power {
+ label = "Wake-Up";
+ gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+ linux,code = <KEY_WAKEUP>;
+ debounce-interval = <10>;
+ gpio-key,wakeup;
+ };
+ };
};
&bl {
@@ -53,6 +82,111 @@
status = "okay";
};
+&dcu0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dcu0_1>;
+ display = <&display>;
+ status = "okay";
+
+ display: display@0 {
+ bits-per-pixel = <16>;
+
+ display-timings {
+ native-mode = <&timing_vga>;
+ /* Standard VGA timing */
+ timing_vga: 640x480 {
+ clock-frequency = <25175000>;
+ hactive = <640>;
+ vactive = <480>;
+ hback-porch = <40>;
+ hfront-porch = <24>;
+ vback-porch = <32>;
+ vfront-porch = <11>;
+ hsync-len = <96>;
+ vsync-len = <2>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pixelclk-active = <0>;
+ };
+ /* WVGA Timing, e.g. EDT ET070080DH6 */
+ timing_wvga: 800x480 {
+ clock-frequency = <33260000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <216>;
+ hfront-porch = <40>;
+ vback-porch = <35>;
+ vfront-porch = <10>;
+ hsync-len = <128>;
+ vsync-len = <2>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pixelclk-active = <0>;
+ };
+ /* WVGA Timing, TouchRevolution Fusion 7" */
+ timing_wvga2: 800x480pixclkact {
+ clock-frequency = <33260000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <216>;
+ hfront-porch = <40>;
+ vback-porch = <35>;
+ vfront-porch = <10>;
+ hsync-len = <128>;
+ vsync-len = <2>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pixelclk-active = <1>;
+ };
+ /* Standard SVGA timing */
+ timing_svga: 800x600 {
+ clock-frequency = <40000000>;
+ hactive = <800>;
+ vactive = <600>;
+ hback-porch = <88>;
+ hfront-porch = <40>;
+ vback-porch = <23>;
+ vfront-porch = <1>;
+ hsync-len = <128>;
+ vsync-len = <4>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ pixelclk-active = <0>;
+ };
+ /* TouchRevolution Fusion 10"/CLAA101NC05 10.1 inch */
+ timing_wsvga: 1024x600 {
+ clock-frequency = <48000000>;
+ hactive = <1024>;
+ vactive = <600>;
+ hback-porch = <104>;
+ hfront-porch = <43>;
+ vback-porch = <24>;
+ vfront-porch = <20>;
+ hsync-len = <5>;
+ vsync-len = <5>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pixelclk-active = <0>;
+ };
+ /* Standard XGA timing */
+ timing_xga: 1024x768 {
+ clock-frequency = <65000000>;
+ hactive = <1024>;
+ vactive = <768>;
+ hback-porch = <160>;
+ hfront-porch = <24>;
+ vback-porch = <29>;
+ vfront-porch = <3>;
+ hsync-len = <136>;
+ vsync-len = <6>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pixelclk-active = <0>;
+ };
+ };
+ };
+};
+
&dspi1 {
status = "okay";
@@ -85,6 +219,20 @@
&i2c0 {
status = "okay";
+ /* TouchRevolution Fusion 7 and 10 multi-touch controller */
+ touch: touchrevf0710a@10 {
+ compatible = "touchrevolution,fusion-f0710a";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpiotouch>;
+ reg = <0x10>;
+ /* SODIMM 28, Pen down interrupt */
+ gpios = <&gpio0 30 GPIO_ACTIVE_HIGH
+ /* SODIMM 30, Reset interrupt */
+ &gpio0 23 GPIO_ACTIVE_LOW
+ >;
+ status = "disabled";
+ };
+
/* M41T0M6 real time clock on carrier board */
rtc: m41t0m6@68 {
compatible = "st,m41t00";
@@ -100,6 +248,10 @@
status = "okay";
};
+&tcon0 {
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
@@ -112,6 +264,10 @@
status = "okay";
};
+&usbdev0 {
+ extcon = <&extcon_usbc_det>;
+};
+
&usbh1 {
vbus-supply = <&usbh_vbus_reg>;
};
@@ -123,5 +279,18 @@
VF610_PAD_PTB21__GPIO_43 0x22ed
>;
};
+
+ pinctrl_gpiokeys: gpiokeys {
+ fsl,pins = <
+ VF610_PAD_PTB19__GPIO_41 0x218d
+ >;
+ };
+
+ pinctrl_gpiotouch: touchgpios {
+ fsl,pins = <
+ VF610_PAD_PTB8__GPIO_30 0x6f
+ VF610_PAD_PTB1__GPIO_23 0x4f
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index fbef0828e930..783ea2a062b5 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -13,14 +13,51 @@
pwms = <&pwm0 0 5000000 0>;
status = "disabled";
};
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sys_3v3_reg: regulator@100 {
+ compatible = "regulator-fixed";
+ reg = <100>;
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ sys_3v3_avdd_reg: regulator@101 {
+ compatible = "regulator-fixed";
+ reg = <101>;
+ regulator-name = "AVDD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
};
&adc0 {
status = "okay";
+ vref-supply = <&sys_3v3_avdd_reg>;
};
&adc1 {
status = "okay";
+ vref-supply = <&sys_3v3_avdd_reg>;
+};
+
+&can0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan0>;
+ status = "disabled";
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "disabled";
};
&dspi1 {
@@ -42,6 +79,7 @@
&fec1 {
phy-mode = "rmii";
+ phy-supply = <&sys_3v3_reg>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fec1>;
};
@@ -52,14 +90,34 @@
pinctrl-0 = <&pinctrl_i2c0>;
};
+&nfc {
+ assigned-clocks = <&clks VF610_CLK_NFC>;
+ assigned-clock-rates = <33000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nfc>;
+ status = "okay";
+
+ nand@0 {
+ compatible = "fsl,vf610-nfc-nandcs";
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ nand-ecc-strength = <32>;
+ nand-ecc-step-size = <2048>;
+ nand-on-flash-bbt;
+ };
+};
+
&pwm0 {
pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_pwm0>;
+ pinctrl-0 = <&pinctrl_pwm0_a &pinctrl_pwm0_c>;
};
&pwm1 {
pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_pwm1>;
+ pinctrl-0 = <&pinctrl_pwm1_b &pinctrl_pwm1_d>;
};
&uart0 {
@@ -79,6 +137,7 @@
&usbdev0 {
disable-over-current;
+ dr_mode = "otg";
status = "okay";
};
@@ -105,11 +164,96 @@
&iomuxc {
vf610-colibri {
- pinctrl_gpio_ext: gpio_ext {
+ pinctrl_additionalgpio: additionalgpios {
+ fsl,pins = <
+ VF610_PAD_PTA12__GPIO_5 0x22ed
+ VF610_PAD_PTA17__GPIO_7 0x22ed
+ VF610_PAD_PTA20__GPIO_10 0x22ed
+ VF610_PAD_PTA21__GPIO_11 0x22ed
+ VF610_PAD_PTA30__GPIO_20 0x22ed
+ VF610_PAD_PTA31__GPIO_21 0x22ed
+ VF610_PAD_PTB6__GPIO_28 0x22ed
+ VF610_PAD_PTB7__GPIO_29 0x22ed
+ VF610_PAD_PTB12__GPIO_34 0x22ed
+ VF610_PAD_PTB13__GPIO_35 0x22ed
+ VF610_PAD_PTB16__GPIO_38 0x22ed
+ VF610_PAD_PTB17__GPIO_39 0x22ed
+ VF610_PAD_PTB18__GPIO_40 0x22ed
+ VF610_PAD_PTB21__GPIO_43 0x22ed
+ VF610_PAD_PTB22__GPIO_44 0x22ed
+ VF610_PAD_PTC1__GPIO_46 0x22ed
+ VF610_PAD_PTC2__GPIO_47 0x22ed
+ VF610_PAD_PTC3__GPIO_48 0x22ed
+ VF610_PAD_PTC4__GPIO_49 0x22ed
+ VF610_PAD_PTC5__GPIO_50 0x22ed
+ VF610_PAD_PTC6__GPIO_51 0x22ed
+ VF610_PAD_PTC7__GPIO_52 0x22ed
+ VF610_PAD_PTC8__GPIO_53 0x22ed
+ VF610_PAD_PTD31__GPIO_63 0x22ed
+ VF610_PAD_PTD30__GPIO_64 0x22ed
+ VF610_PAD_PTD29__GPIO_65 0x22ed
+ VF610_PAD_PTD28__GPIO_66 0x22ed
+ VF610_PAD_PTD27__GPIO_67 0x22ed
+ VF610_PAD_PTD26__GPIO_68 0x22ed
+ VF610_PAD_PTD25__GPIO_69 0x22ed
+ VF610_PAD_PTD24__GPIO_70 0x22ed
+ VF610_PAD_PTD9__GPIO_88 0x22ed
+ VF610_PAD_PTD10__GPIO_89 0x22ed
+ VF610_PAD_PTD11__GPIO_90 0x22ed
+ VF610_PAD_PTD12__GPIO_91 0x22ed
+ VF610_PAD_PTD13__GPIO_92 0x22ed
+ VF610_PAD_PTB23__GPIO_93 0x22ed
+ VF610_PAD_PTB26__GPIO_96 0x22ed
+ VF610_PAD_PTB28__GPIO_98 0x22ed
+ VF610_PAD_PTC30__GPIO_103 0x22ed
+ VF610_PAD_PTA7__GPIO_134 0x22ed
+ >;
+ };
+
+ pinctrl_flexcan0: can0grp {
+ fsl,pins = <
+ VF610_PAD_PTB14__CAN0_RX 0x31F1
+ VF610_PAD_PTB15__CAN0_TX 0x31F2
+ >;
+ };
+
+ pinctrl_flexcan1: can1grp {
fsl,pins = <
- VF610_PAD_PTD10__GPIO_89 0x22ed /* EXT_IO_0 */
- VF610_PAD_PTD9__GPIO_88 0x22ed /* EXT_IO_1 */
- VF610_PAD_PTD26__GPIO_68 0x22ed /* EXT_IO_2 */
+ VF610_PAD_PTB16__CAN1_RX 0x31F1
+ VF610_PAD_PTB17__CAN1_TX 0x31F2
+ >;
+ };
+
+ pinctrl_dcu0_1: dcu0grp_1 {
+ fsl,pins = <
+ VF610_PAD_PTE0__DCU0_HSYNC 0x1902
+ VF610_PAD_PTE1__DCU0_VSYNC 0x1902
+ VF610_PAD_PTE2__DCU0_PCLK 0x1902
+ VF610_PAD_PTE4__DCU0_DE 0x1902
+ VF610_PAD_PTE5__DCU0_R0 0x1902
+ VF610_PAD_PTE6__DCU0_R1 0x1902
+ VF610_PAD_PTE7__DCU0_R2 0x1902
+ VF610_PAD_PTE8__DCU0_R3 0x1902
+ VF610_PAD_PTE9__DCU0_R4 0x1902
+ VF610_PAD_PTE10__DCU0_R5 0x1902
+ VF610_PAD_PTE11__DCU0_R6 0x1902
+ VF610_PAD_PTE12__DCU0_R7 0x1902
+ VF610_PAD_PTE13__DCU0_G0 0x1902
+ VF610_PAD_PTE14__DCU0_G1 0x1902
+ VF610_PAD_PTE15__DCU0_G2 0x1902
+ VF610_PAD_PTE16__DCU0_G3 0x1902
+ VF610_PAD_PTE17__DCU0_G4 0x1902
+ VF610_PAD_PTE18__DCU0_G5 0x1902
+ VF610_PAD_PTE19__DCU0_G6 0x1902
+ VF610_PAD_PTE20__DCU0_G7 0x1902
+ VF610_PAD_PTE21__DCU0_B0 0x1902
+ VF610_PAD_PTE22__DCU0_B1 0x1902
+ VF610_PAD_PTE23__DCU0_B2 0x1902
+ VF610_PAD_PTE24__DCU0_B3 0x1902
+ VF610_PAD_PTE25__DCU0_B4 0x1902
+ VF610_PAD_PTE26__DCU0_B5 0x1902
+ VF610_PAD_PTE27__DCU0_B6 0x1902
+ VF610_PAD_PTE28__DCU0_B7 0x1902
>;
};
@@ -140,7 +284,7 @@
VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
@@ -149,6 +293,12 @@
>;
};
+ pinctrl_gpio_bl_on: gpio_bl_on {
+ fsl,pins = <
+ VF610_PAD_PTC0__GPIO_45 0x22ef
+ >;
+ };
+
pinctrl_i2c0: i2c0grp {
fsl,pins = <
VF610_PAD_PTB14__I2C0_SCL 0x37ff
@@ -156,16 +306,45 @@
>;
};
- pinctrl_pwm0: pwm0grp {
+ pinctrl_nfc: nfcgrp {
+ fsl,pins = <
+ VF610_PAD_PTD23__NF_IO7 0x28df
+ VF610_PAD_PTD22__NF_IO6 0x28df
+ VF610_PAD_PTD21__NF_IO5 0x28df
+ VF610_PAD_PTD20__NF_IO4 0x28df
+ VF610_PAD_PTD19__NF_IO3 0x28df
+ VF610_PAD_PTD18__NF_IO2 0x28df
+ VF610_PAD_PTD17__NF_IO1 0x28df
+ VF610_PAD_PTD16__NF_IO0 0x28df
+ VF610_PAD_PTB24__NF_WE_B 0x28c2
+ VF610_PAD_PTB25__NF_CE0_B 0x28c2
+ VF610_PAD_PTB27__NF_RE_B 0x28c2
+ VF610_PAD_PTC26__NF_RB_B 0x283d
+ VF610_PAD_PTC27__NF_ALE 0x28c2
+ VF610_PAD_PTC28__NF_CLE 0x28c2
+ >;
+ };
+
+ pinctrl_pwm0_a: pwm0agrp {
fsl,pins = <
VF610_PAD_PTB0__FTM0_CH0 0x1182
+ >;
+ };
+
+ pinctrl_pwm0_c: pwm0cgrp {
+ fsl,pins = <
VF610_PAD_PTB1__FTM0_CH1 0x1182
>;
};
- pinctrl_pwm1: pwm1grp {
+ pinctrl_pwm1_b: pwm1bgrp {
fsl,pins = <
VF610_PAD_PTB8__FTM1_CH0 0x1182
+ >;
+ };
+
+ pinctrl_pwm1_d: pwm1dgrp {
+ fsl,pins = <
VF610_PAD_PTB9__FTM1_CH1 0x1182
>;
};
@@ -174,6 +353,8 @@
fsl,pins = <
VF610_PAD_PTB10__UART0_TX 0x21a2
VF610_PAD_PTB11__UART0_RX 0x21a1
+ VF610_PAD_PTB12__UART0_RTS 0x21a2
+ VF610_PAD_PTB13__UART0_CTS 0x21a1
>;
};
@@ -193,6 +374,12 @@
>;
};
+ pinctrl_usbc_det: gpio_usbc_det {
+ fsl,pins = <
+ VF610_PAD_PTC29__GPIO_102 0x22ed
+ >;
+ };
+
pinctrl_usbh1_reg: gpio_usb_vbus {
fsl,pins = <
VF610_PAD_PTD4__GPIO_83 0x22ed
diff --git a/arch/arm/boot/dts/vf500-colibri-dual-eth.dts b/arch/arm/boot/dts/vf500-colibri-dual-eth.dts
new file mode 100644
index 000000000000..24990e241e0e
--- /dev/null
+++ b/arch/arm/boot/dts/vf500-colibri-dual-eth.dts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/dts-v1/;
+#include "vf500-colibri.dtsi"
+#include "vf-colibri-dual-eth.dtsi"
+
+/ {
+ model = "Toradex Colibri VF50 on Dual Ethernet Board";
+ compatible = "toradex,vf500-colibri_vf50-on-dual-eth-board", "toradex,vf500-colibri_vf50", "fsl,vf500";
+};
diff --git a/arch/arm/boot/dts/vf500-colibri-eval-v3.dts b/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
index 7fc782c4fc52..c5efb576570c 100644
--- a/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
@@ -15,3 +15,7 @@
model = "Toradex Colibri VF50 on Colibri Evaluation Board";
compatible = "toradex,vf500-colibri_vf50-on-eval", "toradex,vf500-colibri_vf50", "fsl,vf500";
};
+
+&touchctrl {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/vf500-colibri.dtsi b/arch/arm/boot/dts/vf500-colibri.dtsi
index cee34a32f25b..fe733e52bccd 100644
--- a/arch/arm/boot/dts/vf500-colibri.dtsi
+++ b/arch/arm/boot/dts/vf500-colibri.dtsi
@@ -17,4 +17,49 @@
memory {
reg = <0x80000000 0x8000000>;
};
+
+ touchctrl: vf50_touchctrl {
+ compatible = "toradex,vf50-touchctrl";
+ io-channels = <&adc1 0>,<&adc0 0>,
+ <&adc0 1>,<&adc1 2>;
+ xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+ xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+ yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+ ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+ pen-detect-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "idle","default","gpios";
+ pinctrl-0 = <&pinctrl_touchctrl_idle>;
+ pinctrl-1 = <&pinctrl_touchctrl_default>;
+ pinctrl-2 = <&pinctrl_touchctrl_gpios>;
+ status = "disabled";
+ };
+};
+
+&iomuxc {
+ vf610-colibri {
+ pinctrl_touchctrl_idle: touchctrl_idle {
+ fsl,pins = <
+ VF610_PAD_PTA18__GPIO_8 0x006d
+ VF610_PAD_PTA19__GPIO_9 0x006c
+ >;
+ };
+
+ pinctrl_touchctrl_default: touchctrl_default {
+ fsl,pins = <
+ VF610_PAD_PTA18__ADC0_SE0 0x0040
+ VF610_PAD_PTA19__ADC0_SE1 0x0040
+ VF610_PAD_PTA16__ADC1_SE0 0x0040
+ VF610_PAD_PTB2__ADC1_SE2 0x0040
+ >;
+ };
+
+ pinctrl_touchctrl_gpios: touchctrl_gpios {
+ fsl,pins = <
+ VF610_PAD_PTA23__GPIO_13 0x22e9
+ VF610_PAD_PTB23__GPIO_93 0x22e9
+ VF610_PAD_PTA22__GPIO_12 0x22e9
+ VF610_PAD_PTA11__GPIO_4 0x22e9
+ >;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/vf500.dtsi b/arch/arm/boot/dts/vf500.dtsi
index e976d2fa1527..f2be079aae51 100644
--- a/arch/arm/boot/dts/vf500.dtsi
+++ b/arch/arm/boot/dts/vf500.dtsi
@@ -43,6 +43,16 @@
clocks = <&clks VF610_CLK_PLATFORM_BUS>;
};
};
+
+ aips-bus@40080000 {
+
+ pmu@40089000 {
+ compatible = "arm,cortex-a5-pmu";
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&a5_cpu>;
+ };
+ };
+
};
};
diff --git a/arch/arm/boot/dts/vf610-colibri-dual-eth.dts b/arch/arm/boot/dts/vf610-colibri-dual-eth.dts
new file mode 100644
index 000000000000..a2eff553956c
--- /dev/null
+++ b/arch/arm/boot/dts/vf610-colibri-dual-eth.dts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/dts-v1/;
+#include "vf610-colibri.dtsi"
+#include "vf-colibri-dual-eth.dtsi"
+
+/ {
+ model = "Toradex Colibri VF61 on Dual Ethernet Board";
+ compatible = "toradex,vf610-colibri_vf61-on-dual-eth-board", "toradex,vf610-colibri_vf61", "fsl,vf610";
+};
diff --git a/arch/arm/boot/dts/vf610-colibri.dtsi b/arch/arm/boot/dts/vf610-colibri.dtsi
index 19fe045b8334..4c94254e4a60 100644
--- a/arch/arm/boot/dts/vf610-colibri.dtsi
+++ b/arch/arm/boot/dts/vf610-colibri.dtsi
@@ -17,9 +17,89 @@
memory {
reg = <0x80000000 0x10000000>;
};
+
+ sound {
+ compatible = "fsl,fsl-sai-audio-wm9712";
+ fsl,ac97-controller = <&sai2>;
+
+ fsl,model = "Colibri VF61 AC97 Audio";
+
+ fsl,audio-routing =
+ "Headphone", "HPOUTL",
+ "Headphone", "HPOUTR",
+ "LINEINL", "LineIn",
+ "LINEINR", "LineIn",
+ "MIC1", "Mic";
+ };
+};
+
+&sai0 {
+ compatible = "fsl,vf610-sai-clk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai0>;
+ status = "okay";
+};
+
+&sai2 {
+ compatible = "fsl,vf610-sai-ac97";
+ #sound-dai-cells = <0>;
+
+ pinctrl-names = "default", "ac97-running", "ac97-reset",
+ "ac97-warm-reset";
+ pinctrl-0 = <&pinctrl_sai2_ac97_running>;
+ pinctrl-1 = <&pinctrl_sai2_ac97_running>;
+ pinctrl-2 = <&pinctrl_sai2_ac97_reset>;
+ pinctrl-3 = <&pinctrl_sai2_ac97_reset>;
+ ac97-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH &gpio0 8 GPIO_ACTIVE_HIGH
+ &gpio0 13 GPIO_ACTIVE_HIGH>;
+ status = "okay";
};
&L2 {
- arm,data-latency = <2 1 2>;
- arm,tag-latency = <3 2 3>;
+ arm,data-latency = <3 3 3>;
+ arm,tag-latency = <2 2 2>;
+};
+
+&iomuxc {
+ vf610-colibri {
+ pinctrl_sai0: sai0grp_1 {
+ fsl,pins = <
+ VF610_PAD_PTB23__SAI0_TX_BCLK 0x31C3
+ >;
+ };
+ pinctrl_sai2_ac97_reset: sai2grp_1 {
+ fsl,pins = <
+ /* Pen-down */
+ VF610_PAD_PTA11__GPIO_4 0x22ed
+ /* AC97 SData Out (test mode selection) */
+ VF610_PAD_PTA18__GPIO_8 0x22ed
+ /* AC97 Sync (warm reset) */
+ VF610_PAD_PTA19__GPIO_9 0x22ed
+ /* AC97 Reset (cold reset) */
+ VF610_PAD_PTA23__GPIO_13 0x22eb
+ >;
+ };
+
+ pinctrl_sai2_ac97_running: sai2grp_2 {
+ fsl,pins = <
+ /* AC97 Bit clock */
+ VF610_PAD_PTA16__SAI2_TX_BCLK 0x31C3
+
+ /* AC97 SData Out */
+ VF610_PAD_PTA18__SAI2_TX_DATA 0x31C2
+
+ /* AC97 Sync */
+ VF610_PAD_PTA19__SAI2_TX_SYNC 0x31C3
+
+ /* AC97 SData In */
+ VF610_PAD_PTA22__SAI2_RX_DATA 0x0041
+
+ /* AC97 Reset (cold reset, keep output buffer on) */
+ VF610_PAD_PTA23__GPIO_13 0x22eb
+
+ /* GenIRQ */
+ VF610_PAD_PTB2__GPIO_24 0x22ed
+ >;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/vf610-cosmic.dts b/arch/arm/boot/dts/vf610-cosmic.dts
index fd8758b639f5..5447f2594659 100644
--- a/arch/arm/boot/dts/vf610-cosmic.dts
+++ b/arch/arm/boot/dts/vf610-cosmic.dts
@@ -68,7 +68,7 @@
VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
diff --git a/arch/arm/boot/dts/vf610-pinfunc.h b/arch/arm/boot/dts/vf610-pinfunc.h
index 1ee681f7ce2f..fcad7132c871 100644
--- a/arch/arm/boot/dts/vf610-pinfunc.h
+++ b/arch/arm/boot/dts/vf610-pinfunc.h
@@ -369,7 +369,7 @@
#define VF610_PAD_PTC11__MLB_DATA 0x0E0 0x358 ALT6 0x1
#define VF610_PAD_PTC11__DEBUG_OUT 0x0E0 0x000 ALT7 0x0
#define VF610_PAD_PTC12__GPIO_57 0x0E4 0x000 ALT0 0x0
-#define VF610_PAD_PTC12__ENET_RMII_RXD1 0x0E4 0x000 ALT1 0x0
+#define VF610_PAD_PTC12__ENET_RMII1_RXD1 0x0E4 0x000 ALT1 0x0
#define VF610_PAD_PTC12__ESAI_SDO1 0x0E4 0x318 ALT3 0x1
#define VF610_PAD_PTC12__SAI2_TX_BCLK 0x0E4 0x370 ALT5 0x1
#define VF610_PAD_PTC12__DEBUG_OUT3 0x0E4 0x000 ALT7 0x0
diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index f64fddce3e2a..c139dc1f2b6e 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -127,6 +127,34 @@
status = "okay";
};
+&dcu0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dcu0_1>;
+ display = <&display>;
+ status = "okay";
+
+ display: display@0 {
+ bits-per-pixel = <24>;
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: nl4827hc19 {
+ clock-frequency = <10870000>;
+ hactive = <480>;
+ vactive = <272>;
+ hback-porch = <2>;
+ hfront-porch = <2>;
+ vback-porch = <1>;
+ vfront-porch = <1>;
+ hsync-len = <41>;
+ vsync-len = <2>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ };
+ };
+ };
+};
+
&fec0 {
phy-mode = "rmii";
phy-handle = <&ethphy0>;
@@ -180,6 +208,39 @@
>;
};
+ pinctrl_dcu0_1: dcu0grp_1 {
+ fsl,pins = <
+ VF610_PAD_PTE0__DCU0_HSYNC 0x42
+ VF610_PAD_PTE1__DCU0_VSYNC 0x42
+ VF610_PAD_PTE2__DCU0_PCLK 0x42
+ VF610_PAD_PTE4__DCU0_DE 0x42
+ VF610_PAD_PTE5__DCU0_R0 0x42
+ VF610_PAD_PTE6__DCU0_R1 0x42
+ VF610_PAD_PTE7__DCU0_R2 0x42
+ VF610_PAD_PTE8__DCU0_R3 0x42
+ VF610_PAD_PTE9__DCU0_R4 0x42
+ VF610_PAD_PTE10__DCU0_R5 0x42
+ VF610_PAD_PTE11__DCU0_R6 0x42
+ VF610_PAD_PTE12__DCU0_R7 0x42
+ VF610_PAD_PTE13__DCU0_G0 0x42
+ VF610_PAD_PTE14__DCU0_G1 0x42
+ VF610_PAD_PTE15__DCU0_G2 0x42
+ VF610_PAD_PTE16__DCU0_G3 0x42
+ VF610_PAD_PTE17__DCU0_G4 0x42
+ VF610_PAD_PTE18__DCU0_G5 0x42
+ VF610_PAD_PTE19__DCU0_G6 0x42
+ VF610_PAD_PTE20__DCU0_G7 0x42
+ VF610_PAD_PTE21__DCU0_B0 0x42
+ VF610_PAD_PTE22__DCU0_B1 0x42
+ VF610_PAD_PTE23__DCU0_B2 0x42
+ VF610_PAD_PTE24__DCU0_B3 0x42
+ VF610_PAD_PTE25__DCU0_B4 0x42
+ VF610_PAD_PTE26__DCU0_B5 0x42
+ VF610_PAD_PTE27__DCU0_B6 0x42
+ VF610_PAD_PTE28__DCU0_B7 0x42
+ >;
+ };
+
pinctrl_dspi0: dspi0grp {
fsl,pins = <
VF610_PAD_PTB19__DSPI0_CS0 0x1182
@@ -221,7 +282,7 @@
VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
@@ -287,6 +348,54 @@
status = "okay";
};
+&iomuxc {
+ vf610-twr {
+ pinctrl_nfc_1: nfcgrp_1 {
+ fsl,pins = <
+ VF610_PAD_PTD31__NF_IO15 0x28df
+ VF610_PAD_PTD30__NF_IO14 0x28df
+ VF610_PAD_PTD29__NF_IO13 0x28df
+ VF610_PAD_PTD28__NF_IO12 0x28df
+ VF610_PAD_PTD27__NF_IO11 0x28df
+ VF610_PAD_PTD26__NF_IO10 0x28df
+ VF610_PAD_PTD25__NF_IO9 0x28df
+ VF610_PAD_PTD24__NF_IO8 0x28df
+ VF610_PAD_PTD23__NF_IO7 0x28df
+ VF610_PAD_PTD22__NF_IO6 0x28df
+ VF610_PAD_PTD21__NF_IO5 0x28df
+ VF610_PAD_PTD20__NF_IO4 0x28df
+ VF610_PAD_PTD19__NF_IO3 0x28df
+ VF610_PAD_PTD18__NF_IO2 0x28df
+ VF610_PAD_PTD17__NF_IO1 0x28df
+ VF610_PAD_PTD16__NF_IO0 0x28df
+ VF610_PAD_PTB24__NF_WE_B 0x28c2
+ VF610_PAD_PTB25__NF_CE0_B 0x28c2
+ VF610_PAD_PTB27__NF_RE_B 0x28c2
+ VF610_PAD_PTC26__NF_RB_B 0x283d
+ VF610_PAD_PTC27__NF_ALE 0x28c2
+ VF610_PAD_PTC28__NF_CLE 0x28c2
+ >;
+ };
+ };
+};
+
+&nfc {
+ assigned-clocks = <&clks VF610_CLK_NFC>;
+ assigned-clock-rates = <33000000>;
+ nand-bus-width = <16>;
+ nand-ecc-mode = "hw";
+ nand-ecc-step-size = <2048>;
+ nand-ecc-strength = <24>;
+ nand-on-flash-bbt;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nfc_1>;
+ status = "okay";
+};
+
+&tcon0 {
+ status = "okay";
+};
+
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index 4aa335166be7..eb4217273c0e 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -54,8 +54,36 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
- interrupt-parent = <&mscm_ir>;
+ interrupt-parent = <&gpc>;
ranges;
+ ocotp-cfg = <&ocotp 0x410 0x420>;
+ rom-revision = <&ocrom 0x80>;
+
+ ocrom: ocrom {
+ compatible = "fsl,vf610-ocrom", "syscon";
+ reg = <0x00000000 0x18000>;
+ };
+
+ ocram0: sram@3f000000 {
+ compatible = "mmio-sram";
+ reg = <0x3f000000 0x40000>;
+ };
+
+ ocram1: sram@3f040000 {
+ compatible = "mmio-sram";
+ reg = <0x3f040000 0x40000>;
+ };
+
+ gfxram0: sram@3f400000 {
+ compatible = "mmio-sram";
+ reg = <0x3f400000 0x80000>;
+ };
+
+ /* used by L2 cache */
+ gfxram1: sram@3f480000 {
+ compatible = "mmio-sram";
+ reg = <0x3f480000 0x80000>;
+ };
aips0: aips-bus@40000000 {
compatible = "fsl,aips-bus", "simple-bus";
@@ -70,10 +98,22 @@
mscm_ir: interrupt-controller@40001800 {
compatible = "fsl,vf610-mscm-ir";
+ #address-cells = <1>;
+ #size-cells = <1>;
reg = <0x40001800 0x400>;
fsl,cpucfg = <&mscm_cpucfg>;
interrupt-controller;
#interrupt-cells = <2>;
+
+ cpu2cpu@40001800 {
+ reg = <0x40001800 0x40>;
+ interrupt-parent = <&mscm_ir>;
+ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>,
+ <1 IRQ_TYPE_LEVEL_HIGH>,
+ <2 IRQ_TYPE_LEVEL_HIGH>,
+ <3 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "int0", "int1", "int2", "int3";
+ };
};
edma0: dma-controller@40018000 {
@@ -92,6 +132,12 @@
status = "disabled";
};
+ sema4: semaphore-controller@4001d000 {
+ compatible = "fsl,vf610-sema4";
+ reg = <0x4001d000 0x1000>;
+ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
can0: flexcan@40020000 {
compatible = "fsl,vf610-flexcan";
reg = <0x40020000 0x4000>;
@@ -174,12 +220,28 @@
status = "disabled";
};
+ sai0: sai@4002f000 {
+ compatible = "fsl,vf610-sai";
+ reg = <0x4002f000 0x1000>;
+ interrupts = <84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_SAI0>,
+ <&clks VF610_CLK_SAI0_DIV>,
+ <&clks 0>, <&clks 0>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
+ dma-names = "tx", "rx";
+ dmas = <&edma0 0 17>,
+ <&edma0 0 16>;
+ status = "disabled";
+ };
+
sai2: sai@40031000 {
compatible = "fsl,vf610-sai";
reg = <0x40031000 0x1000>;
interrupts = <86 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_SAI2>;
- clock-names = "sai";
+ clocks = <&clks VF610_CLK_SAI2>,
+ <&clks VF610_CLK_SAI2_DIV>,
+ <&clks 0>, <&clks 0>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
dma-names = "tx", "rx";
dmas = <&edma0 0 21>,
<&edma0 0 20>;
@@ -226,6 +288,17 @@
interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks VF610_CLK_ADC0>;
clock-names = "adc";
+ #io-channel-cells = <1>;
+ status = "disabled";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
+ };
+
+ tcon0: tcon@4003d000 {
+ compatible = "fsl,vf610-tcon";
+ reg = <0x4003d000 0x1000>;
+ clocks = <&clks VF610_CLK_TCON0>;
+ clock-names = "tcon";
status = "disabled";
};
@@ -264,6 +337,7 @@
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&iomuxc 0 0 32>;
+ fsl,gpio-wakeup = <&wakeup 22 0 8>; /* PTB0...PTB7 */
};
gpio1: gpio@4004a000 {
@@ -275,6 +349,10 @@
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&iomuxc 0 32 32>;
+ fsl,gpio-wakeup = <&wakeup 1 8 2>, /* PTB11, PTB12 (NMI)*/
+ <&wakeup 4 10 1>, /* PTB14 */
+ <&wakeup 6 11 1>, /* PTB16 */
+ <&wakeup 9 12 2>; /* PTB19, PTB20 */
};
gpio2: gpio@4004b000 {
@@ -297,6 +375,9 @@
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&iomuxc 0 96 32>;
+ fsl,gpio-wakeup = <&wakeup 1 14 1>, /* PTB27 */
+ <&wakeup 7 15 1>, /* PTC30 */
+ <&wakeup 29 16 1>; /* PTE20 */
};
gpio4: gpio@4004d000 {
@@ -315,6 +396,11 @@
reg = <0x40050000 0x400>;
};
+ scsc: scsc@40052000 {
+ compatible = "fsl,vf610-scsc";
+ reg = <0x40052000 0x1000>;
+ };
+
usbphy0: usbphy@40050800 {
compatible = "fsl,vf610-usbphy";
reg = <0x40050800 0x400>;
@@ -333,6 +419,16 @@
status = "disabled";
};
+ dcu0: dcu@40058000 {
+ compatible = "fsl,vf610-dcu";
+ reg = <0x40058000 0x1200>;
+ interrupts = <30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_DCU0>;
+ clock-names = "dcu";
+ tcon-controller = <&tcon0>;
+ status = "disabled";
+ };
+
i2c0: i2c@40066000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -347,6 +443,27 @@
status = "disabled";
};
+ i2c1: i2c@40067000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-i2c";
+ reg = <0x40067000 0x1000>;
+ interrupts = <72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_I2C1>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 52>,
+ <&edma0 0 53>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ wakeup: wkpu@4006a000 {
+ compatible = "fsl,vf610-wkpu";
+ reg = <0x4006a000 0x1000>;
+ interrupts = <92 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_WKPU>;
+ };
+
clks: ccm@4006b000 {
compatible = "fsl,vf610-ccm";
reg = <0x4006b000 0x1000>;
@@ -379,6 +496,14 @@
reg = <0x4006e000 0x1000>;
interrupts = <96 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ gpc: gpc@4006c000 {
+ compatible = "fsl,vf610-gpc";
+ reg = <0x4006c000 0x1000>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&mscm_ir>;
+ };
};
aips1: aips-bus@40080000 {
@@ -403,6 +528,11 @@
status = "disabled";
};
+ ocotp: ocotp@400a5000 {
+ compatible = "fsl,vf610-ocotp", "syscon";
+ reg = <0x400a5000 0x1000>;
+ };
+
snvs0: snvs@400a7000 {
compatible = "fsl,sec-v4.0-mon", "simple-bus";
#address-cells = <1>;
@@ -436,12 +566,33 @@
status = "disabled";
};
+ ddrmc: ddrmc@400ae000 {
+ compatible = "fsl,vf610-ddrmc";
+ reg = <0x400ae000 0x400>;
+ clocks = <&clks VF610_CLK_DDRMC>;
+ clock-names = "ddrc";
+ };
+
adc1: adc@400bb000 {
compatible = "fsl,vf610-adc";
reg = <0x400bb000 0x1000>;
interrupts = <54 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks VF610_CLK_ADC1>;
clock-names = "adc";
+ #io-channel-cells = <1>;
+ status = "disabled";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
+ };
+
+ esdhc0: esdhc@400b1000 {
+ compatible = "fsl,imx53-esdhc";
+ reg = <0x400b1000 0x1000>;
+ interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_IPG_BUS>,
+ <&clks VF610_CLK_PLATFORM_BUS>,
+ <&clks VF610_CLK_ESDHC0>;
+ clock-names = "ipg", "ahb", "per";
status = "disabled";
};
@@ -520,6 +671,49 @@
status = "disabled";
};
+ nfc: nand@400e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-nfc";
+ reg = <0x400e0000 0x4000>;
+ interrupts = <83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_NFC>;
+ clock-names = "nfc";
+ status = "disabled";
+ };
+
+ i2c2: i2c@400e6000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-i2c";
+ reg = <0x400e6000 0x1000>;
+ interrupts = <73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_I2C2>;
+ clock-names = "ipg";
+ dmas = <&edma0 1 36>,
+ <&edma0 1 37>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ i2c3: i2c@400e7000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-i2c";
+ reg = <0x400e7000 0x1000>;
+ interrupts = <74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_I2C3>;
+ clock-names = "ipg";
+ dmas = <&edma0 1 38>,
+ <&edma0 1 39>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+ };
+
+ adc_hwmon: iio_hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc0 16>, <&adc1 16>;
};
};
};
diff --git a/arch/arm/configs/colibri_vf_defconfig b/arch/arm/configs/colibri_vf_defconfig
new file mode 100644
index 000000000000..45f2421a5373
--- /dev/null
+++ b/arch/arm/configs/colibri_vf_defconfig
@@ -0,0 +1,317 @@
+CONFIG_KERNEL_LZO=y
+CONFIG_SYSVIPC=y
+CONFIG_FHANDLE=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_NAMESPACES=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_MXC=y
+CONFIG_SOC_VF610=y
+CONFIG_SWP_EMULATE=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_KEXEC=y
+# CONFIG_ATAGS_PROC is not set
+CONFIG_CPU_IDLE=y
+# CONFIG_CPU_IDLE_GOV_LADDER is not set
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_NET_IPGRE_DEMUX=m
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_MASQ=y
+CONFIG_NFT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_NFACCT=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NFT_CHAIN_NAT_IPV4=y
+CONFIG_NFT_MASQ_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_L2TP=m
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_IGMP_SNOOPING is not set
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_VLAN_8021Q=y
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_CAN=m
+CONFIG_CAN_FLEXCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_DMA_CMA=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VF610_NFC=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_FASTMAP=y
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_SCAN_ASYNC=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_HISILICON is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_MICREL_PHY=y
+CONFIG_PPP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_USB_NET_DRIVERS=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_USB_ZD1201=m
+CONFIG_RT2X00=m
+CONFIG_RT2800USB=m
+# CONFIG_RT2800USB_RT35XX is not set
+CONFIG_RTL8192CU=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_MOUSE_PS2 is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_FUSION_F0710A=m
+CONFIG_TOUCHSCREEN_WM97XX=y
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+CONFIG_TOUCHSCREEN_COLIBRI_VF50=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_FSL_LPUART=y
+CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_IMX=y
+CONFIG_SPI=y
+CONFIG_SPI_FSL_DSPI=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_SENSORS_IIO_HWMON=y
+CONFIG_WATCHDOG=y
+CONFIG_IMX2_WDT=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_ANATOP=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_RC_SUPPORT=y
+# CONFIG_RC_MAP is not set
+# CONFIG_RC_DECODERS is not set
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+# CONFIG_USB_GSPCA is not set
+CONFIG_FB=y
+CONFIG_FB_FSL_DCU=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_GPIO=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_FSL_SAI=y
+CONFIG_SND_IMX_SOC=y
+CONFIG_SND_SOC_FSL_SAI_WM9712=y
+CONFIG_HIDRAW=y
+CONFIG_HID_MULTITOUCH=m
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MXS_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_FSL_USB2=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_ESDHC_IMX=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PWM=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_SNVS=y
+CONFIG_DMADEVICES=y
+# CONFIG_MX3_IPU is not set
+CONFIG_FSL_EDMA=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXTCON=y
+CONFIG_EXTCON_USB_GPIO=y
+CONFIG_IIO=y
+CONFIG_IIO_TRIGGER=y
+CONFIG_VF610_ADC=y
+CONFIG_PWM=y
+CONFIG_PWM_FSL_FTM=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_OVERLAY_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=10
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_SECURITYFS=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_XZ_DEC=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 3244cf1d2773..19fbc41731d7 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -94,14 +94,17 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o
ifeq ($(CONFIG_SUSPEND),y)
AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o
+AFLAGS_suspend-vf610.o :=-Wa,-march=armv7-a
+obj-$(CONFIG_SOC_VF610) += suspend-vf610.o
endif
obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
+obj-$(CONFIG_SOC_VF610) += pm-vf610.o
obj-$(CONFIG_SOC_IMX50) += mach-imx50.o
obj-$(CONFIG_SOC_IMX51) += mach-imx51.o
obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
-obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o
+obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o vf610_sema4.o
obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c
index 8935bff99fe7..db44a198a0d9 100644
--- a/arch/arm/mach-imx/clk-gate2.c
+++ b/arch/arm/mach-imx/clk-gate2.c
@@ -31,6 +31,7 @@ struct clk_gate2 {
struct clk_hw hw;
void __iomem *reg;
u8 bit_idx;
+ u8 cgr_val;
u8 flags;
spinlock_t *lock;
unsigned int *share_count;
@@ -50,7 +51,8 @@ static int clk_gate2_enable(struct clk_hw *hw)
goto out;
reg = readl(gate->reg);
- reg |= 3 << gate->bit_idx;
+ reg &= ~(3 << gate->bit_idx);
+ reg |= gate->cgr_val << gate->bit_idx;
writel(reg, gate->reg);
out:
@@ -125,7 +127,7 @@ static struct clk_ops clk_gate2_ops = {
struct clk *clk_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
- void __iomem *reg, u8 bit_idx,
+ void __iomem *reg, u8 bit_idx, u8 cgr_val,
u8 clk_gate2_flags, spinlock_t *lock,
unsigned int *share_count)
{
@@ -140,6 +142,7 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
/* struct clk_gate2 assignments */
gate->reg = reg;
gate->bit_idx = bit_idx;
+ gate->cgr_val = cgr_val;
gate->flags = clk_gate2_flags;
gate->lock = lock;
gate->share_count = share_count;
diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c
index 61876ed6e11e..6e739454ff89 100644
--- a/arch/arm/mach-imx/clk-vf610.c
+++ b/arch/arm/mach-imx/clk-vf610.c
@@ -10,9 +10,11 @@
#include <linux/of_address.h>
#include <linux/clk.h>
+#include <linux/syscore_ops.h>
#include <dt-bindings/clock/vf610-clock.h>
#include "clk.h"
+#include "common.h"
#define CCM_CCR (ccm_base + 0x00)
#define CCM_CSR (ccm_base + 0x04)
@@ -40,6 +42,7 @@
#define CCM_CCGR9 (ccm_base + 0x64)
#define CCM_CCGR10 (ccm_base + 0x68)
#define CCM_CCGR11 (ccm_base + 0x6c)
+#define CCM_CCGRx(x) (CCM_CCGR0 + (x) * 4)
#define CCM_CMEOR0 (ccm_base + 0x70)
#define CCM_CMEOR1 (ccm_base + 0x74)
#define CCM_CMEOR2 (ccm_base + 0x78)
@@ -115,9 +118,25 @@ static struct clk_div_table pll4_audio_div_table[] = {
static struct clk *clk[VF610_CLK_END];
static struct clk_onecell_data clk_data;
+static u32 anadig_pll3_ctrl;
+static u32 anadig_pll4_ctrl;
+static u32 anadig_pll5_ctrl;
+static u32 anadig_pll6_ctrl;
+static u32 anadig_pll7_ctrl;
+static u32 ccpgr0;
+static u32 cscmr1;
+static u32 cscmr2;
+static u32 cscdr1;
+static u32 cscdr2;
+static u32 cscdr3;
+static u32 ccgr[12];
+
static unsigned int const clks_init_on[] __initconst = {
VF610_CLK_SYS_BUS,
VF610_CLK_DDR_SEL,
+ VF610_CLK_DAP,
+ VF610_CLK_DDRMC,
+ VF610_CLK_WKPU,
};
static struct clk * __init vf610_get_fixed_clock(
@@ -131,6 +150,57 @@ static struct clk * __init vf610_get_fixed_clock(
return clk;
};
+static int vf610_clk_suspend(void)
+{
+ int i;
+
+ anadig_pll3_ctrl = readl_relaxed(PLL3_CTRL);
+ anadig_pll4_ctrl = readl_relaxed(PLL4_CTRL);
+ anadig_pll5_ctrl = readl_relaxed(PLL5_CTRL);
+ anadig_pll6_ctrl = readl_relaxed(PLL6_CTRL);
+ anadig_pll7_ctrl = readl_relaxed(PLL7_CTRL);
+
+ ccpgr0 = readl_relaxed(CCM_CCPGR0);
+ cscmr1 = readl_relaxed(CCM_CSCMR1);
+ cscmr2 = readl_relaxed(CCM_CSCMR2);
+
+ cscdr1 = readl_relaxed(CCM_CSCDR1);
+ cscdr2 = readl_relaxed(CCM_CSCDR2);
+ cscdr3 = readl_relaxed(CCM_CSCDR3);
+
+ for (i = 0; i < 12; i++)
+ ccgr[i] = readl_relaxed(CCM_CCGRx(i));
+
+ return 0;
+}
+
+static void vf610_clk_resume(void)
+{
+ int i;
+
+ writel_relaxed(anadig_pll3_ctrl, PLL3_CTRL);
+ writel_relaxed(anadig_pll4_ctrl, PLL4_CTRL);
+ writel_relaxed(anadig_pll5_ctrl, PLL5_CTRL);
+ writel_relaxed(anadig_pll6_ctrl, PLL6_CTRL);
+ writel_relaxed(anadig_pll7_ctrl, PLL7_CTRL);
+
+ writel_relaxed(ccpgr0, CCM_CCPGR0);
+ writel_relaxed(cscmr1, CCM_CSCMR1);
+ writel_relaxed(cscmr2, CCM_CSCMR2);
+
+ writel_relaxed(cscdr1, CCM_CSCDR1);
+ writel_relaxed(cscdr2, CCM_CSCDR2);
+ writel_relaxed(cscdr3, CCM_CSCDR3);
+
+ for (i = 0; i < 12; i++)
+ writel_relaxed(ccgr[i], CCM_CCGRx(i));
+}
+
+static struct syscore_ops vf610_clk_syscore_ops = {
+ .suspend = vf610_clk_suspend,
+ .resume = vf610_clk_resume,
+};
+
static void __init vf610_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
@@ -159,6 +229,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
ccm_base = of_iomap(np, 0);
BUG_ON(!ccm_base);
+ vf610_pm_set_ccm_base(ccm_base);
+
clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel", CCM_CCSR, 4, 1, slow_sels, ARRAY_SIZE(slow_sels));
clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel", CCM_CCSR, 5, 1, fast_sels, ARRAY_SIZE(fast_sels));
@@ -232,6 +304,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_audio_div", "pll4_audio", 0, CCM_CACRR, 6, 3, 0, pll4_audio_div_table, &imx_ccm_lock);
clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1);
+ clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc", "ddr_sel", CCM_CCGR6, CCM_CCGRx_CGn(14), 0x2);
+
clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6);
clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6);
@@ -263,15 +337,19 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7));
- clk[VF610_CLK_UART0] = imx_clk_gate2("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7));
- clk[VF610_CLK_UART1] = imx_clk_gate2("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8));
- clk[VF610_CLK_UART2] = imx_clk_gate2("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9));
- clk[VF610_CLK_UART3] = imx_clk_gate2("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10));
- clk[VF610_CLK_UART4] = imx_clk_gate2("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9));
- clk[VF610_CLK_UART5] = imx_clk_gate2("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10));
+ clk[VF610_CLK_UART0] = imx_clk_gate2_cgr("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7), 0x2);
+ clk[VF610_CLK_UART1] = imx_clk_gate2_cgr("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8), 0x2);
+ clk[VF610_CLK_UART2] = imx_clk_gate2_cgr("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9), 0x2);
+ clk[VF610_CLK_UART3] = imx_clk_gate2_cgr("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10), 0x2);
+ clk[VF610_CLK_UART4] = imx_clk_gate2_cgr("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9), 0x2);
+ clk[VF610_CLK_UART5] = imx_clk_gate2_cgr("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10), 0x2);
clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6));
clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7));
+ clk[VF610_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(6));
+ clk[VF610_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(7));
+
+ clk[VF610_CLK_WKPU] = imx_clk_gate2_cgr("wkpu", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(10), 0x2);
clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(12));
clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(13));
@@ -324,6 +402,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3);
clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8));
+ clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13));
+
clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4);
clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30);
clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4);
@@ -332,22 +412,22 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4);
clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16);
clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4);
- clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "sai0_div", CCM_CCGR0, CCM_CCGRx_CGn(15));
+ clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(15));
clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4);
clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17);
clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4);
- clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "sai1_div", CCM_CCGR1, CCM_CCGRx_CGn(0));
+ clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(0));
clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4);
clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18);
clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4);
- clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "sai2_div", CCM_CCGR1, CCM_CCGRx_CGn(1));
+ clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(1));
clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4);
clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19);
clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4);
- clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "sai3_div", CCM_CCGR1, CCM_CCGRx_CGn(2));
+ clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(2));
clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4);
clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9);
@@ -383,9 +463,12 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(2));
clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7));
+ clk[VF610_CLK_DAP] = imx_clk_gate("dap", "platform_bus", CCM_CCSR, 24);
imx_check_clocks(clk, ARRAY_SIZE(clk));
+ clk_set_parent(clk[VF610_CLK_ENET_SEL], clk[VF610_CLK_ENET_50M]);
+
clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]);
clk_set_rate(clk[VF610_CLK_QSPI0_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_SEL]) / 2);
clk_set_rate(clk[VF610_CLK_QSPI0_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X4_DIV]) / 2);
@@ -396,17 +479,23 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk_set_rate(clk[VF610_CLK_QSPI1_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X4_DIV]) / 2);
clk_set_rate(clk[VF610_CLK_QSPI1_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X2_DIV]) / 2);
- clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_AUDIO_EXT]);
- clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_AUDIO_EXT]);
- clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]);
+ clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_PLL4_MAIN_DIV]);
+ clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_PLL4_MAIN_DIV]);
+ clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_PLL4_MAIN_DIV]);
clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]);
+ clk_set_rate(clk[VF610_CLK_PLL4_MAIN_DIV], 147456000);
+
+ clk_set_parent(clk[VF610_CLK_DCU0_SEL], clk[VF610_CLK_PLL1_PFD2]);
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clk[clks_init_on[i]]);
+ register_syscore_ops(&vf610_clk_syscore_ops);
+
/* Add the clocks to provider list */
clk_data.clks = clk;
clk_data.clk_num = ARRAY_SIZE(clk);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init);
+
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index 6a07903a28bc..8aec27129ec7 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -30,7 +30,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
struct clk *clk_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
- void __iomem *reg, u8 bit_idx,
+ void __iomem *reg, u8 bit_idx, u8 cgr_val,
u8 clk_gate_flags, spinlock_t *lock,
unsigned int *share_count);
@@ -44,7 +44,7 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
- shift, 0, &imx_ccm_lock, NULL);
+ shift, 0x3, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_gate2_shared(const char *name,
@@ -52,7 +52,14 @@ static inline struct clk *imx_clk_gate2_shared(const char *name,
unsigned int *share_count)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
- shift, 0, &imx_ccm_lock, share_count);
+ shift, 0x3, 0, &imx_ccm_lock, share_count);
+}
+
+static inline struct clk *imx_clk_gate2_cgr(const char *name,
+ const char *parent, void __iomem *reg, u8 shift, u8 cgr_val)
+{
+ return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ shift, cgr_val, 0, &imx_ccm_lock, NULL);
}
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 0f04e30b726d..f37f1938965a 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -79,6 +79,13 @@ enum mxc_cpu_pwr_mode {
STOP_POWER_OFF, /* STOP + SRPG */
};
+enum vf610_cpu_pwr_mode {
+ VF610_RUN,
+ VF610_LP_RUN,
+ VF610_STOP,
+ VF610_LP_STOP,
+};
+
enum mx3_cpu_pwr_mode {
MX3_RUN,
MX3_WAIT,
@@ -122,9 +129,11 @@ int imx_cpu_kill(unsigned int cpu);
#ifdef CONFIG_SUSPEND
void v7_cpu_resume(void);
void imx6_suspend(void __iomem *ocram_vbase);
+void vf610_suspend(void __iomem *ocram_vbase);
#else
static inline void v7_cpu_resume(void) {}
static inline void imx6_suspend(void __iomem *ocram_vbase) {}
+static inline void vf610_suspend(void __iomem *ocram_vbase) {}
#endif
void imx6q_pm_init(void);
@@ -132,6 +141,8 @@ void imx6dl_pm_init(void);
void imx6sl_pm_init(void);
void imx6sx_pm_init(void);
void imx6q_pm_set_ccm_base(void __iomem *base);
+void vf610_pm_init(void);
+void vf610_pm_set_ccm_base(void __iomem *base);
#ifdef CONFIG_PM
void imx51_pm_init(void);
diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c
index 2e7c75b66fe0..1ba7738170c6 100644
--- a/arch/arm/mach-imx/mach-vf610.c
+++ b/arch/arm/mach-imx/mach-vf610.c
@@ -11,6 +11,13 @@
#include <linux/irqchip.h>
#include <asm/mach/arch.h>
#include <asm/hardware/cache-l2x0.h>
+#include "common.h"
+
+static void __init vf610_init_machine(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ vf610_pm_init();
+}
static const char * const vf610_dt_compat[] __initconst = {
"fsl,vf500",
@@ -23,5 +30,6 @@ static const char * const vf610_dt_compat[] __initconst = {
DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF5xx/VF6xx (Device Tree)")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
+ .init_machine = vf610_init_machine,
.dt_compat = vf610_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-imx/pm-vf610.c b/arch/arm/mach-imx/pm-vf610.c
new file mode 100644
index 000000000000..7192924e009f
--- /dev/null
+++ b/arch/arm/mach-imx/pm-vf610.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2014 Toradex AG
+ *
+ * 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
+ */
+
+#ifdef DEBUG
+#define pr_pmdebug(fmt, ...) pr_info("PM: VF610: " fmt "\n", ##__VA_ARGS__)
+#else
+#define pr_pmdebug(fmt, ...)
+#endif
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/genalloc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/suspend.h>
+#include <linux/clk.h>
+#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <asm/tlb.h>
+
+#include "common.h"
+
+#define DDRMC_PHY_OFFSET 0x400
+
+#define CCR 0x0
+#define BM_CCR_FIRC_EN (0x1 << 16)
+#define BM_CCR_FXOSC_EN (0x1 << 12)
+
+#define CCSR 0x8
+#define BM_CCSR_DDRC_CLK_SEL (0x1 << 6)
+#define BM_CCSR_FAST_CLK_SEL (0x1 << 5)
+#define BM_CCSR_SLOW_CLK_SEL (0x1 << 4)
+#define BM_CCSR_SYS_CLK_SEL_MASK (0x7 << 0)
+
+#define CACRR 0xc
+
+#define CLPCR 0x2c
+#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5)
+#define BM_CLPCR_SBYOS (0x1 << 6)
+#define BM_CLPCR_DIS_REF_OSC (0x1 << 7)
+#define BM_CLPCR_ANADIG_STOP_MODE (0x1 << 8)
+#define BM_CLPCR_FXOSC_BYPSEN (0x1 << 10)
+#define BM_CLPCR_FXOSC_PWRDWN (0x1 << 11)
+#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22)
+#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23)
+#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 24)
+#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 25)
+
+#define CGPR 0x64
+#define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17)
+
+#define GPC_PGCR 0x0
+#define BM_PGCR_DS_STOP (0x1 << 7)
+#define BM_PGCR_DS_LPSTOP (0x1 << 6)
+#define BM_PGCR_WB_STOP (0x1 << 4)
+#define BM_PGCR_HP_OFF (0x1 << 3)
+#define BM_PGCR_PG_PD1 (0x1 << 0)
+
+#define GPC_LPMR 0x40
+#define BM_LPMR_RUN 0x0
+#define BM_LPMR_STOP 0x2
+
+#define ANATOP_PLL1_CTRL 0x270
+#define ANATOP_PLL2_CTRL 0x30
+#define ANATOP_PLL2_PFD 0x100
+#define BM_PLL_POWERDOWN (0x1 << 12)
+#define BM_PLL_ENABLE (0x1 << 13)
+#define BM_PLL_BYPASS (0x1 << 16)
+#define BM_PLL_LOCK (0x1 << 31)
+#define BM_PLL_PFD2_CLKGATE (0x1 << 15)
+#define BM_PLL_USB_POWER (0x1 << 12)
+#define BM_PLL_EN_USB_CLKS (0x1 << 6)
+
+#define VF610_SUSPEND_OCRAM_SIZE 0x4000
+#define VF610_DDRMC_IO_NUM 94
+#define VF610_IOMUX_DDR_IO_NUM 48
+#define VF610_ANATOP_IO_NUM 2
+
+static void __iomem *ccm_base;
+static void __iomem *suspend_ocram_base;
+static void (*vf610_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
+static bool has_cke_reset_pulls;
+
+#ifdef DEBUG
+static void __iomem *uart_membase;
+static unsigned long uart_clk;
+#endif
+
+static const u32 vf610_iomuxc_ddr_io_offset[] __initconst = {
+ 0x220, 0x224, 0x228, 0x22c, 0x230, 0x234, 0x238, 0x23c,
+ 0x240, 0x244, 0x248, 0x24c, 0x250, 0x254, 0x258, 0x25c,
+ 0x260, 0x264, 0x268, 0x26c, 0x270, 0x274, 0x278, 0x27c,
+ 0x280, 0x284, 0x288, 0x28c, 0x290, 0x294, 0x298, 0x29c,
+ 0x2a0, 0x2a4, 0x2a8, 0x2ac, 0x2b0, 0x2b4, 0x2b8, 0x2bc,
+ 0x2c0, 0x2c4, 0x2c8, 0x2cc, 0x2d0, 0x2d4, 0x2d8, 0x21c,
+};
+
+
+static const u32 vf610_ddrmc_io_offset[] __initconst = {
+ 0x00, 0x08, 0x28, 0x2c, 0x30, 0x34, 0x38,
+ 0x40, 0x44, 0x48, 0x50, 0x54, 0x58, 0x5c,
+ 0x60, 0x64, 0x68, 0x70, 0x74, 0x78, 0x7c,
+ 0x84, 0x88, 0x98, 0x9c, 0xa4, 0xc0,
+ 0x108, 0x10c, 0x114, 0x118, 0x120, 0x124,
+ 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c,
+ 0x148, 0x15c, 0x160, 0x164, 0x16c, 0x180,
+ 0x184, 0x188, 0x18c, 0x198, 0x1a4, 0x1a8,
+ 0x1b8, 0x1d4, 0x1d8, 0x1e0, 0x1e4, 0x1e8,
+ 0x1ec, 0x1f0, 0x1f8, 0x210, 0x224, 0x228,
+ 0x22c, 0x230, 0x23c, 0x240, 0x244, 0x248,
+ 0x24c, 0x250, 0x25c, 0x268, 0x26c, 0x278,
+ 0x268
+};
+
+static const u32 vf610_ddrmc_phy_io_offset[] __initconst = {
+ 0x00, 0x04, 0x08, 0x0c, 0x10,
+ 0x40, 0x44, 0x48, 0x4c, 0x50,
+ 0x80, 0x84, 0x88, 0x8c, 0x90,
+ 0xc4, 0xc8, 0xd0
+};
+
+/*
+ * suspend ocram space layout:
+ * ======================== high address ======================
+ * .
+ * .
+ * .
+ * ^
+ * ^
+ * ^
+ * vf610_suspend code
+ * PM_INFO structure(vf610_cpu_pm_info)
+ * ======================== low address =======================
+ */
+
+struct vf610_pm_base {
+ phys_addr_t pbase;
+ void __iomem *vbase;
+};
+
+struct vf610_pm_socdata {
+ const char *anatop_compat;
+ const char *scsc_compat;
+ const char *wkpu_compat;
+ const char *ccm_compat;
+ const char *gpc_compat;
+ const char *src_compat;
+ const char *ddrmc_compat;
+ const char *iomuxc_compat;
+};
+
+static const struct vf610_pm_socdata vf610_pm_data __initconst = {
+ .anatop_compat = "fsl,vf610-anatop",
+ .scsc_compat = "fsl,vf610-scsc",
+ .wkpu_compat = "fsl,vf610-wkpu",
+ .ccm_compat = "fsl,vf610-ccm",
+ .gpc_compat = "fsl,vf610-gpc",
+ .src_compat = "fsl,vf610-src",
+ .ddrmc_compat = "fsl,vf610-ddrmc",
+ .iomuxc_compat = "fsl,vf610-iomuxc",
+};
+
+/*
+ * This structure is for passing necessary data for low level ocram
+ * suspend code(arch/arm/mach-imx/suspend-vf610.S), if this struct
+ * definition is changed, the offset definition in
+ * arch/arm/mach-imx/suspend-vf610.S must be also changed accordingly,
+ * otherwise, the suspend to ocram function will be broken!
+ */
+struct vf610_cpu_pm_info {
+ phys_addr_t pbase; /* The physical address of pm_info. */
+ phys_addr_t resume_addr; /* The physical resume address for asm code */
+ u32 cpu_type; /* Currently not used, leave it for alignment */
+ u32 pm_info_size; /* Size of pm_info. */
+ struct vf610_pm_base anatop_base;
+ struct vf610_pm_base scsc_base;
+ struct vf610_pm_base wkpu_base;
+ struct vf610_pm_base ccm_base;
+ struct vf610_pm_base gpc_base;
+ struct vf610_pm_base src_base;
+ struct vf610_pm_base ddrmc_base;
+ struct vf610_pm_base iomuxc_base;
+ struct vf610_pm_base l2_base;
+ u32 ccm_cacrr;
+ u32 ccm_ccsr;
+ u32 ddrmc_io_num; /* Number of MMDC IOs which need saved/restored. */
+ u32 ddrmc_io_val[VF610_DDRMC_IO_NUM][2]; /* To save offset and value */
+ u32 iomux_ddr_io_num;
+ u32 iomux_ddr_io_val[VF610_IOMUX_DDR_IO_NUM][2];
+} __aligned(8);
+
+#ifdef DEBUG
+static void vf610_uart_reinit(unsigned long int rate, unsigned long int baud)
+{
+ u8 tmp, c2;
+ u16 sbr, brfa;
+
+ /* UART_C2 */
+ c2 = __raw_readb(uart_membase + 0x3);
+ __raw_writeb(0, uart_membase + 0x3);
+
+ sbr = (u16) (rate / (baud * 16));
+ brfa = (rate / baud) - (sbr * 16);
+
+ tmp = ((sbr & 0x1f00) >> 8);
+ __raw_writeb(tmp, uart_membase + 0x0);
+ tmp = sbr & 0x00ff;
+ __raw_writeb(tmp, uart_membase + 0x1);
+
+ /* UART_C4 */
+ __raw_writeb(brfa & 0xf, uart_membase + 0xa);
+
+ __raw_writeb(c2, uart_membase + 0x3);
+}
+#else
+#define vf610_uart_reinit(rate, baud)
+#endif
+
+static void vf610_set(void __iomem *pll_base, u32 mask)
+{
+ writel(readl(pll_base) | mask, pll_base);
+}
+
+static void vf610_clr(void __iomem *pll_base, u32 mask)
+{
+ writel(readl(pll_base) & ~mask, pll_base);
+}
+
+int vf610_set_lpm(enum vf610_cpu_pwr_mode mode)
+{
+ u32 ccr = readl_relaxed(ccm_base + CCR);
+ u32 ccsr = readl_relaxed(ccm_base + CCSR);
+ u32 cacrr = readl_relaxed(ccm_base + CACRR);
+ u32 cclpcr = 0;
+ u32 gpc_pgcr = 0;
+
+ struct vf610_cpu_pm_info *pm_info = suspend_ocram_base;
+ void __iomem *gpc_base = pm_info->gpc_base.vbase;
+ void __iomem *anatop = pm_info->anatop_base.vbase;
+
+ switch (mode) {
+ case VF610_LP_STOP:
+ /* Store clock settings */
+ pm_info->ccm_ccsr = ccsr;
+ pm_info->ccm_cacrr = cacrr;
+
+ ccr |= BM_CCR_FIRC_EN;
+ writel_relaxed(ccr, ccm_base + CCR);
+
+ cclpcr |= BM_CLPCR_ANADIG_STOP_MODE;
+ cclpcr |= BM_CLPCR_SBYOS;
+
+ cclpcr |= BM_CLPCR_MASK_SCU_IDLE;
+ cclpcr |= BM_CLPCR_MASK_L2CC_IDLE;
+ cclpcr |= BM_CLPCR_MASK_CORE1_WFI;
+ writel_relaxed(cclpcr, ccm_base + CLPCR);
+
+ gpc_pgcr |= BM_PGCR_DS_STOP;
+ gpc_pgcr |= BM_PGCR_DS_LPSTOP;
+ gpc_pgcr |= BM_PGCR_WB_STOP;
+ gpc_pgcr |= BM_PGCR_HP_OFF;
+ gpc_pgcr |= BM_PGCR_PG_PD1;
+ writel_relaxed(gpc_pgcr, gpc_base + GPC_PGCR);
+ break;
+ case VF610_STOP:
+ cclpcr &= ~BM_CLPCR_ANADIG_STOP_MODE;
+ cclpcr |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;
+ cclpcr |= BM_CLPCR_SBYOS;
+ writel_relaxed(cclpcr, ccm_base + CLPCR);
+
+ gpc_pgcr |= BM_PGCR_DS_STOP;
+ gpc_pgcr |= BM_PGCR_HP_OFF;
+ writel_relaxed(gpc_pgcr, gpc_base + GPC_PGCR);
+
+ /* fall-through */
+ case VF610_LP_RUN:
+ /* Store clock settings */
+ pm_info->ccm_ccsr = ccsr;
+ pm_info->ccm_cacrr = cacrr;
+
+ ccr |= BM_CCR_FIRC_EN;
+ writel_relaxed(ccr, ccm_base + CCR);
+
+ /* Enable PLL2 for DDR clock */
+ vf610_set(anatop + ANATOP_PLL2_CTRL, BM_PLL_ENABLE);
+ vf610_clr(anatop + ANATOP_PLL2_CTRL, BM_PLL_POWERDOWN);
+ vf610_clr(anatop + ANATOP_PLL2_CTRL, BM_PLL_BYPASS);
+ while (!(readl(anatop + ANATOP_PLL2_CTRL) & BM_PLL_LOCK));
+ vf610_clr(anatop + ANATOP_PLL2_PFD, BM_PLL_PFD2_CLKGATE);
+
+ /* Switch internal OSC's */
+ ccsr &= ~BM_CCSR_FAST_CLK_SEL;
+ ccsr &= ~BM_CCSR_SLOW_CLK_SEL;
+
+ /* Select PLL2 as DDR clock */
+ ccsr &= ~BM_CCSR_DDRC_CLK_SEL;
+ writel_relaxed(ccsr, ccm_base + CCSR);
+
+ ccsr &= ~BM_CCSR_SYS_CLK_SEL_MASK;
+ writel_relaxed(ccsr, ccm_base + CCSR);
+ vf610_uart_reinit(4000000UL, 115200);
+
+ vf610_set(anatop + ANATOP_PLL1_CTRL, BM_PLL_BYPASS);
+ writel_relaxed(BM_LPMR_STOP, gpc_base + GPC_LPMR);
+ break;
+ case VF610_RUN:
+ writel_relaxed(BM_LPMR_RUN, gpc_base + GPC_LPMR);
+
+ vf610_clr(anatop + ANATOP_PLL1_CTRL, BM_PLL_BYPASS);
+ while(!(readl(anatop + ANATOP_PLL1_CTRL) & BM_PLL_LOCK));
+
+ /* Restore clock settings */
+ writel(pm_info->ccm_ccsr, ccm_base + CCSR);
+
+ vf610_uart_reinit(uart_clk, 115200);
+ pr_pmdebug("resuming, uart_reinit done");
+
+ /* Disable PLL2 if not needed */
+ if (pm_info->ccm_ccsr & BM_CCSR_DDRC_CLK_SEL)
+ vf610_set(anatop + ANATOP_PLL2_CTRL, BM_PLL_POWERDOWN);
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vf610_suspend_finish(unsigned long val)
+{
+ if (!vf610_suspend_in_ocram_fn) {
+ cpu_do_idle();
+ } else {
+ /*
+ * call low level suspend function in ocram,
+ * as we need to float DDR IO.
+ */
+ local_flush_tlb_all();
+ flush_cache_all();
+ outer_flush_all();
+ vf610_suspend_in_ocram_fn(suspend_ocram_base);
+ }
+
+ return 0;
+}
+
+static int vf610_pm_enter(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ vf610_set_lpm(VF610_STOP);
+ flush_cache_all();
+
+ /* zzZZZzzz */
+ cpu_do_idle();
+
+ vf610_set_lpm(VF610_RUN);
+ break;
+ case PM_SUSPEND_MEM:
+ vf610_set_lpm(VF610_LP_STOP);
+
+ cpu_suspend(0, vf610_suspend_finish);
+ outer_resume();
+
+ vf610_set_lpm(VF610_RUN);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vf610_pm_valid(suspend_state_t state)
+{
+ return (state == PM_SUSPEND_STANDBY ||
+ (state == PM_SUSPEND_MEM && has_cke_reset_pulls));
+}
+
+static const struct platform_suspend_ops vf610_pm_ops = {
+ .enter = vf610_pm_enter,
+ .valid = vf610_pm_valid,
+};
+
+void __init vf610_pm_set_ccm_base(void __iomem *base)
+{
+ ccm_base = base;
+}
+
+static int __init imx_pm_get_base(struct vf610_pm_base *base,
+ const char *compat)
+{
+ struct device_node *node;
+ struct resource res;
+ int ret = 0;
+
+ node = of_find_compatible_node(NULL, NULL, compat);
+ if (!node) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret)
+ goto put_node;
+
+ base->pbase = res.start;
+ base->vbase = ioremap(res.start, resource_size(&res));
+
+ if (!base->vbase)
+ ret = -ENOMEM;
+
+put_node:
+ of_node_put(node);
+out:
+ return ret;
+}
+
+#ifdef DEBUG
+static int __init vf610_uart_init(void)
+{
+ struct device_node *dn;
+ const char *name;
+ struct clk *clk;
+ int ret;
+
+ name = of_get_property(of_chosen, "stdout-path", NULL);
+ if (name == NULL)
+ return -ENODEV;
+
+ dn = of_find_node_by_path(name);
+ if (!dn)
+ return -ENODEV;
+
+ clk = of_clk_get(dn, 0);
+
+ if (!clk) {
+ ret = PTR_ERR(clk);
+ goto put_node;
+ }
+
+ uart_clk = clk_get_rate(clk);
+
+ uart_membase = of_iomap(dn, 0);
+ if (!clk) {
+ ret = -ENOMEM;
+ goto put_node;
+ }
+
+ ret = 0;
+
+put_node:
+ of_node_put(dn);
+ return ret;
+}
+#endif
+
+static int __init vf610_suspend_init(const struct vf610_pm_socdata *socdata)
+{
+ phys_addr_t ocram_pbase;
+ struct device_node *node;
+ struct platform_device *pdev;
+ struct vf610_cpu_pm_info *pm_info;
+ struct gen_pool *ocram_pool;
+ unsigned long ocram_base;
+ int ret = 0, reg = 0;
+ int i;
+
+#ifdef DEBUG
+ ret = vf610_uart_init();
+ if (ret < 0)
+ return ret;
+#endif
+
+ node = of_find_compatible_node(NULL, NULL, socdata->ddrmc_compat);
+ if (node) {
+ has_cke_reset_pulls =
+ of_property_read_bool(node, "fsl,has-cke-reset-pulls");
+
+ of_node_put(node);
+ }
+
+ if (has_cke_reset_pulls)
+ pr_info("PM: CKE/RESET pulls available, enable Suspend-to-RAM\n");
+ else
+ pr_info("PM: No CKE/RESET pulls, disable Suspend-to-RAM\n");
+
+ suspend_set_ops(&vf610_pm_ops);
+
+ node = of_find_compatible_node(NULL, NULL, "mmio-sram");
+ if (!node) {
+ pr_warn("%s: failed to find ocram node!\n", __func__);
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(node);
+ if (!pdev) {
+ pr_warn("%s: failed to find ocram device!\n", __func__);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ ocram_pool = dev_get_gen_pool(&pdev->dev);
+ if (!ocram_pool) {
+ pr_warn("%s: ocram pool unavailable!\n", __func__);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ ocram_base = gen_pool_alloc(ocram_pool, VF610_SUSPEND_OCRAM_SIZE);
+ if (!ocram_base) {
+ pr_warn("%s: unable to alloc ocram!\n", __func__);
+ ret = -ENOMEM;
+ goto put_node;
+ }
+
+ ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);
+
+ suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
+ VF610_SUSPEND_OCRAM_SIZE, false);
+
+ pm_info = suspend_ocram_base;
+ pm_info->pbase = ocram_pbase;
+ pm_info->resume_addr = virt_to_phys(cpu_resume);
+ pm_info->pm_info_size = sizeof(*pm_info);
+
+ ret = imx_pm_get_base(&pm_info->anatop_base, socdata->anatop_compat);
+ if (ret) {
+ pr_warn("%s: failed to get anatop base %d!\n", __func__, ret);
+ goto put_node;
+ }
+
+ ret = imx_pm_get_base(&pm_info->scsc_base, socdata->scsc_compat);
+ if (ret) {
+ pr_warn("%s: failed to get scsc base %d!\n", __func__, ret);
+ goto scsc_map_failed;
+ }
+
+ ret = imx_pm_get_base(&pm_info->ccm_base, socdata->ccm_compat);
+ if (ret) {
+ pr_warn("%s: failed to get ccm base %d!\n", __func__, ret);
+ goto ccm_map_failed;
+ }
+
+ ret = imx_pm_get_base(&pm_info->gpc_base, socdata->gpc_compat);
+ if (ret) {
+ pr_warn("%s: failed to get gpc base %d!\n", __func__, ret);
+ goto gpc_map_failed;
+ }
+
+ ret = imx_pm_get_base(&pm_info->src_base, socdata->src_compat);
+ if (ret) {
+ pr_warn("%s: failed to get src base %d!\n", __func__, ret);
+ goto src_map_failed;
+ }
+
+ ret = imx_pm_get_base(&pm_info->ddrmc_base, socdata->ddrmc_compat);
+ if (ret) {
+ pr_warn("%s: failed to get ddrmc base %d!\n", __func__, ret);
+ goto ddrmc_map_failed;
+ }
+
+ ret = imx_pm_get_base(&pm_info->iomuxc_base, socdata->iomuxc_compat);
+ if (ret) {
+ pr_warn("%s: failed to get iomuxc base %d!\n", __func__, ret);
+ goto iomuxc_map_failed;
+ }
+
+ ret = imx_pm_get_base(&pm_info->l2_base, "arm,pl310-cache");
+ if (ret && ret != -ENODEV) {
+ pr_warn("%s: failed to get pl310-cache base %d!\n",
+ __func__, ret);
+ goto pl310_cache_map_failed;
+ }
+
+ pm_info->ddrmc_io_num = VF610_DDRMC_IO_NUM;
+
+ /* Store DDRMC registers */
+ for (i = 0; i < ARRAY_SIZE(vf610_ddrmc_io_offset); i++, reg++) {
+ pm_info->ddrmc_io_val[reg][0] = vf610_ddrmc_io_offset[i];
+ pm_info->ddrmc_io_val[reg][1] =
+ readl_relaxed(pm_info->ddrmc_base.vbase +
+ vf610_ddrmc_io_offset[i]);
+ }
+
+ /* Store DDRMC PHY registers */
+ for (i = 0; i < ARRAY_SIZE(vf610_ddrmc_phy_io_offset); i++, reg++) {
+ pm_info->ddrmc_io_val[reg][0] = vf610_ddrmc_phy_io_offset[i] +
+ DDRMC_PHY_OFFSET;
+ pm_info->ddrmc_io_val[reg][1] =
+ readl_relaxed(pm_info->ddrmc_base.vbase +
+ DDRMC_PHY_OFFSET + vf610_ddrmc_phy_io_offset[i]);
+ }
+
+ /* Store IOMUX DDR pad registers */
+ pm_info->iomux_ddr_io_num = VF610_IOMUX_DDR_IO_NUM;
+ for (i = 0; i < ARRAY_SIZE(vf610_iomuxc_ddr_io_offset); i++) {
+ pm_info->iomux_ddr_io_val[i][0] = vf610_iomuxc_ddr_io_offset[i];
+ pm_info->iomux_ddr_io_val[i][1] =
+ readl_relaxed(pm_info->iomuxc_base.vbase +
+ vf610_iomuxc_ddr_io_offset[i]);
+ }
+
+ vf610_suspend_in_ocram_fn = fncpy(
+ suspend_ocram_base + sizeof(*pm_info),
+ &vf610_suspend,
+ VF610_SUSPEND_OCRAM_SIZE - sizeof(*pm_info));
+
+ goto put_node;
+
+pl310_cache_map_failed:
+ iounmap(&pm_info->iomuxc_base.vbase);
+iomuxc_map_failed:
+ iounmap(&pm_info->ddrmc_base.vbase);
+ddrmc_map_failed:
+ iounmap(&pm_info->src_base.vbase);
+src_map_failed:
+ iounmap(&pm_info->gpc_base.vbase);
+gpc_map_failed:
+ iounmap(&pm_info->ccm_base.vbase);
+ccm_map_failed:
+ iounmap(&pm_info->scsc_base.vbase);
+scsc_map_failed:
+ iounmap(&pm_info->anatop_base.vbase);
+put_node:
+ of_node_put(node);
+
+ return ret;
+}
+
+void __init vf610_pm_init(void)
+{
+ int ret;
+
+ WARN_ON(!ccm_base);
+
+ if (IS_ENABLED(CONFIG_SUSPEND)) {
+ ret = vf610_suspend_init(&vf610_pm_data);
+ if (ret)
+ pr_warn("%s: No DDR LPM support with suspend %d!\n",
+ __func__, ret);
+ }
+}
+
diff --git a/arch/arm/mach-imx/suspend-vf610.S b/arch/arm/mach-imx/suspend-vf610.S
new file mode 100644
index 000000000000..595dd4e2c74c
--- /dev/null
+++ b/arch/arm/mach-imx/suspend-vf610.S
@@ -0,0 +1,448 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ * Copyright 2015 Toradex AG
+ *
+ * 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 <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
+
+/*
+ * ==================== low level suspend ====================
+ *
+ * Better to follow below rules to use ARM registers:
+ * r0: pm_info structure address;
+ * r1 ~ r4: for saving pm_info members;
+ * r5 ~ r10: free registers;
+ * r11: io base address.
+ *
+ * suspend ocram space layout:
+ * ======================== high address ======================
+ * .
+ * .
+ * .
+ * ^
+ * ^
+ * ^
+ * vf610_suspend code
+ * PM_INFO structure(vf610_cpu_pm_info)
+ * ======================== low address =======================
+ */
+
+/*
+ * Below offsets are based on struct vf610_cpu_pm_info
+ * which defined in arch/arm/mach-imx/pm-vf610.c, this
+ * structure contains necessary pm info for low level
+ * suspend related code.
+ */
+#define PM_INFO_PBASE_OFFSET 0x0
+#define PM_INFO_RESUME_ADDR_OFFSET 0x4
+#define PM_INFO_CPU_TYPE_OFFSET 0x8
+#define PM_INFO_PM_INFO_SIZE_OFFSET 0xC
+#define PM_INFO_VF610_ANATOP_P_OFFSET 0x10
+#define PM_INFO_VF610_ANATOP_V_OFFSET 0x14
+#define PM_INFO_VF610_SCSC_P_OFFSET 0x18
+#define PM_INFO_VF610_SCSC_V_OFFSET 0x1C
+#define PM_INFO_VF610_WKPU_P_OFFSET 0x20
+#define PM_INFO_VF610_WKPU_V_OFFSET 0x24
+#define PM_INFO_VF610_CCM_P_OFFSET 0x28
+#define PM_INFO_VF610_CCM_V_OFFSET 0x2C
+#define PM_INFO_VF610_GPC_P_OFFSET 0x30
+#define PM_INFO_VF610_GPC_V_OFFSET 0x34
+#define PM_INFO_VF610_SRC_P_OFFSET 0x38
+#define PM_INFO_VF610_SRC_V_OFFSET 0x3C
+#define PM_INFO_VF610_DDRMC_P_OFFSET 0x40
+#define PM_INFO_VF610_DDRMC_V_OFFSET 0x44
+#define PM_INFO_VF610_IOMUXC_P_OFFSET 0x48
+#define PM_INFO_VF610_IOMUXC_V_OFFSET 0x4c
+#define PM_INFO_VF610_L2_P_OFFSET 0x50
+#define PM_INFO_VF610_L2_V_OFFSET 0x54
+#define PM_INFO_CCM_CACRR 0x58
+#define PM_INFO_CCM_CCSR 0x5c
+#define PM_INFO_DDRMC_IO_NUM_OFFSET 0x60
+#define PM_INFO_DDRMC_IO_VAL_OFFSET 0x64
+#define PM_INFO_IOMUXC_DDR_IO_NUM_OFFSET (0x64 + 94 * 2 * 4)
+#define PM_INFO_IOMUXC_DDR_IO_VAL_OFFSET (0x68 + 94 * 2 * 4)
+
+#define VF610_ANADIG_PLL2_CTRL 0x30
+
+#define VF610_ANADIG_MISC0 0x150
+#define VF610_ANADIG_MISC0_CLK_24M_IRC_XTAL_SEL (0x1 < 13)
+
+#define VF610_ANADIG_PLL1_CTRL 0x270
+
+#define VF610_ANADIG_POWERDOWN (1 << 12)
+#define VF610_ANADIG_ENABLE (1 << 13)
+#define VF610_ANADIG_BYPASS (1 << 16)
+#define VF610_ANADIG_LOCK (1 << 31)
+
+#define VF610_SCSC_SIRC 0x0
+#define VF610_SCSC_SIRC_SIRC_EN (0x1 << 0)
+#define VF610_SCSC_SOSC 0x4
+#define VF610_SCSC_SOSC_SOSC_EN (0x1 << 0)
+
+#define VF610_GPC_PGCR 0x0
+#define VF610_GPC_LPMR 0x40
+
+#define VF610_CCM_CCR 0x00
+#define VF610_CCM_CCR_FXOSC_EN (0x1 << 12)
+
+#define VF610_CCM_CCSR 0x08
+#define VF610_CCM_CCSR_DDRC_CLK_SEL (0x1 << 6)
+#define VF610_CCM_CCSR_FAST_CLK_SEL (0x1 << 5)
+
+#define VF610_CCM_CACRR 0x0C
+
+#define VF610_CCM_CLPCR 0x2C
+#define VF610_CCM_CLPCR_DIS_REF_OSC (0x1 << 7)
+#define VF610_CCM_CLPCR_FXOSC_PWRDWN (0x1 << 11)
+
+#define VF610_CCM_CCGR0 0x40
+#define VF610_CCM_CCGR2 0x48
+#define VF610_CCM_CCGR3 0x4C
+#define VF610_CCM_CCGR4 0x50
+#define VF610_CCM_CCGR6 0x58
+
+#define VF610_SRC_GPR0 0x20
+#define VF610_SRC_GPR1 0x24
+#define VF610_SRC_MISC2 0x54
+
+#define VF610_DDRMC_CR00 0x0
+#define VF610_DDRMC_CR00_START (0x1 << 0)
+
+#define VF610_DDRMC_CR33 0x84
+#define VF610_DDRMC_CR33_PWUP_SREF_EX (0x1 << 0)
+
+#define VF610_DDRMC_CR34 0x88
+
+#define VF610_DDRMC_CR35 0x8C
+#define VF610_DDRMC_CR35_LP_CMD(cmd) ((cmd) << 8)
+
+#define VF610_DDRMC_CR80 0x140
+#define VF610_DDRMC_CR80_LP_COMPLETE (0x1 << 9)
+#define VF610_DDRMC_CR80_INIT_COMPLETE (0x1 << 8)
+#define VF610_DDRMC_CR81 0x144
+
+ .align 3
+
+ /*
+ * Take DDR RAM out of Low-Power mode
+ */
+ .macro resume_ddrmc ddrmc_base
+
+ /* Clear low power complete flag... */
+ ldr r6, =VF610_DDRMC_CR80_LP_COMPLETE
+ str r6, [\ddrmc_base, #VF610_DDRMC_CR81]
+
+ ldr r6, [\ddrmc_base, #VF610_DDRMC_CR35]
+ orr r6, r6, #VF610_DDRMC_CR35_LP_CMD(0x9)
+ str r6, [\ddrmc_base, #VF610_DDRMC_CR35]
+
+1:
+ ldr r5, [\ddrmc_base, #VF610_DDRMC_CR80]
+ ands r5, r5, #VF610_DDRMC_CR80_LP_COMPLETE
+ beq 1b
+
+ .endm
+
+ .macro enable_syspll pll_base
+
+ ldr r5, [\pll_base]
+ orr r5, r5, #VF610_ANADIG_ENABLE
+ bic r5, r5, #VF610_ANADIG_POWERDOWN
+ bic r5, r5, #VF610_ANADIG_BYPASS
+ str r5, [\pll_base]
+
+1:
+ ldr r5, [\pll_base]
+ tst r5, #VF610_ANADIG_LOCK
+ beq 1b
+
+ .endm
+
+ENTRY(vf610_suspend)
+ ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
+ ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
+ ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
+ ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
+
+ /*
+ * make sure TLB contain the addr we want,
+ * as we will access them after MMDC IO floated.
+ */
+
+ ldr r11, [r0, #PM_INFO_VF610_DDRMC_V_OFFSET]
+ ldr r6, [r11, #0x0]
+ ldr r11, [r0, #PM_INFO_VF610_GPC_V_OFFSET]
+ ldr r6, [r11, #0x0]
+ ldr r11, [r0, #PM_INFO_VF610_SRC_V_OFFSET]
+ ldr r6, [r11, #0x0]
+ ldr r11, [r0, #PM_INFO_VF610_CCM_V_OFFSET]
+ ldr r6, [r11, #0x0]
+
+ ldr r11, [r0, #PM_INFO_VF610_SRC_V_OFFSET]
+
+ /* Disable DDR RESET */
+ ldr r6, [r11, #VF610_SRC_MISC2]
+ orr r6, r6, #0x1
+ str r6, [r11, #VF610_SRC_MISC2]
+
+ /* Set ENTRY/ARGUMENT register */
+ ldr r6, =vf610_suspend
+ ldr r7, =resume
+ sub r7, r7, r6
+ add r8, r1, r4
+ add r9, r8, r7
+ str r9, [r11, #VF610_SRC_GPR0]
+ str r1, [r11, #VF610_SRC_GPR1]
+
+ /* Put memory in self refresh... */
+ ldr r11, [r0, #PM_INFO_VF610_DDRMC_V_OFFSET]
+
+ ldr r6, =VF610_DDRMC_CR80_LP_COMPLETE
+ str r6, [r11, #VF610_DDRMC_CR81]
+
+ ldr r6, [r11, #VF610_DDRMC_CR35]
+ orr r6, r6, #VF610_DDRMC_CR35_LP_CMD(0xA)
+ str r6, [r11, #VF610_DDRMC_CR35]
+
+ddrmc_cmd_complete:
+ /* A Unfixed module seems to hang at this read.... */
+ ldr r5, [r11, #VF610_DDRMC_CR80]
+ ands r5, r5, #VF610_DDRMC_CR80_LP_COMPLETE
+ beq ddrmc_cmd_complete
+
+ /* switch to internal FIRC */
+ ldr r11, [r0, #PM_INFO_VF610_CCM_V_OFFSET]
+ ldr r5, [r11, #VF610_CCM_CCSR]
+ bic r5, r5, #0x30 /* FAST_/SLOW_CLK_SEL */
+ str r5, [r11, #VF610_CCM_CCSR]
+ bic r5, r5, #0x07 /* SYS_CLK_SEL */
+ str r5, [r11, #VF610_CCM_CCSR]
+
+ /* LP-Mode: STOP */
+ ldr r11, [r0, #PM_INFO_VF610_GPC_V_OFFSET]
+ ldr r6, =0x02
+ str r6, [r11, #VF610_GPC_LPMR]
+
+ /* Zzz, enter stop mode */
+ wfi
+ nop
+ nop
+ nop
+ nop
+
+ /* If we get here, there is already an interrupt pending. Restore... */
+ ldr r6, =0x00
+ str r6, [r11, #VF610_GPC_LPMR]
+
+ /* Get previous CCSR/CACRR settings */
+ ldr r11, [r0, #PM_INFO_VF610_CCM_V_OFFSET]
+ ldr r5, [r0, #PM_INFO_CCM_CCSR]
+ str r5, [r11, #VF610_CCM_CCSR]
+
+ ldr r5, [r0, #PM_INFO_CCM_CACRR]
+ str r5, [r11, #VF610_CCM_CACRR]
+
+ ldr r11, [r0, #PM_INFO_VF610_DDRMC_V_OFFSET]
+ resume_ddrmc r11
+
+ ret lr
+
+/* Resume path if CPU uses the SRC_GPR0 (PERSISTENT_ENTRY0) */
+resume:
+ /* invalidate L1 I-cache first */
+ mov r6, #0x0
+ mcr p15, 0, r6, c7, c5, 0
+ mcr p15, 0, r6, c7, c5, 6
+
+ /* enable the Icache and branch prediction */
+ mov r6, #0x1800
+ mcr p15, 0, r6, c1, c0, 0
+ isb
+
+ ldr r11, [r0, #PM_INFO_VF610_CCM_P_OFFSET]
+
+ ldr r5, [r11, #VF610_CCM_CCSR]
+ orr r5, r5, #(1 << 13)
+ str r5, [r11, #VF610_CCM_CCSR]
+
+ /* enable UART0 */
+ ldr r5, [r11, #VF610_CCM_CCGR0]
+ orr r5, r5, #0xC000
+ str r5, [r11, #VF610_CCM_CCGR0]
+
+ /* enable IOMUX, PORT A-E */
+ ldr r5, [r11, #VF610_CCM_CCGR2]
+ ldr r6, =0xFFF0000
+ orr r5, r5, r6
+ str r5, [r11, #VF610_CCM_CCGR2]
+
+ /* enable ANADIG and SCSM */
+ ldr r5, [r11, #VF610_CCM_CCGR3]
+ orr r5, r5, #0x33
+ str r5, [r11, #VF610_CCM_CCGR3]
+
+ /* enable GPC, CCM and WKUP */
+ ldr r5, [r11, #VF610_CCM_CCGR4]
+ orr r5, r5, #0x3f00000
+ str r5, [r11, #VF610_CCM_CCGR4]
+
+ /* enable mmdc */
+ ldr r5, [r11, #VF610_CCM_CCGR6]
+ orr r5, r5, #0x30000000
+ str r5, [r11, #VF610_CCM_CCGR6]
+
+ /* Mux UART0 */
+ ldr r5,=0x1021a2
+ ldr r6,=0x40048080
+ str r5, [r6, #0x0]
+ ldr r5,=0x1021a1
+ ldr r6,=0x40048084
+ str r5, [r6, #0x0]
+
+ /* Set IOMUX for DDR pads */
+ ldr r11, [r0, #PM_INFO_VF610_IOMUXC_P_OFFSET]
+
+ ldr r6, [r0, #PM_INFO_IOMUXC_DDR_IO_NUM_OFFSET]
+ ldr r7, =PM_INFO_IOMUXC_DDR_IO_VAL_OFFSET
+ add r7, r7, r0
+
+loop_iomuxc_ddr_restore:
+ ldr r8, [r7], #0x4
+ ldr r9, [r7], #0x4
+ str r9, [r11, r8]
+ subs r6, r6, #0x1
+ bne loop_iomuxc_ddr_restore
+
+
+ /* Enable slow oscilators */
+ ldr r11, [r0, #PM_INFO_VF610_SCSC_P_OFFSET]
+
+ ldr r5, [r11, #VF610_SCSC_SOSC]
+ orr r5, r5, #VF610_SCSC_SOSC_SOSC_EN
+ str r5, [r11, #VF610_SCSC_SOSC]
+
+ ldr r5, [r11, #VF610_SCSC_SIRC]
+ orr r5, r5, #VF610_SCSC_SIRC_SIRC_EN
+ str r5, [r11, #VF610_SCSC_SIRC]
+
+ /* Enable fast osciallator */
+ ldr r11, [r0, #PM_INFO_VF610_CCM_P_OFFSET]
+
+ ldr r5, [r11, #VF610_CCM_CLPCR]
+ bic r5, r5, #VF610_CCM_CLPCR_DIS_REF_OSC
+ bic r5, r5, #VF610_CCM_CLPCR_FXOSC_PWRDWN
+ str r5, [r11, #VF610_CCM_CLPCR]
+
+ ldr r5, [r11, #VF610_CCM_CCR]
+ orr r5, r5, #VF610_CCM_CCR_FXOSC_EN
+ str r5, [r11, #VF610_CCM_CCR]
+
+ ldr r5, [r11, #VF610_CCM_CCSR]
+ orr r5, r5, #VF610_CCM_CCSR_FAST_CLK_SEL
+ str r5, [r11, #VF610_CCM_CCSR]
+
+ ldr r11, [r0, #PM_INFO_VF610_ANATOP_P_OFFSET]
+
+ /* Select external FXOSC */
+ ldr r5, [r11, #VF610_ANADIG_MISC0]
+ bic r5, r5, #VF610_ANADIG_MISC0_CLK_24M_IRC_XTAL_SEL
+ str r5, [r11, #VF610_ANADIG_MISC0]
+
+ /* pll1 enable */
+ add r6, r11, #VF610_ANADIG_PLL1_CTRL
+ enable_syspll r6
+
+ /* enable pll2 only if required for DDR */
+ ldr r5, [r0, #PM_INFO_CCM_CCSR]
+ tst r5, #VF610_CCM_CCSR_DDRC_CLK_SEL
+ bne switch_sysclk
+
+ /* pll2 enable */
+ add r6, r11, #VF610_ANADIG_PLL2_CTRL
+ enable_syspll r6
+
+switch_sysclk:
+
+ /* Enable PFD and switch to fast clock */
+ ldr r11, [r0, #PM_INFO_VF610_CCM_P_OFFSET]
+
+ /* Get previous CCSR/CACRR settings */
+ ldr r5, [r0, #PM_INFO_CCM_CCSR]
+ str r5, [r11, #VF610_CCM_CCSR]
+
+ ldr r5, [r0, #PM_INFO_CCM_CACRR]
+ str r5, [r11, #VF610_CCM_CACRR]
+
+ /* Restore memory configuration */
+ ldr r11, [r0, #PM_INFO_VF610_DDRMC_P_OFFSET]
+
+ ldr r6, [r0, #PM_INFO_DDRMC_IO_NUM_OFFSET]
+ ldr r7, =PM_INFO_DDRMC_IO_VAL_OFFSET
+ add r7, r7, r0
+
+ /* Clear start bit of first memory register, do not start yet... */
+ ldr r8, [r7], #0x4
+ ldr r9, [r7], #0x4
+ bic r9, r9, #VF610_DDRMC_CR00_START
+ str r9, [r11, r8]
+ subs r6, r6, #0x1
+
+loop_ddrmc_restore:
+ ldr r8, [r7], #0x4
+ ldr r9, [r7], #0x4
+ str r9, [r11, r8]
+ subs r6, r6, #0x1
+ bne loop_ddrmc_restore
+
+ /* Set PWUP_SREF_EX to avoid a full memory initialization */
+ ldr r6, [r11, #VF610_DDRMC_CR33]
+ orr r6, r6, #VF610_DDRMC_CR33_PWUP_SREF_EX
+ str r6, [r11, #VF610_DDRMC_CR33]
+
+ /* Start initialization */
+ ldr r6, =VF610_DDRMC_CR80_INIT_COMPLETE
+ str r6, [r11, #VF610_DDRMC_CR81]
+
+ ldr r6, [r11, #VF610_DDRMC_CR00]
+ orr r6, r6, #VF610_DDRMC_CR00_START
+ str r6, [r11, #VF610_DDRMC_CR00]
+
+ddrmc_initializing:
+ ldr r5, [r11, #VF610_DDRMC_CR80]
+ ands r5, r5, #VF610_DDRMC_CR80_INIT_COMPLETE
+ beq ddrmc_initializing
+
+ resume_ddrmc r11
+
+ /* LP-Mode: RUN */
+ ldr r11, [r0, #PM_INFO_VF610_GPC_P_OFFSET]
+ ldr r5, =0x0
+ str r5, [r11, #VF610_GPC_LPMR]
+
+ /* Enable SNVS */
+ ldr r3, [r0, #PM_INFO_VF610_CCM_P_OFFSET]
+ ldr r4, [r3, #VF610_CCM_CCGR6]
+ orr r4, r4, #0x0000C000
+ str r4, [r3, #VF610_CCM_CCGR6]
+
+ /* Enable SNVS access (RTC) */
+ ldr r11, =0x400a7000
+ ldr r4, =0x80000100
+ str r4, [r11, #0x4]
+
+ /* get physical resume address from pm_info. */
+ ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
+
+ ret lr
+ENDPROC(vf610_suspend)
+
diff --git a/arch/arm/mach-imx/vf610_sema4.c b/arch/arm/mach-imx/vf610_sema4.c
new file mode 100644
index 000000000000..9b4d7a74a8ab
--- /dev/null
+++ b/arch/arm/mach-imx/vf610_sema4.c
@@ -0,0 +1,314 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include "hardware.h"
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <linux/debugfs.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <linux/vf610_sema4.h>
+// ************************************ Local Data *************************************************
+
+#define NUM_GATES 16
+#define MASK_FROM_GATE(gate_num) ((u32)(1 << (NUM_GATES*2 - 1 - idx[gate_num])))
+
+#define THIS_CORE (0)
+#define LOCK_VALUE (THIS_CORE + 1)
+
+#define SEMA4_CP0INE (0x40)
+#define SEMA4_CP0NTF (0x80)
+
+static MVF_SEMA4* gates[NUM_GATES];
+static void __iomem *sema4_base;
+
+// account for the way the bits are set / returned in CP0INE and CP0NTF
+static const int idx[16] = {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12};
+
+// debugfs
+#define DEBUGFS_DIR "mvf_sema4"
+static struct dentry *debugfs_dir;
+
+// ************************************ Interrupt handler *************************************************
+
+static irqreturn_t sema4_irq_handler(int irq, void *dev_id)
+{
+ int gate_num;
+
+ u32 cp0ntf = readl(sema4_base + SEMA4_CP0NTF);
+
+ for(gate_num=0; gate_num<NUM_GATES; gate_num++)
+ {
+ // interrupt from this gate?
+ if(cp0ntf & MASK_FROM_GATE(gate_num))
+ {
+ // grab the gate to stop the interrupts
+ writeb(LOCK_VALUE, sema4_base + gate_num);
+
+ // make sure there's a gate assigned
+ if(gates[gate_num])
+ {
+ //if(gates[gate_num]->use_interrupts) {
+ // wake up whoever was aiting
+ wake_up_interruptible(&(gates[gate_num]->wait_queue));
+ // bump stats
+ gates[gate_num]->interrupts++;
+ //}
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+// ************************************ Utility functions *************************************************
+
+int mvf_sema4_assign(int gate_num, MVF_SEMA4** sema4_p)
+{
+ u32 cp0ine;
+ unsigned long irq_flags;
+ char debugfs_gatedir_name[4];
+ struct dentry *debugfs_gate_dir;
+
+ if((gate_num < 0) || (gate_num >= NUM_GATES))
+ return -EINVAL;
+
+ if(gates[gate_num])
+ return -EBUSY;
+
+ *sema4_p = (MVF_SEMA4 *)kmalloc(sizeof(MVF_SEMA4), GFP_KERNEL);
+ if(*sema4_p == NULL)
+ return -ENOMEM;
+ memset(*sema4_p, 0, sizeof(MVF_SEMA4));
+
+ gates[gate_num] = *sema4_p;
+ (*sema4_p)->gate_num = gate_num;
+
+ init_waitqueue_head(&((*sema4_p)->wait_queue));
+ local_irq_save(irq_flags);
+ cp0ine = readl(sema4_base + SEMA4_CP0INE);
+ cp0ine |= MASK_FROM_GATE(gate_num);
+ writel(cp0ine, sema4_base + SEMA4_CP0INE);
+ local_irq_restore(irq_flags);
+
+ // debugfs
+ sprintf(debugfs_gatedir_name, "%d", gate_num);
+ debugfs_gate_dir = debugfs_create_dir(debugfs_gatedir_name, debugfs_dir);
+ debugfs_create_u32("attempts", S_IRUGO | S_IWUGO, debugfs_gate_dir, &(*sema4_p)->attempts);
+ debugfs_create_u32("interrupts", S_IRUGO | S_IWUGO, debugfs_gate_dir, &(*sema4_p)->interrupts);
+ debugfs_create_u32("failures", S_IRUGO | S_IWUGO, debugfs_gate_dir, &(*sema4_p)->failures);
+ debugfs_create_u64("total_latency_us", S_IRUGO | S_IWUGO, debugfs_gate_dir, &(*sema4_p)->total_latency_us);
+ debugfs_create_u32("worst_latency_us", S_IRUGO | S_IWUGO, debugfs_gate_dir, &(*sema4_p)->worst_latency_us);
+
+ return 0;
+}
+EXPORT_SYMBOL(mvf_sema4_assign);
+
+int mvf_sema4_deassign(MVF_SEMA4 *sema4)
+{
+ u32 cp0ine;
+ unsigned long irq_flags;
+
+ int gate_num;
+ if(!sema4)
+ return -EINVAL;
+ gate_num = sema4->gate_num;
+
+ local_irq_save(irq_flags);
+ cp0ine = readl(sema4_base + SEMA4_CP0INE);
+ cp0ine &= ~MASK_FROM_GATE(gate_num);
+ writel(cp0ine, sema4_base + SEMA4_CP0INE);
+ local_irq_restore(irq_flags);
+
+ kfree(sema4);
+ gates[gate_num] = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(mvf_sema4_deassign);
+
+static long delta_time(struct timeval *start) {
+
+ struct timeval now;
+ long now_us, start_us;
+
+ do_gettimeofday(&now);
+
+ now_us = (now.tv_sec * 1000000) + now.tv_usec;
+ start_us = (start->tv_sec * 1000000) + start->tv_usec;
+
+ return now_us > start_us ? now_us - start_us : 0;
+}
+
+static void add_latency_stat(MVF_SEMA4 *sema4) {
+
+ long latency = delta_time(&sema4->request_time);
+
+ sema4->total_latency_us += latency;
+ sema4->worst_latency_us = sema4->worst_latency_us < latency ? latency : sema4->worst_latency_us;
+}
+
+int mvf_sema4_lock(MVF_SEMA4 *sema4, unsigned int timeout_us, bool use_interrupts)
+{
+ int retval;
+ int gate_num;
+ if(!sema4)
+ return -EINVAL;
+ gate_num = sema4->gate_num;
+
+ // bump stats
+ gates[gate_num]->attempts++;
+ do_gettimeofday(&gates[gate_num]->request_time);
+
+ // try to grab it
+ writeb(LOCK_VALUE, sema4_base + gate_num);
+ if(readb(sema4_base + gate_num) == LOCK_VALUE) {
+ add_latency_stat(gates[gate_num]);
+ return 0;
+ }
+
+ // no timeout, fail
+ if(!timeout_us) {
+ gates[gate_num]->failures++;
+ return -EBUSY;
+ }
+
+ // spin lock?
+ if(!use_interrupts) {
+ while(readb(sema4_base + gate_num) != LOCK_VALUE) {
+
+ if((timeout_us != 0xffffffff) && (delta_time(&gates[gate_num]->request_time) > timeout_us)) {
+ gates[gate_num]->failures++;
+ return -EBUSY;
+ }
+
+ writeb(LOCK_VALUE, sema4_base + gate_num);
+ }
+ add_latency_stat(gates[gate_num]);
+ return 0;
+ }
+
+ // wait forever?
+ if(timeout_us == 0xffffffff)
+ {
+ if(wait_event_interruptible(sema4->wait_queue, (readb(sema4_base + gate_num) == LOCK_VALUE))) {
+ gates[gate_num]->failures++;
+ return -ERESTARTSYS;
+ }
+ }
+ else
+ {
+ // return: 0 = timeout, >0 = woke up with that many jiffies left, <0 = error
+ retval = wait_event_interruptible_timeout(sema4->wait_queue,
+ (readb(sema4_base + gate_num) == LOCK_VALUE),
+ usecs_to_jiffies(timeout_us));
+ if(retval == 0) {
+ gates[gate_num]->failures++;
+ return -ETIME;
+ }
+ else if(retval < 0) {
+ gates[gate_num]->failures++;
+ return retval;
+ }
+ }
+
+ add_latency_stat(gates[gate_num]);
+ return 0;
+}
+EXPORT_SYMBOL(mvf_sema4_lock);
+
+int mvf_sema4_unlock(MVF_SEMA4 *sema4)
+{
+ if(!sema4)
+ return -EINVAL;
+
+ // unlock it
+ writeb(0, sema4_base + sema4->gate_num);
+
+ return 0;
+}
+EXPORT_SYMBOL(mvf_sema4_unlock);
+
+// return 0 on success (meaning it is set to us)
+int mvf_sema4_test(MVF_SEMA4 *sema4)
+{
+ if(!sema4)
+ return -EINVAL;
+
+ return (readb(sema4_base + sema4->gate_num)) == LOCK_VALUE ? 0 : 1;
+}
+EXPORT_SYMBOL(mvf_sema4_test);
+
+static int vf610_sema4_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *iores;
+ int irq, ret, i;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sema4_base = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(sema4_base))
+ return PTR_ERR(sema4_base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq specified\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, sema4_irq_handler, 0, "SEMA4", NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+ return ret;
+ }
+
+ // clear the gates table
+ for (i = 0; i < NUM_GATES; i++)
+ gates[i] = NULL;
+
+ writel_relaxed(0, sema4_base + SEMA4_CP0INE);
+
+ // debugfs
+ debugfs_dir = debugfs_create_dir(DEBUGFS_DIR, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id vf610_sema4_dt_ids[] = {
+ { .compatible = "fsl,vf610-sema4" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver vf610_sema4_compat_driver = {
+ .driver = {
+ .name = "vf610-sema4",
+ .owner = THIS_MODULE,
+ .of_match_table = vf610_sema4_dt_ids,
+ },
+ .probe = vf610_sema4_probe,
+};
+
+static int __init vf610_sema4_compat_init(void)
+{
+ return platform_driver_register(&vf610_sema4_compat_driver);
+}
+device_initcall(vf610_sema4_compat_init);
+
+MODULE_DESCRIPTION("Freescale SEMA4 driver");
+MODULE_LICENSE("GPL v2");