diff options
Diffstat (limited to 'arch/arm')
205 files changed, 34157 insertions, 829 deletions
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b21b3a64641a..0ec6f5b4e5a6 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -435,8 +435,19 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-rex-basic.dtb \ imx6dl-riotboard.dtb \ imx6dl-sabreauto.dtb \ + imx6dl-sabreauto-enetirq.dtb \ + imx6dl-sabreauto-flexcan1.dtb \ + imx6dl-sabreauto-ecspi.dtb \ + imx6dl-sabreauto-gpmi-weim.dtb \ + imx6dl-sabreauto-pcie.dtb \ imx6dl-sabrelite.dtb \ imx6dl-sabresd.dtb \ + imx6dl-sabresd-ldo.dtb \ + imx6dl-sabresd-btwifi.dtb \ + imx6dl-sabresd-hdcp.dtb \ + imx6dl-sabresd-enetirq.dtb \ + imx6dl-sabresd-pcie.dtb \ + imx6dl-sabresd-pcie-ep.dtb \ imx6dl-savageboard.dtb \ imx6dl-ts4900.dtb \ imx6dl-ts7970.dtb \ @@ -514,8 +525,20 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-pistachio.dtb \ imx6q-rex-pro.dtb \ imx6q-sabreauto.dtb \ + imx6q-sabreauto-enetirq.dtb \ + imx6q-sabreauto-flexcan1.dtb \ + imx6q-sabreauto-ecspi.dtb \ + imx6q-sabreauto-gpmi-weim.dtb \ + imx6q-sabreauto-pcie.dtb \ imx6q-sabrelite.dtb \ imx6q-sabresd.dtb \ + imx6q-sabresd-ldo.dtb \ + imx6q-sabresd-btwifi.dtb \ + imx6q-sabresd-hdcp.dtb \ + imx6q-sabresd-uart.dtb \ + imx6q-sabresd-enetirq.dtb \ + imx6q-sabresd-pcie.dtb \ + imx6q-sabresd-pcie-ep.dtb \ imx6q-savageboard.dtb \ imx6q-sbc6x.dtb \ imx6q-tbs2910.dtb \ @@ -541,7 +564,14 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6qp-nitrogen6_som2.dtb \ imx6qp-phytec-mira-rdk-nand.dtb \ imx6qp-sabreauto.dtb \ + imx6qp-sabreauto-flexcan1.dtb \ + imx6qp-sabreauto-ecspi.dtb \ + imx6qp-sabreauto-gpmi-weim.dtb \ imx6qp-sabresd.dtb \ + imx6qp-sabresd-ldo.dtb \ + imx6qp-sabresd-btwifi.dtb \ + imx6qp-sabresd-hdcp.dtb \ + imx6qp-sabresd-pcie-ep.dtb \ imx6qp-tx6qp-8037.dtb \ imx6qp-tx6qp-8037-mb7.dtb \ imx6qp-tx6qp-8137.dtb \ @@ -550,21 +580,46 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6qp-zii-rdu2.dtb dtb-$(CONFIG_SOC_IMX6SL) += \ imx6sl-evk.dtb \ + imx6sl-evk-ldo.dtb \ + imx6sl-evk-csi.dtb \ + imx6sl-evk-uart.dtb \ + imx6sl-evk-btwifi.dtb \ imx6sl-warp.dtb dtb-$(CONFIG_SOC_IMX6SLL) += \ - imx6sll-evk.dtb + imx6sll-evk.dtb \ + imx6sll-evk-reva.dtb \ + imx6sll-evk-btwifi.dtb dtb-$(CONFIG_SOC_IMX6SX) += \ imx6sx-nitrogen6sx.dtb \ imx6sx-sabreauto.dtb \ imx6sx-sdb-reva.dtb \ + imx6sx-sdb-reva-ldo.dtb \ imx6sx-sdb-sai.dtb \ imx6sx-sdb.dtb \ + imx6sx-sdb-ldo.dtb \ + imx6sx-sdb-emmc.dtb \ + imx6sx-sdb-lcdif1.dtb \ + imx6sx-sdb-m4.dtb \ + imx6sx-sdb-mqs.dtb \ + imx6sx-sdb-btwifi.dtb \ + imx6sx-sdb-pcie-ep.dtb \ imx6sx-softing-vining-2000.dtb \ imx6sx-udoo-neo-basic.dtb \ imx6sx-udoo-neo-extended.dtb \ imx6sx-udoo-neo-full.dtb dtb-$(CONFIG_SOC_IMX6UL) += \ imx6ul-14x14-evk.dtb \ + imx6ul-14x14-evk-csi.dtb \ + imx6ul-14x14-evk-emmc.dtb \ + imx6ul-14x14-evk-btwifi.dtb \ + imx6ul-14x14-evk-btwifi-oob.dtb \ + imx6ul-14x14-evk-ecspi-slave.dtb \ + imx6ul-14x14-evk-ecspi.dtb \ + imx6ul-14x14-evk-gpmi-weim.dtb \ + imx6ul-9x9-evk.dtb \ + imx6ul-9x9-evk-ldo.dtb \ + imx6ul-9x9-evk-btwifi.dtb \ + imx6ul-9x9-evk-btwifi-oob.dtb \ imx6ul-ccimx6ulsbcexpress.dtb \ imx6ul-ccimx6ulsbcpro.dtb \ imx6ul-geam.dtb \ @@ -581,12 +636,23 @@ dtb-$(CONFIG_SOC_IMX6UL) += \ imx6ul-tx6ul-0011.dtb \ imx6ul-tx6ul-mainboard.dtb \ imx6ull-14x14-evk.dtb \ + imx6ull-14x14-evk-emmc.dtb \ + imx6ull-14x14-evk-btwifi.dtb \ + imx6ull-14x14-evk-btwifi-oob.dtb \ + imx6ull-14x14-evk-gpmi-weim.dtb \ + imx6ull-9x9-evk.dtb \ + imx6ull-9x9-evk-ldo.dtb \ + imx6ull-9x9-evk-btwifi.dtb \ + imx6ull-9x9-evk-btwifi-oob.dtb \ imx6ull-colibri-eval-v3.dtb \ imx6ull-colibri-wifi-eval-v3.dtb \ imx6ull-phytec-segin-ff-rdk-nand.dtb \ imx6ull-phytec-segin-ff-rdk-emmc.dtb \ imx6ull-phytec-segin-lc-rdk-nand.dtb \ - imx6ulz-14x14-evk.dtb + imx6ulz-14x14-evk.dtb \ + imx6ulz-14x14-evk-btwifi.dtb \ + imx6ulz-14x14-evk-gpmi-weim.dtb \ + imx6ulz-14x14-evk-emmc.dtb dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-cl-som-imx7.dtb \ imx7d-colibri-emmc-eval-v3.dtb \ @@ -598,15 +664,35 @@ dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-pico-pi.dtb \ imx7d-sbc-imx7.dtb \ imx7d-sdb.dtb \ + imx7d-sdb-epdc.dtb \ + imx7d-sdb-mipi-dsi.dtb \ + imx7d-sdb-gpmi-weim.dtb \ + imx7d-sdb-m4.dtb \ + imx7d-sdb-qspi.dtb \ imx7d-sdb-reva.dtb \ imx7d-sdb-sht11.dtb \ + imx7d-sdb-usd-wifi.dtb \ + imx7d-sdb-pcie-ep.dtb \ + imx7d-12x12-lpddr3-val.dtb \ + imx7d-12x12-lpddr3-val-sai.dtb \ imx7d-zii-rmu2.dtb \ imx7d-zii-rpu2.dtb \ imx7s-colibri-eval-v3.dtb \ imx7s-mba7.dtb \ imx7s-warp.dtb dtb-$(CONFIG_SOC_IMX7ULP) += \ - imx7ulp-evk.dtb + imx7ulp-evk.dtb \ + imx7ulp-evk-ft5416.dtb \ + imx7ulp-evk-mipi.dtb \ + imx7ulp-evkb.dtb \ + imx7ulp-evkb-emmc.dtb \ + imx7ulp-evkb-sd1.dtb \ + imx7ulp-evkb-spi-slave.dtb \ + imx7ulp-evkb-sensors-to-i2c5.dtb \ + imx7ulp-evkb-lpuart.dtb \ + imx7ulp-evkb-mipi.dtb \ + imx7ulp-evkb-rm68200-wxga.dtb \ + imx7ulp-evkb-rm68191-qhd.dtb dtb-$(CONFIG_SOC_LS1021A) += \ ls1021a-moxa-uc-8410a.dtb \ ls1021a-qds.dtb \ diff --git a/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts b/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts new file mode 100644 index 000000000000..d468a5535657 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. + + +#include "imx6dl-sabreauto.dts" + +&ecspi1 { + pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&can2 { + /* max7310_c on i2c3 is gone */ + status = "disabled"; +}; + +&i2c3 { + /* pin conflict with ecspi1 */ + status = "disabled"; +}; + +&uart3 { + /* the uart3 depends on the i2c3, so disable it too. */ + status = "disabled"; +}; + +&usbh1 { + /* max7310_b on i2c3 is gone */ + status = "disabled"; +}; + +&usbotg { + dr_mode = "peripheral"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabreauto-enetirq.dts b/arch/arm/boot/dts/imx6dl-sabreauto-enetirq.dts new file mode 100644 index 000000000000..75c798f7616a --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabreauto-enetirq.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2013 Freescale Semiconductor, Inc. +// Copyright 2019 NXP + +#include "imx6dl-sabreauto.dts" + +&fec { + pinctrl-0 = <&pinctrl_enet &pinctrl_enet_irq>; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&gpc 0 119 IRQ_TYPE_LEVEL_HIGH>; + fsl,err006687-workaround-present; +}; + +&mlb { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts b/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts new file mode 100644 index 000000000000..f101f7c7b7b0 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6dl-sabreauto.dts" + +&can1{ + status = "okay"; +}; + +&fec { + /* pin conflict with flexcan1 */ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts b/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts new file mode 100644 index 000000000000..8990519be861 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. + + +#include "imx6dl-sabreauto.dts" + +&ecspi1 { + /* pin conflict with weim */ + status = "disabled"; +}; + +&can2 { + /* max7310_c on i2c3 is gone */ + status = "disabled"; +}; + +&gpmi { + status = "okay"; +}; + +&i2c3 { + /* pin conflict with weim */ + status = "disabled"; +}; + +&uart3 { + /* pin conflict with gpmi and weim */ + status = "disabled"; +}; + +&usbh1 { + /* max7310_b on i2c3 is gone */ + status = "disabled"; +}; + +&usbotg { + dr_mode = "peripheral"; + status = "okay"; +}; + +&weim { + pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabreauto-pcie.dts b/arch/arm/boot/dts/imx6dl-sabreauto-pcie.dts new file mode 100644 index 000000000000..88fc15b1a9de --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabreauto-pcie.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6dl-sabreauto.dts" + +&pcie { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabreauto.dts b/arch/arm/boot/dts/imx6dl-sabreauto.dts index ff3283c83a39..be38a92c6a90 100644 --- a/arch/arm/boot/dts/imx6dl-sabreauto.dts +++ b/arch/arm/boot/dts/imx6dl-sabreauto.dts @@ -26,3 +26,21 @@ 396000 1175000 >; }; + +&ldb { + lvds-channel@0 { + crtc = "ipu1-di0"; + }; + + lvds-channel@1 { + crtc = "ipu1-di1"; + }; +}; + +&mxcfb1 { + status = "okay"; +}; + +&mxcfb2 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabresd-btwifi.dts b/arch/arm/boot/dts/imx6dl-sabresd-btwifi.dts new file mode 100644 index 000000000000..ac57fffe74c7 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabresd-btwifi.dts @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6dl-sabresd.dts" +#include "imx6qdl-sabresd-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts b/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts new file mode 100644 index 000000000000..5aee10ff88b9 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. +// Copyright 2019 NXP + +#include "imx6dl-sabresd.dts" + +&fec { + pinctrl-0 = <&pinctrl_enet &pinctrl_enet_irq>; + interrupts-extended = <&gpio1 6 0x4>, <&gpc 0 119 0x4>; + fsl,err006687-workaround-present; +}; + +&i2c3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts b/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts new file mode 100644 index 000000000000..2c7f04456cbb --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6dl-sabresd.dts" + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +&hdmi_video { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi_hdcp>; + fsl,hdcp; +}; + +&i2c2 { + status = "disable"; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts b/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts new file mode 100644 index 000000000000..e5c623d85e4e --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6dl-sabresd.dts" + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; + +&wdog1 { + status = "okay"; +}; + +&wdog2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabresd-pcie-ep.dts b/arch/arm/boot/dts/imx6dl-sabresd-pcie-ep.dts new file mode 100644 index 000000000000..002989a951e3 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabresd-pcie-ep.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6dl-sabresd.dts" + +&pcie{ + status = "disabled"; +}; + +&pcie_ep{ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabresd-pcie.dts b/arch/arm/boot/dts/imx6dl-sabresd-pcie.dts new file mode 100644 index 000000000000..c57558c815d9 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabresd-pcie.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6dl-sabresd.dts" + +&pcie { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl-sabresd.dts b/arch/arm/boot/dts/imx6dl-sabresd.dts index cd6bbf22a16f..7b253d13b02d 100644 --- a/arch/arm/boot/dts/imx6dl-sabresd.dts +++ b/arch/arm/boot/dts/imx6dl-sabresd.dts @@ -12,7 +12,163 @@ compatible = "fsl,imx6dl-sabresd", "fsl,imx6dl"; }; +&battery { + offset-charger = <1485>; + offset-discharger = <1464>; + offset-usb-charger = <1285>; +}; + +&iomuxc { + epdc { + pinctrl_epdc_elan_touch: epdc_elan_touch_grp { + fsl,pins = < + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x80000000 + MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x80000000 + MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 + >; + }; + + pinctrl_epdc_0: epdcgrp-0 { + fsl,pins = < + MX6QDL_PAD_EIM_A16__EPDC_DATA00 0x80000000 + MX6QDL_PAD_EIM_DA10__EPDC_DATA01 0x80000000 + MX6QDL_PAD_EIM_DA12__EPDC_DATA02 0x80000000 + MX6QDL_PAD_EIM_DA11__EPDC_DATA03 0x80000000 + MX6QDL_PAD_EIM_LBA__EPDC_DATA04 0x80000000 + MX6QDL_PAD_EIM_EB2__EPDC_DATA05 0x80000000 + MX6QDL_PAD_EIM_CS0__EPDC_DATA06 0x80000000 + MX6QDL_PAD_EIM_RW__EPDC_DATA07 0x80000000 + MX6QDL_PAD_EIM_A21__EPDC_GDCLK 0x80000000 + MX6QDL_PAD_EIM_A22__EPDC_GDSP 0x80000000 + MX6QDL_PAD_EIM_A23__EPDC_GDOE 0x80000000 + MX6QDL_PAD_EIM_A24__EPDC_GDRL 0x80000000 + MX6QDL_PAD_EIM_D31__EPDC_SDCLK_P 0x80000000 + MX6QDL_PAD_EIM_D27__EPDC_SDOE 0x80000000 + MX6QDL_PAD_EIM_DA1__EPDC_SDLE 0x80000000 + MX6QDL_PAD_EIM_EB1__EPDC_SDSHR 0x80000000 + MX6QDL_PAD_EIM_DA2__EPDC_BDR0 0x80000000 + MX6QDL_PAD_EIM_DA4__EPDC_SDCE0 0x80000000 + MX6QDL_PAD_EIM_DA5__EPDC_SDCE1 0x80000000 + MX6QDL_PAD_EIM_DA6__EPDC_SDCE2 0x80000000 + >; + }; + }; +}; + +&epdc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_epdc_0>; + V3P3-supply = <&V3P3_reg>; + VCOM-supply = <&VCOM_reg>; + DISPLAY-supply = <&DISPLAY_reg>; + status = "okay"; +}; + +&i2c3 { + elan@10 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_epdc_elan_touch>; + compatible = "elan,elan-touch"; + reg = <0x10>; + interrupt-parent = <&gpio3>; + interrupts = <28 IRQ_TYPE_EDGE_FALLING>; + gpio_elan_cs = <&gpio2 18 0>; + gpio_elan_rst = <&gpio3 8 0>; + gpio_intr = <&gpio3 28 0>; + status = "okay"; + }; + + max17135@48 { + compatible = "maxim,max17135"; + reg = <0x48>; + vneg_pwrup = <1>; + gvee_pwrup = <1>; + vpos_pwrup = <2>; + gvdd_pwrup = <1>; + gvdd_pwrdn = <1>; + vpos_pwrdn = <2>; + gvee_pwrdn = <1>; + vneg_pwrdn = <1>; + SENSOR-supply = <®_sensors>; + gpio_pmic_pwrgood = <&gpio2 21 0>; + gpio_pmic_vcom_ctrl = <&gpio3 17 0>; + gpio_pmic_wakeup = <&gpio3 20 0>; + gpio_pmic_v3p3 = <&gpio2 20 0>; + gpio_pmic_intr = <&gpio2 25 0>; + + regulators { + DISPLAY_reg: DISPLAY { + regulator-name = "DISPLAY"; + }; + + GVDD_reg: GVDD { + /* 20v */ + regulator-name = "GVDD"; + }; + + GVEE_reg: GVEE { + /* -22v */ + regulator-name = "GVEE"; + }; + + HVINN_reg: HVINN { + /* -22v */ + regulator-name = "HVINN"; + }; + + HVINP_reg: HVINP { + /* 20v */ + regulator-name = "HVINP"; + }; + + VCOM_reg: VCOM { + regulator-name = "VCOM"; + /* Real max: -500000 */ + regulator-max-microvolt = <4325000>; + /* Real min: -4325000 */ + regulator-min-microvolt = <500000>; + }; + + VNEG_reg: VNEG { + /* -15v */ + regulator-name = "VNEG"; + }; + + VPOS_reg: VPOS { + /* 15v */ + regulator-name = "VPOS"; + }; + + V3P3_reg: V3P3 { + regulator-name = "V3P3"; + }; + }; + }; +}; + &ipu1_csi1_from_ipu1_csi1_mux { clock-lanes = <0>; data-lanes = <1 2>; }; + +&ldb { + lvds-channel@0 { + crtc = "ipu1-di0"; + }; + + lvds-channel@1 { + crtc = "ipu1-di1"; + }; +}; + +&mxcfb1 { + status = "okay"; +}; + +&mxcfb2 { + status = "okay"; +}; + +&pxp { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi index 2ed10310a7b7..845adeed6785 100644..100755 --- a/arch/arm/boot/dts/imx6dl.dtsi +++ b/arch/arm/boot/dts/imx6dl.dtsi @@ -38,9 +38,13 @@ <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, <&clks IMX6QDL_CLK_STEP>, <&clks IMX6QDL_CLK_PLL1_SW>, - <&clks IMX6QDL_CLK_PLL1_SYS>; + <&clks IMX6QDL_CLK_PLL1_SYS>, + <&clks IMX6QDL_CLK_PLL1>, + <&clks IMX6QDL_PLL1_BYPASS>, + <&clks IMX6QDL_PLL1_BYPASS_SRC>; clock-names = "arm", "pll2_pfd2_396m", "step", - "pll1_sw", "pll1_sys"; + "pll1_sw", "pll1_sys", "pll1", + "pll1_bypass", "pll1_bypass_src"; arm-supply = <®_arm>; pu-supply = <®_pu>; soc-supply = <®_soc>; @@ -77,30 +81,105 @@ }; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + linux,cma-default; + }; + }; + soc { - ocram: sram@900000 { + busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6QDL_CLK_PLL2_BUS>, <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, + <&clks IMX6QDL_CLK_PLL2_198M>, <&clks IMX6QDL_CLK_ARM>, + <&clks IMX6QDL_CLK_PLL3_USB_OTG>, <&clks IMX6QDL_CLK_PERIPH>, + <&clks IMX6QDL_CLK_PERIPH_PRE>, <&clks IMX6QDL_CLK_PERIPH_CLK2>, + <&clks IMX6QDL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6QDL_CLK_OSC>, + <&clks IMX6QDL_CLK_AXI_ALT_SEL>, <&clks IMX6QDL_CLK_AXI_SEL> , + <&clks IMX6QDL_CLK_PLL3_PFD1_540M>; + clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", + "pll3_usb_otg", "periph", "periph_pre", "periph_clk2", + "periph_clk2_sel", "osc", "axi_alt_sel", "axi_sel", + "pll3_pfd1_540m"; + interrupts = <0 107 0x4>, <0 112 0x4>; + interrupt-names = "irq_busfreq_0", "irq_busfreq_1"; + fsl,max_ddr_freq = <400000000>; + }; + + ocram: sram@905000 { compatible = "mmio-sram"; - reg = <0x00900000 0x20000>; + reg = <0x905000 0x1B000>; clocks = <&clks IMX6QDL_CLK_OCRAM>; }; + ocram_optee: sram@918000 { + compatible = "fsl,optee-lpm-sram"; + reg = <0x918000 0x8000>; + overw_reg = <&ocram 0x905000 0x13000>; + }; + + gpu: gpu@00130000 { + compatible = "fsl,imx6dl-gpu", "fsl,imx6q-gpu"; + reg = <0x00130000 0x4000>, <0x00134000 0x4000>, + <0x10000000 0x0>, <0x0 0x8000000>; + reg-names = "iobase_3d", "iobase_2d", + "phys_baseaddr", "contiguous_mem"; + interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>, + <0 10 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "irq_3d", "irq_2d"; + clocks = <&clks IMX6QDL_CLK_OPENVG_AXI>, <&clks IMX6QDL_CLK_GPU3D_AXI>, + <&clks IMX6QDL_CLK_GPU2D_CORE>, <&clks IMX6QDL_CLK_GPU3D_CORE>, + <&clks IMX6QDL_CLK_DUMMY>; + clock-names = "gpu2d_axi_clk", "gpu3d_axi_clk", + "gpu2d_clk", "gpu3d_clk", + "gpu3d_shader_clk"; + resets = <&src 0>, <&src 3>; + reset-names = "gpu3d", "gpu2d"; + power-domains = <&pd_pu>; + }; + aips1: aips-bus@2000000 { iomuxc: iomuxc@20e0000 { compatible = "fsl,imx6dl-iomuxc"; }; pxp: pxp@20f0000 { - reg = <0x020f0000 0x4000>; + compatible = "fsl,imx6dl-pxp-dma"; + reg = <0x20f0000 0x4000>; interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_IPU2>, <&clks IMX6QDL_CLK_DUMMY>; + clock-names = "pxp-axi", "disp-axi"; + status = "disabled"; }; epdc: epdc@20f4000 { - reg = <0x020f4000 0x4000>; + compatible = "fsl,imx6dl-epdc"; + reg = <0x20f4000 0x4000>; interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_IPU2>, <&clks IMX6QDL_CLK_IPU2_DI1>; + clock-names = "epdc_axi", "epdc_pix"; }; }; aips2: aips-bus@2100000 { + mipi_dsi: mipi@21e0000 { + compatible = "fsl,imx6dl-mipi-dsi"; + reg = <0x21e0000 0x4000>; + interrupts = <0 102 0x4>; + gpr = <&gpr>; + clocks = <&clks IMX6QDL_CLK_HSI_TX>, <&clks IMX6QDL_CLK_VIDEO_27M>; + clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; + status = "disabled"; + }; + i2c4: i2c@21f8000 { #address-cells = <1>; #size-cells = <0>; @@ -124,6 +203,12 @@ }; }; +&dcic2 { + clocks = <&clks IMX6QDL_CLK_DCIC1 >, + <&clks IMX6QDL_CLK_DCIC2>; /* DCIC2 depend on DCIC1 clock in imx6dl*/ + clock-names = "dcic", "disp-axi"; +}; + &gpio1 { gpio-ranges = <&iomuxc 0 131 2>, <&iomuxc 2 137 8>, <&iomuxc 10 189 2>, <&iomuxc 12 194 1>, <&iomuxc 13 193 1>, <&iomuxc 14 192 1>, @@ -302,12 +387,19 @@ }; &ldb { - clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>, + compatible = "fsl,imx6dl-ldb", "fsl,imx53-ldb"; + clocks = <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>, <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, - <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>; - clock-names = "di0_pll", "di1_pll", + <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_3_5>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_3_5>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_7>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_7>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>; + clock-names = "ldb_di0", "ldb_di1", "di0_sel", "di1_sel", - "di0", "di1"; + "di2_sel", + "ldb_di0_div_3_5", "ldb_di1_div_3_5", + "ldb_di0_div_7", "ldb_di1_div_7", + "ldb_di0_div_sel", "ldb_di1_div_sel"; }; &mipi_csi { @@ -389,3 +481,7 @@ &vpu { compatible = "fsl,imx6dl-vpu", "cnm,coda960"; }; + +&vpu_fsl { + iramsize = <0>; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts b/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts new file mode 100644 index 000000000000..44a31e56d8f2 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. + +#include "imx6q-sabreauto.dts" + +&ecspi1 { + pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&can2 { + /* max7310_c on i2c3 is gone */ + status = "disabled"; +}; + +&i2c3 { + /* pin conflict with ecspi1 */ + status = "disabled"; +}; + +&uart3 { + /* the uart3 depends on the i2c3, so disable it too. */ + status = "disabled"; +}; + +&usbh1 { + /* max7310_b on i2c3 is gone */ + status = "disabled"; +}; + +&usbotg { + /* max7310_c on i2c3 is gone */ + status = "okay"; + dr_mode = "peripheral"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto-enetirq.dts b/arch/arm/boot/dts/imx6q-sabreauto-enetirq.dts new file mode 100644 index 000000000000..04351f1feed4 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabreauto-enetirq.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2019 NXP + +#include "imx6q-sabreauto.dts" + +&fec { + pinctrl-0 = <&pinctrl_enet &pinctrl_enet_irq>; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&gpc 0 119 IRQ_TYPE_LEVEL_HIGH>; + fsl,err006687-workaround-present; +}; + +&mlb { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts b/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts new file mode 100644 index 000000000000..71dd58944801 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6q-sabreauto.dts" + +&can1{ + status = "okay"; +}; + +&fec { + /* pin conflict with flexcan1 */ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts b/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts new file mode 100644 index 000000000000..bbeb10557cbc --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. + + +#include "imx6q-sabreauto.dts" + +&ecspi1 { + /* pin conflict with weim */ + status = "disabled"; +}; + +&can2 { + /* max7310_c on i2c3 is gone */ + status = "disabled"; +}; + +&gpmi { + status = "okay"; +}; + +&i2c3 { + /* pin conflict with weim */ + status = "disabled"; +}; + +&uart3 { + /* pin conflict with gpmi and weim */ + status = "disabled"; +}; + +&usbh1 { + /* max7310_b on i2c3 is gone */ + status = "disabled"; +}; + +&usbotg { + /* max7310_c on i2c3 is gone */ + status = "okay"; + dr_mode = "peripheral"; +}; + +&weim { + pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto-pcie.dts b/arch/arm/boot/dts/imx6q-sabreauto-pcie.dts new file mode 100644 index 000000000000..769a2cf4a6ac --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabreauto-pcie.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6q-sabreauto.dts" + +&pcie { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts b/arch/arm/boot/dts/imx6q-sabreauto.dts index 6e981a3e0a83..e6493858c30e 100644 --- a/arch/arm/boot/dts/imx6q-sabreauto.dts +++ b/arch/arm/boot/dts/imx6q-sabreauto.dts @@ -13,6 +13,31 @@ compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; }; +&ldb { + lvds-channel@0 { + crtc = "ipu2-di0"; + }; + lvds-channel@1 { + crtc = "ipu2-di1"; + }; +}; + +&mxcfb1 { + status = "okay"; +}; + +&mxcfb2 { + status = "okay"; +}; + +&mxcfb3 { + status = "okay"; +}; + +&mxcfb4 { + status = "okay"; +}; + &sata { status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q-sabresd-btwifi.dts b/arch/arm/boot/dts/imx6q-sabresd-btwifi.dts new file mode 100644 index 000000000000..5f55b7df2942 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-btwifi.dts @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6q-sabresd.dts" +#include "imx6qdl-sabresd-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts b/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts new file mode 100644 index 000000000000..4c9e62779c47 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. +// Copyright 2019 NXP + +#include "imx6q-sabresd.dts" + +&fec { + pinctrl-0 = <&pinctrl_enet &pinctrl_enet_irq>; + interrupts-extended = <&gpio1 6 0x4>, <&gpc 0 119 0x4>; + fsl,err006687-workaround-present; +}; + +&i2c3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts b/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts new file mode 100644 index 000000000000..3116e3efb835 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 "imx6q-sabresd.dts" + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +&hdmi_video { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi_hdcp>; + fsl,hdcp; +}; + +&i2c2 { + status = "disable"; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd-ldo.dts b/arch/arm/boot/dts/imx6q-sabresd-ldo.dts new file mode 100644 index 000000000000..8363302dca35 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-ldo.dts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6q-sabresd.dts" + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; + +&wdog1 { + status = "okay"; +}; + +&wdog2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd-pcie-ep.dts b/arch/arm/boot/dts/imx6q-sabresd-pcie-ep.dts new file mode 100644 index 000000000000..534a77c525c3 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-pcie-ep.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6q-sabresd.dts" + +&pcie{ + status = "disabled"; +}; + +&pcie_ep{ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd-pcie.dts b/arch/arm/boot/dts/imx6q-sabresd-pcie.dts new file mode 100644 index 000000000000..2ff88f6a1d52 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-pcie.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6q-sabresd.dts" + +&pcie { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd-uart.dts b/arch/arm/boot/dts/imx6q-sabresd-uart.dts new file mode 100644 index 000000000000..800479da5941 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd-uart.dts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6q-sabresd.dts" + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5_1>; + fsl,uart-has-rtscts; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ +}; + +&ecspi1 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts index eec944673c0b..ca8c7d1a29cb 100644 --- a/arch/arm/boot/dts/imx6q-sabresd.dts +++ b/arch/arm/boot/dts/imx6q-sabresd.dts @@ -13,6 +13,38 @@ compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; }; +&battery { + offset-charger = <1900>; + offset-discharger = <1694>; + offset-usb-charger = <1685>; +}; + +&ldb { + lvds-channel@0 { + crtc = "ipu2-di0"; + }; + + lvds-channel@1 { + crtc = "ipu2-di1"; + }; +}; + +&mxcfb1 { + status = "okay"; +}; + +&mxcfb2 { + status = "okay"; +}; + +&mxcfb3 { + status = "okay"; +}; + +&mxcfb4 { + status = "okay"; +}; + &sata { status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index d038f4117024..2d3e137fc1fc 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -43,9 +43,13 @@ <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, <&clks IMX6QDL_CLK_STEP>, <&clks IMX6QDL_CLK_PLL1_SW>, - <&clks IMX6QDL_CLK_PLL1_SYS>; + <&clks IMX6QDL_CLK_PLL1_SYS>, + <&clks IMX6QDL_CLK_PLL1>, + <&clks IMX6QDL_PLL1_BYPASS>, + <&clks IMX6QDL_PLL1_BYPASS_SRC>; clock-names = "arm", "pll2_pfd2_396m", "step", - "pll1_sw", "pll1_sys"; + "pll1_sw", "pll1_sys", "pll1", + "pll1_bypass", "pll1_bypass_src"; arm-supply = <®_arm>; pu-supply = <®_pu>; soc-supply = <®_soc>; @@ -154,13 +158,44 @@ }; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + linux,cma-default; + }; + }; + soc { - ocram: sram@900000 { + busfreq: busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>, + <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>; + clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", + "periph", "periph_pre", "periph_clk2", "periph_clk2_sel", "osc"; + interrupts = <0 107 0x04>, <0 112 0x4>, <0 113 0x4>, <0 114 0x4>; + interrupt-names = "irq_busfreq_0", "irq_busfreq_1", "irq_busfreq_2", "irq_busfreq_3"; + fsl,max_ddr_freq = <528000000>; + }; + + ocram: sram@905000 { compatible = "mmio-sram"; - reg = <0x00900000 0x40000>; + reg = <0x905000 0x3B000>; clocks = <&clks IMX6QDL_CLK_OCRAM>; }; + ocram_optee: sram@938000 { + compatible = "fsl,optee-lpm-sram"; + reg = <0x938000 0x8000>; + overw_reg = <&ocram 0x905000 0x33000>; + }; + aips-bus@2000000 { /* AIPS1 */ spba-bus@2000000 { ecspi5: spi@2018000 { @@ -172,7 +207,7 @@ clocks = <&clks IMX6Q_CLK_ECSPI5>, <&clks IMX6Q_CLK_ECSPI5>; clock-names = "ipg", "per"; - dmas = <&sdma 11 8 1>, <&sdma 12 8 2>; + dmas = <&sdma 11 7 1>, <&sdma 12 7 2>; dma-names = "rx", "tx"; status = "disabled"; }; @@ -183,6 +218,18 @@ }; }; + aips-bus@2100000 { /* AIPS2 */ + mipi_dsi: mipi@21e0000 { + compatible = "fsl,imx6q-mipi-dsi"; + reg = <0x21e0000 0x4000>; + interrupts = <0 102 0x4>; + gpr = <&gpr>; + clocks = <&clks IMX6QDL_CLK_HSI_TX>, <&clks IMX6QDL_CLK_VIDEO_27M>; + clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; + status = "disabled"; + }; + }; + sata: sata@2200000 { compatible = "fsl,imx6q-ahci"; reg = <0x02200000 0x4000>; @@ -203,6 +250,30 @@ clock-names = "bus", "core"; power-domains = <&pd_pu>; #cooling-cells = <2>; + status = "disabled"; + }; + + gpu: gpu@00130000 { + compatible = "fsl,imx6q-gpu"; + reg = <0x00130000 0x4000>, <0x00134000 0x4000>, + <0x02204000 0x4000>, <0x10000000 0x0>, + <0x0 0x8000000>; + reg-names = "iobase_3d", "iobase_2d", + "iobase_vg", "phys_baseaddr", + "contiguous_mem"; + interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>, + <0 10 IRQ_TYPE_LEVEL_HIGH>, + <0 11 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "irq_3d", "irq_2d", "irq_vg"; + clocks = <&clks IMX6QDL_CLK_GPU2D_AXI>, <&clks IMX6QDL_CLK_OPENVG_AXI>, + <&clks IMX6QDL_CLK_GPU3D_AXI>, <&clks IMX6QDL_CLK_GPU2D_CORE>, + <&clks IMX6QDL_CLK_GPU3D_CORE>, <&clks IMX6QDL_CLK_GPU3D_SHADER>; + clock-names = "gpu2d_axi_clk", "openvg_axi_clk", + "gpu3d_axi_clk", "gpu2d_clk", + "gpu3d_clk", "gpu3d_shader_clk"; + resets = <&src 0>, <&src 3>, <&src 3>; + reset-names = "gpu3d", "gpu2d", "gpuvg"; + power-domains = <&pd_pu>; }; ipu2: ipu@2800000 { @@ -214,9 +285,17 @@ <0 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_IPU2>, <&clks IMX6QDL_CLK_IPU2_DI0>, - <&clks IMX6QDL_CLK_IPU2_DI1>; - clock-names = "bus", "di0", "di1"; + <&clks IMX6QDL_CLK_IPU2_DI1>, + <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, + <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, + <&clks IMX6QDL_CLK_LDB_DI0>, + <&clks IMX6QDL_CLK_LDB_DI1>; + clock-names = "bus", + "di0", "di1", + "di0_sel", "di1_sel", + "ldb_di0", "ldb_di1"; resets = <&src 4>; + bypass_reset = <0>; ipu2_csi0: port@0 { reg = <0>; @@ -429,13 +508,19 @@ }; &ldb { - clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>, + compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb"; + clocks = <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>, <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, - <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>; - clock-names = "di0_pll", "di1_pll", - "di0_sel", "di1_sel", "di2_sel", "di3_sel", - "di0", "di1"; + <&clks IMX6QDL_CLK_LDB_DI0_DIV_3_5>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_3_5>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_7>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_7>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>; + clock-names = "ldb_di0", "ldb_di1", + "di0_sel", "di1_sel", + "di2_sel", "di3_sel", + "ldb_di0_div_3_5", "ldb_di1_div_3_5", + "ldb_di0_div_7", "ldb_di1_div_7", + "ldb_di0_div_sel", "ldb_di1_div_sel"; lvds-channel@0 { port@2 { diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index cf628465cd0a..e213ae47e441 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -11,7 +11,14 @@ stdout-path = &uart4; }; - memory@10000000 { + aliases { + mxcfb0 = &mxcfb1; + mxcfb1 = &mxcfb2; + mxcfb2 = &mxcfb3; + mxcfb3 = &mxcfb4; + }; + + memory: memory@10000000 { device_type = "memory"; reg = <0x10000000 0x80000000>; }; @@ -84,6 +91,14 @@ regulator-always-on; }; + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + reg_usb_h1_vbus: regulator-usb-h1-vbus { compatible = "regulator-fixed"; regulator-name = "usb_h1_vbus"; @@ -121,26 +136,113 @@ vin-supply = <®_can_en>; }; + reg_si4763_vio1: regulator@3 { + compatible = "regulator-fixed"; + regulator-name = "vio1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_si4763_vio2: regulator@4 { + compatible = "regulator-fixed"; + regulator-name = "vio2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_si4763_vd: regulator@5 { + compatible = "regulator-fixed"; + regulator-name = "vd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_si4763_va: regulator@6 { + compatible = "regulator-fixed"; + regulator-name = "va"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_hdmi: regulator-hdmi { + compatible = "regulator-fixed"; + regulator-name = "hdmi-5v-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + hdmi-5v-supply = <&swbst_reg>; + }; + + mxcfb1: fb@0 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "ldb"; + interface_pix_fmt = "RGB666"; + default_bpp = <16>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + mxcfb2: fb@1 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "hdmi"; + interface_pix_fmt = "RGB24"; + mode_str ="1920x1080M@60"; + default_bpp = <24>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + mxcfb3: fb@2 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "lcd"; + interface_pix_fmt = "RGB565"; + mode_str ="CLAA-WVGA"; + default_bpp = <16>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + mxcfb4: fb@3 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "ldb"; + interface_pix_fmt = "RGB666"; + default_bpp = <16>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + sound-cs42888 { compatible = "fsl,imx6-sabreauto-cs42888", - "fsl,imx-audio-cs42888"; + "fsl,imx-audio-cs42888"; model = "imx-cs42888"; - audio-cpu = <&esai>; - audio-asrc = <&asrc>; + esai-controller = <&esai>; + asrc-controller = <&asrc>; audio-codec = <&codec>; - audio-routing = - "Line Out Jack", "AOUT1L", - "Line Out Jack", "AOUT1R", - "Line Out Jack", "AOUT2L", - "Line Out Jack", "AOUT2R", - "Line Out Jack", "AOUT3L", - "Line Out Jack", "AOUT3R", - "Line Out Jack", "AOUT4L", - "Line Out Jack", "AOUT4R", - "AIN1L", "Line In Jack", - "AIN1R", "Line In Jack", - "AIN2L", "Line In Jack", - "AIN2R", "Line In Jack"; + }; + + sound-hdmi { + compatible = "fsl,imx6q-audio-hdmi", + "fsl,imx-audio-hdmi"; + model = "imx-audio-hdmi"; + hdmi-controller = <&hdmi_audio>; + }; + + sound-fm { + compatible = "fsl,imx-audio-si476x", + "fsl,imx-tuner-si476x"; + model = "imx-radio-si4763"; + ssi-controller = <&ssi2>; + fm-controller = <&si476x_codec>; + mux-int-port = <2>; + mux-ext-port = <5>; }; sound-spdif { @@ -174,19 +276,22 @@ #size-cells = <0>; reg = <1>; - adv7180: camera@21 { - compatible = "adi,adv7180"; + adv7180: adv7180@21 { + compatible = "adv,adv7180"; reg = <0x21>; - powerdown-gpios = <&max7310_b 2 GPIO_ACTIVE_LOW>; - interrupt-parent = <&gpio1>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - - port { - adv7180_to_ipu1_csi0_mux: endpoint { - remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; - bus-width = <8>; - }; - }; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu1_1>; + clocks = <&clks IMX6QDL_CLK_CKO>; + clock-names = "csi_mclk"; + DOVDD-supply = <®_3p3v>; /* 3.3v, enabled via 2.8 VGEN6 */ + AVDD-supply = <®_3p3v>; /* 1.8v */ + DVDD-supply = <®_3p3v>; /* 1.8v */ + PVDD-supply = <®_3p3v>; /* 1.8v */ + pwn-gpios = <&max7310_b 2 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + cvbs = <1>; }; max7310_a: gpio@30 { @@ -214,8 +319,9 @@ }; light-sensor@44 { - compatible = "isil,isl29023"; + compatible = "fsl,isl29023"; reg = <0x44>; + rext = <499>; interrupt-parent = <&gpio5>; interrupts = <17 IRQ_TYPE_EDGE_FALLING>; }; @@ -237,6 +343,25 @@ }; }; }; + + v4l2_cap_0 { + compatible = "fsl,imx6q-v4l2-capture"; + ipu_id = <0>; + csi_id = <0>; + mclk_source = <0>; + status = "okay"; + }; + + v4l2_out { + compatible = "fsl,mxc_v4l2_output"; + status = "okay"; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; }; &ipu1_csi0_from_ipu1_csi0_mux { @@ -244,7 +369,10 @@ }; &ipu1_csi0_mux_from_parallel_sensor { + /* Downstream driver doesn't use endpoints */ + /* remote-endpoint = <&adv7180_to_ipu1_csi0_mux>; + */ bus-width = <8>; }; @@ -261,11 +389,23 @@ <&clks IMX6QDL_CLK_PLL4_POST_DIV>; assigned-clock-parents = <&clks IMX6QDL_CLK_LVDS2_IN>, <&clks IMX6QDL_PLL4_BYPASS_SRC>, - <&clks IMX6QDL_CLK_PLL3_USB_OTG>, - <&clks IMX6QDL_CLK_PLL3_USB_OTG>; + <&clks IMX6QDL_CLK_PLL2_PFD0_352M>, + <&clks IMX6QDL_CLK_PLL2_PFD0_352M>; assigned-clock-rates = <0>, <0>, <0>, <0>, <24576000>; }; +&dcic1 { + dcic_id = <0>; + dcic_mux = "dcic-hdmi"; + status = "okay"; +}; + +&dcic2 { + dcic_id = <1>; + dcic_mux = "dcic-lvds0"; + status = "okay"; +}; + &ecspi1 { cs-gpios = <&gpio3 19 0>; pinctrl-names = "default"; @@ -295,15 +435,14 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii-id"; - interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, - <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; - fsl,err006687-workaround-present; + fsl,magic-packet; status = "okay"; }; &can1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_flexcan1>; + pinctrl-assert-gpios = <&max7310_b 3 GPIO_ACTIVE_HIGH>; /* TX */ xceiver-supply = <®_can_stby>; status = "disabled"; /* pin conflict with fec */ }; @@ -318,13 +457,31 @@ &gpmi { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpmi_nand>; + /* enable at -gpmi-weim.dts due to pin conflict */ + status = "disabled"; + nand-on-flash-bbt; +}; + +&hdmi_audio { status = "okay"; }; -&hdmi { +&hdmi_cec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hdmi_cec>; - ddc-i2c-bus = <&i2c2>; + status = "okay"; +}; + +&hdmi_core { + ipu_id = <0>; + disp_id = <1>; + status = "okay"; +}; + +&hdmi_video { + fsl,phy_reg_vlev = <0x294>; + fsl,phy_reg_cksymtx = <0x800d>; + HDMI-supply = <®_hdmi>; status = "okay"; }; @@ -453,6 +610,25 @@ interrupts = <28 IRQ_TYPE_EDGE_FALLING>; wakeup-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; }; + + si4763: si4763@63 { + compatible = "si4761"; + reg = <0x63>; + va-supply = <®_si4763_va>; + vd-supply = <®_si4763_vd>; + vio1-supply = <®_si4763_vio1>; + vio2-supply = <®_si4763_vio2>; + revision-a10; /* set to default A10 compatible command set */ + + si476x_codec: si476x-codec { + compatible = "si476x-codec"; + }; + }; + + hdmi_edid: edid@50 { + compatible = "fsl,imx6-hdmi-i2c"; + reg = <0x50>; + }; }; &i2c3 { @@ -474,6 +650,14 @@ >; }; + pinctrl_audmux: audmux { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0 + MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0 + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + >; + }; + pinctrl_ecspi1: ecspi1grp { fsl,pins = < MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 @@ -511,6 +695,12 @@ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_enet_irq: enetirqgrp { + fsl,pins = < MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; @@ -595,6 +785,30 @@ >; }; + pinctrl_ipu1_1: ipu1grp-1 { /* parallel port 16-bit */ + fsl,pins = < + MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x80000000 + MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x80000000 + MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x80000000 + MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x80000000 + MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x80000000 + MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x80000000 + MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x80000000 + MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x80000000 + MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000 + MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000 + MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000 + MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000 + MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000 + MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000 + MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000 + MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000 + MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000 + MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000 + MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000 + >; + }; + pinctrl_i2c3: i2c3grp { fsl,pins = < MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 @@ -636,6 +850,14 @@ >; }; + pinctrl_mlb: mlb { + fsl,pins = < + MX6QDL_PAD_ENET_TXD1__MLB_CLK 0x80000000 + MX6QDL_PAD_GPIO_6__MLB_SIG 0x80000000 + MX6QDL_PAD_GPIO_2__MLB_DATA 0x80000000 + >; + }; + pinctrl_pwm3: pwm1grp { fsl,pins = < MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 @@ -660,6 +882,24 @@ >; }; + pinctrl_uart3_1: uart3grp-1 { + fsl,pins = < + MX6QDL_PAD_SD4_CLK__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_CMD__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart3dte_1: uart3dtegrp-1 { + fsl,pins = < + MX6QDL_PAD_SD4_CLK__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_CMD__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x1b0b1 + MX6QDL_PAD_EIM_EB3__UART3_CTS_B 0x1b0b1 + >; + }; + pinctrl_uart4: uart4grp { fsl,pins = < MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 @@ -673,6 +913,17 @@ >; }; + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x170f9 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x100f9 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 + >; + }; + pinctrl_usdhc3: usdhc3grp { fsl,pins = < MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 @@ -780,6 +1031,7 @@ lvds-channel@0 { fsl,data-mapping = "spwg"; fsl,data-width = <18>; + primary; status = "okay"; display-timings { @@ -797,15 +1049,38 @@ }; }; }; + + lvds-channel@1 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing1>; + timing1: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; }; -&pwm3 { +&mlb { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pwm3>; + pinctrl-0 = <&pinctrl_mlb>; status = "okay"; }; -&pcie { +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; status = "okay"; }; @@ -815,6 +1090,26 @@ status = "okay"; }; +&ssi2 { + assigned-clocks = <&clks IMX6QDL_CLK_SSI2_SEL>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <0>; + fsl,mode = "i2s-master"; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3_1>; + pinctrl-assert-gpios = <&max7310_b 4 GPIO_ACTIVE_HIGH>, /* CTS */ + <&max7310_c 3 GPIO_ACTIVE_HIGH>; /* RXD and TXD */ + fsl,uart-has-rtscts; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart3dte_1>; */ +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart4>; @@ -833,6 +1128,14 @@ status = "okay"; }; +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + no-1-8-v; + status = "okay"; +}; + &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc3>; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd-btwifi.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd-btwifi.dtsi new file mode 100644 index 000000000000..cf8604181d32 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-sabresd-btwifi.dtsi @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * NOTE: This DTS file is wrote for plugging in Murata 1MW M.2 + * into SD2 slot by using Murata uSD-to-M.2 Adapter. + * + * By default, OOB IRQ is enabled with below HW rework. + * HW rework: + * Install R209,R210,R211,R212,R213,R214,R215 on SDB board. + */ + +/ { + leds { + compatible = "gpio-leds"; + status = "disabled"; + }; + + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + usdhc1_pwrseq: usdhc1_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio4 7 GPIO_ACTIVE_LOW>; + }; +}; + +&ecspi1 { + status = "disabled"; +}; + +&iomuxc { + imx6qdl-sabresd-murata-v2 { + pinctrl_btreg: btreggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 + >; + }; + + /* add MUXing entry for SD2 4-bit interface and configure control pins */ + pinctrl_wifi: wifigrp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x13069 /* WL_REG_ON */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x0b001 /* WL_HOST_WAKE */ + >; + }; + }; +}; + +&pinctrl_gpio_leds { + fsl,pins = < + >; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5_1 + &pinctrl_btreg>; + fsl,uart-has-rtscts; + resets = <&modem_reset>; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ +}; + +&usdhc2 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wifi>; + bus-width = <4>; + no-1-8-v; + non-removable; + keep-power-in-suspend; + mmc-pwrseq = <&usdhc1_pwrseq>; + pm-ignore-notify; + cap-power-off-card; + /delete-property/ enable-sdio-wakeup; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&gpio4>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "host-wake"; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index fe59dde41b64..96a4993e84a1 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -8,11 +8,31 @@ #include <dt-bindings/input/input.h> / { + aliases { + mxcfb0 = &mxcfb1; + mxcfb1 = &mxcfb2; + mxcfb2 = &mxcfb3; + mxcfb3 = &mxcfb4; + }; + chosen { stdout-path = &uart1; }; - memory@10000000 { + battery: max8903@0 { + compatible = "fsl,max8903-charger"; + pinctrl-names = "default"; + dok_input = <&gpio2 24 1>; + uok_input = <&gpio1 27 1>; + chg_input = <&gpio3 23 1>; + flt_input = <&gpio5 2 1>; + fsl,dcm_always_high; + fsl,dc_valid; + fsl,usb_valid; + status = "okay"; + }; + + memory: memory@10000000 { device_type = "memory"; reg = <0x10000000 0x40000000>; }; @@ -66,6 +86,22 @@ enable-active-high; }; + reg_hdmi: regulator-hdmi { + compatible = "regulator-fixed"; + regulator-name = "hdmi-5v-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + hdmi-5v-supply = <&swbst_reg>; + }; + + reg_mipi_dsi_pwr_on: mipi_dsi_pwr_on { + compatible = "regulator-fixed"; + regulator-name = "mipi_dsi_pwr_on"; + gpio = <&gpio6 14 0>; + enable-active-high; + }; + gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -97,17 +133,86 @@ compatible = "fsl,imx6q-sabresd-wm8962", "fsl,imx-audio-wm8962"; model = "wm8962-audio"; - ssi-controller = <&ssi2>; + audio-cpu = <&ssi2>; audio-codec = <&codec>; + asrc-controller = <&asrc>; audio-routing = "Headphone Jack", "HPOUTL", "Headphone Jack", "HPOUTR", "Ext Spk", "SPKOUTL", "Ext Spk", "SPKOUTR", "AMIC", "MICBIAS", - "IN3R", "AMIC"; + "IN3R", "AMIC", + "DMIC", "MICBIAS", + "DMICDAT", "DMIC", + "CPU-Playback", "ASRC-Playback", + "Playback", "CPU-Playback", + "ASRC-Capture", "CPU-Capture", + "CPU-Capture", "Capture"; mux-int-port = <2>; mux-ext-port = <3>; + codec-master; + hp-det-gpios = <&gpio7 8 1>; + mic-det-gpios = <&gpio1 9 1>; + }; + + sound-hdmi { + compatible = "fsl,imx6q-audio-hdmi", + "fsl,imx-audio-hdmi"; + model = "imx-audio-hdmi"; + hdmi-controller = <&hdmi_audio>; + }; + + mxcfb1: fb@0 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "ldb"; + interface_pix_fmt = "RGB666"; + default_bpp = <16>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + mxcfb2: fb@1 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "hdmi"; + interface_pix_fmt = "RGB24"; + mode_str ="1920x1080M@60"; + default_bpp = <24>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + mxcfb3: fb@2 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "lcd"; + interface_pix_fmt = "RGB565"; + mode_str ="CLAA-WVGA"; + default_bpp = <16>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + mxcfb4: fb@3 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "ldb"; + interface_pix_fmt = "RGB666"; + default_bpp = <16>; + int_clk = <0>; + late_init = <0>; + status = "disabled"; + }; + + lcd@0 { + compatible = "fsl,lcd"; + ipu_id = <0>; + disp_id = <0>; + default_ifmt = "RGB565"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu1>; + status = "okay"; }; backlight_lvds: backlight-lvds { @@ -123,21 +228,33 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio_leds>; - red { + charger-led { gpios = <&gpio1 2 0>; - default-state = "on"; + linux,default-trigger = "max8903-charger-charging"; + retain-state-suspended; + default-state = "off"; }; }; - panel { - compatible = "hannstar,hsd100pxn1"; - backlight = <&backlight_lvds>; + v4l2_cap_0 { + compatible = "fsl,imx6q-v4l2-capture"; + ipu_id = <0>; + csi_id = <0>; + mclk_source = <0>; + status = "okay"; + }; - port { - panel_in: endpoint { - remote-endpoint = <&lvds0_out>; - }; - }; + v4l2_cap_1 { + compatible = "fsl,imx6q-v4l2-capture"; + ipu_id = <0>; + csi_id = <1>; + mclk_source = <0>; + status = "okay"; + }; + + v4l2_out { + compatible = "fsl,mxc_v4l2_output"; + status = "okay"; }; }; @@ -149,7 +266,9 @@ }; &ipu1_csi0_mux_from_parallel_sensor { +#if 0 remote-endpoint = <&ov5642_to_ipu1_csi0_mux>; +#endif }; &ipu1_csi0 { @@ -160,6 +279,11 @@ &mipi_csi { status = "okay"; + ipu_id = <0>; + csi_id = <1>; + v_channel = <0>; + lanes = <2>; +#if 0 port@0 { reg = <0>; @@ -169,6 +293,17 @@ data-lanes = <1 2>; }; }; +#endif +}; + +&mipi_dsi { + dev_id = <0>; + disp_id = <1>; + lcd_panel = "TRULY-WVGA"; + disp-power-on-supply = <®_mipi_dsi_pwr_on>; + reset-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>; + reset-delay-us = <50>; + status = "okay"; }; &audmux { @@ -180,8 +315,20 @@ &clks { assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>; - assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>, - <&clks IMX6QDL_CLK_PLL3_USB_OTG>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL2_PFD0_352M>, + <&clks IMX6QDL_CLK_PLL2_PFD0_352M>; +}; + +&dcic1 { + dcic_id = <0>; + dcic_mux = "dcic-hdmi"; + status = "okay"; +}; + +&dcic2 { + dcic_id = <1>; + dcic_mux = "dcic-lvds1"; + status = "okay"; }; &ecspi1 { @@ -204,20 +351,44 @@ pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii-id"; phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; + fsl,magic-packet; status = "okay"; }; -&hdmi { +&gpc { + fsl,ldo-bypass = <1>; +}; + +&hdmi_audio { + status = "okay"; +}; + +&hdmi_cec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hdmi_cec>; - ddc-i2c-bus = <&i2c2>; + status = "okay"; +}; + +&hdmi_core { + ipu_id = <0>; + disp_id = <0>; + status = "okay"; +}; + +&hdmi_video { + fsl,phy_reg_vlev = <0x294>; + fsl,phy_reg_cksymtx = <0x800d>; + HDMI-supply = <®_hdmi>; status = "okay"; }; &i2c1 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>; status = "okay"; codec: wm8962@1a { @@ -253,6 +424,7 @@ vddio-supply = <®_sensors>; }; +#if 0 ov5642: camera@3c { compatible = "ovti,ov5642"; pinctrl-names = "default"; @@ -277,12 +449,32 @@ }; }; }; +#endif + ov564x: ov564x@3c { + compatible = "ovti,ov564x"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu1_2>; + clocks = <&clks IMX6QDL_CLK_CKO>; + clock-names = "csi_mclk"; + DOVDD-supply = <&vgen4_reg>; /* 1.8v */ + AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3, on rev B board is VGEN5 */ + DVDD-supply = <&vgen2_reg>; /* 1.5v*/ + pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */ + rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */ + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + }; }; &i2c2 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>; status = "okay"; touchscreen@4 { @@ -295,6 +487,15 @@ wakeup-gpios = <&gpio6 8 GPIO_ACTIVE_HIGH>; }; + max11801@48 { + compatible = "maxim,max11801"; + reg = <0x48>; + interrupt-parent = <&gpio3>; + interrupts = <26 2>; + work-mode = <1>;/*DCM mode*/ + }; + +#if 0 ov5640: camera@3c { compatible = "ovti,ov5640"; pinctrl-names = "default"; @@ -317,6 +518,22 @@ }; }; }; +#endif + + ov564x_mipi: ov564x_mipi@3c { /* i2c2 driver */ + compatible = "ovti,ov564x_mipi"; + reg = <0x3c>; + clocks = <&clks IMX6QDL_CLK_CKO>; + clock-names = "csi_mclk"; + DOVDD-supply = <&vgen4_reg>; /* 1.8v */ + AVDD-supply = <&vgen3_reg>; /* 2.8v rev C board is VGEN3 rev B board is VGEN5 */ + DVDD-supply = <&vgen2_reg>; /* 1.5v*/ + pwn-gpios = <&gpio1 19 1>; /* active low: SD1_CLK */ + rst-gpios = <&gpio1 20 0>; /* active high: SD1_DAT2 */ + csi_id = <1>; + mclk = <24000000>; + mclk_source = <0>; + }; pmic: pfuze100@8 { compatible = "fsl,pfuze100"; @@ -418,12 +635,20 @@ }; }; }; + + hdmi_edid: edid@50 { + compatible = "fsl,imx6-hdmi-i2c"; + reg = <0x50>; + }; }; &i2c3 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c3>; + pinctrl-1 = <&pinctrl_i2c3_gpio>; + scl-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; status = "okay"; egalax_ts@4 { @@ -446,13 +671,14 @@ }; light-sensor@44 { - compatible = "isil,isl29023"; + compatible = "fsl,isl29023"; reg = <0x44>; + rext = <499>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3_isl29023_int>; interrupt-parent = <&gpio3>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; - vcc-supply = <®_sensors>; + vdd-supply = <®_sensors>; }; }; @@ -472,6 +698,13 @@ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 + MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x80000000 + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x80000000 + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 + MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x80000000 + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x80000000 + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 >; }; @@ -514,6 +747,12 @@ >; }; + pinctrl_enet_irq: enetirqgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; + pinctrl_gpio_keys: gpio_keysgrp { fsl,pins = < MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0 @@ -524,7 +763,14 @@ pinctrl_hdmi_cec: hdmicecgrp { fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x108b0 + >; + }; + + pinctrl_hdmi_hdcp: hdmihdcpgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 >; }; @@ -535,6 +781,13 @@ >; }; + pinctrl_i2c1_gpio: i2c1_gpio_grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x1b0b0 + MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x1b8b0 + >; + }; + pinctrl_i2c1_mma8451_int: i2c1mma8451intgrp { fsl,pins = < MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0xb0b1 @@ -548,6 +801,13 @@ >; }; + pinctrl_i2c2_gpio: i2c2_gpio_grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x1b8b0 + MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x1b0b0 + >; + }; + pinctrl_i2c2_egalax_int: i2c2egalaxintgrp { fsl,pins = < MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x1b0b0 @@ -561,6 +821,13 @@ >; }; + pinctrl_i2c3_gpio: i2c3_gpio_grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x1b8b0 + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 + >; + }; + pinctrl_i2c3_isl29023_int: i2c3isl29023intgrp { fsl,pins = < MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0xb0b1 @@ -573,6 +840,59 @@ >; }; + pinctrl_ipu1: ipu1grp { + fsl,pins = < + MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 + MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 + MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 + MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 + MX6QDL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x80000000 + MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 + MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 + MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 + MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 + MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 + MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 + MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 + MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 + MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 + MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 + MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 + MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 + MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 + MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 + MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 + MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 + MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 + MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 + MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 + MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 + MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 + MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 + MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 + MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 + >; + }; + + pinctrl_ipu1_2: ipu1grp-2 { /* parallel camera */ + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000 + MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000 + MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000 + MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000 + MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000 + MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000 + MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000 + MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000 + MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x80000000 + MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000 + MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000 + MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000 + MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x80000000 + MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000 + >; + }; + pinctrl_ipu1_csi0: ipu1csi0grp { fsl,pins = < MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 @@ -634,6 +954,24 @@ >; }; + pinctrl_uart5_1: uart5grp-1 { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_COL4__UART5_RTS_B 0x1b0b1 + MX6QDL_PAD_KEY_ROW4__UART5_CTS_B 0x1b0b1 + >; + }; + + pinctrl_uart5dte_1: uart5dtegrp-1 { + fsl,pins = < + MX6QDL_PAD_KEY_ROW1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_COL1__UART5_RX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW4__UART5_RTS_B 0x1b0b1 + MX6QDL_PAD_KEY_COL4__UART5_CTS_B 0x1b0b1 + >; + }; + pinctrl_usbotg: usbotggrp { fsl,pins = < MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 @@ -704,16 +1042,45 @@ &ldb { status = "okay"; - lvds-channel@1 { + lvds-channel@0 { fsl,data-mapping = "spwg"; fsl,data-width = <18>; status = "okay"; - port@4 { - reg = <4>; + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; + + lvds-channel@1 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + primary; + status = "okay"; - lvds0_out: endpoint { - remote-endpoint = <&panel_in>; + display-timings { + native-mode = <&timing1>; + timing1: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; }; }; }; @@ -724,7 +1091,7 @@ pinctrl-0 = <&pinctrl_pcie>; reset-gpio = <&gpio7 12 GPIO_ACTIVE_LOW>; vpcie-supply = <®_pcie>; - status = "okay"; + epdev_on-supply = <&vgen3_reg>; }; &pwm1 { @@ -757,11 +1124,14 @@ status = "okay"; }; -&snvs_pwrkey { - status = "okay"; -}; - &ssi2 { + assigned-clocks = <&clks IMX6QDL_CLK_PLL4>, + <&clks IMX6QDL_PLL4_BYPASS>, + <&clks IMX6QDL_CLK_SSI2_SEL>; + assigned-clock-parents = <&clks IMX6QDL_CLK_OSC>, + <&clks IMX6QDL_CLK_PLL4>, + <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <737280000>, <0>, <0>; status = "okay"; }; @@ -808,6 +1178,7 @@ bus-width = <8>; non-removable; no-1-8-v; + auto-cmd23-broken; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index bc488df31511..aef9d63cb031 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -156,6 +156,11 @@ interrupt-parent = <&gpc>; ranges; + caam_sm: caam-sm@100000 { + compatible = "fsl,imx6q-caam-sm"; + reg = <0x100000 0x4000>; + }; + dma_apbh: dma-apbh@110000 { compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; reg = <0x00110000 0x2000>; @@ -215,6 +220,45 @@ }; }; + hdmi_core: hdmi_core@120000 { + compatible = "fsl,imx6q-hdmi-core"; + reg = <0x120000 0x9000>; + clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>, + <&clks IMX6QDL_CLK_HDMI_IAHB>, + <&clks IMX6QDL_CLK_HSI_TX>; + clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core"; + status = "disabled"; + }; + + hdmi_video: hdmi_video@20e0000 { + compatible = "fsl,imx6q-hdmi-video"; + reg = <0x20e0000 0x1000>; + reg-names = "hdmi_gpr"; + interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>, + <&clks IMX6QDL_CLK_HDMI_IAHB>, + <&clks IMX6QDL_CLK_HSI_TX>; + clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core"; + status = "disabled"; + }; + + hdmi_audio: hdmi_audio@120000 { + compatible = "fsl,imx6q-hdmi-audio"; + clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>, + <&clks IMX6QDL_CLK_HDMI_IAHB>, + <&clks IMX6QDL_CLK_HSI_TX>; + clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core"; + dmas = <&sdma 2 26 0>; + dma-names = "tx"; + status = "disabled"; + }; + + hdmi_cec: hdmi_cec@120000 { + compatible = "fsl,imx6q-hdmi-cec"; + interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + gpu_3d: gpu@130000 { compatible = "vivante,gc"; reg = <0x00130000 0x4000>; @@ -225,6 +269,7 @@ clock-names = "bus", "core", "shader"; power-domains = <&pd_pu>; #cooling-cells = <2>; + status = "disabled"; }; gpu_2d: gpu@134000 { @@ -236,6 +281,19 @@ clock-names = "bus", "core"; power-domains = <&pd_pu>; #cooling-cells = <2>; + status = "disabled"; + }; + + ocrams: sram@00900000 { + compatible = "fsl,lpm-sram"; + reg = <0x00900000 0x4000>; + clocks = <&clks IMX6QDL_CLK_OCRAM>; + }; + + ocrams_ddr: sram@00904000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x00904000 0x1000>; + clocks = <&clks IMX6QDL_CLK_OCRAM>; }; timer@a00600 { @@ -294,6 +352,20 @@ status = "disabled"; }; + pcie_ep: pcie_ep@1ffc000 { + compatible = "fsl,imx6q-pcie-ep"; + reg = <0x01ffc000 0x04000>, <0x01000000 0xf00000>; + reg-names = "regs", "addr_space"; + num-lanes = <1>; + clocks = <&clks IMX6QDL_CLK_PCIE_AXI>, + <&clks IMX6QDL_CLK_LVDS1_GATE>, + <&clks IMX6QDL_CLK_PCIE_REF_125M>; + clock-names = "pcie", "pcie_bus", "pcie_phy"; + num-ib-windows = <4>; + num-ob-windows = <4>; + status = "disabled"; + }; + aips-bus@2000000 { /* AIPS1 */ compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -318,7 +390,7 @@ clocks = <&clks IMX6QDL_CLK_SPDIF_GCLK>, <&clks IMX6QDL_CLK_OSC>, <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_ASRC>, <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_ESAI_EXTAL>, - <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_DUMMY>, + <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_MLB>, <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_SPBA>; clock-names = "core", "rxtx0", "rxtx1", "rxtx2", @@ -337,7 +409,7 @@ clocks = <&clks IMX6QDL_CLK_ECSPI1>, <&clks IMX6QDL_CLK_ECSPI1>; clock-names = "ipg", "per"; - dmas = <&sdma 3 8 1>, <&sdma 4 8 2>; + dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; dma-names = "rx", "tx"; status = "disabled"; }; @@ -351,7 +423,7 @@ clocks = <&clks IMX6QDL_CLK_ECSPI2>, <&clks IMX6QDL_CLK_ECSPI2>; clock-names = "ipg", "per"; - dmas = <&sdma 5 8 1>, <&sdma 6 8 2>; + dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; dma-names = "rx", "tx"; status = "disabled"; }; @@ -365,7 +437,7 @@ clocks = <&clks IMX6QDL_CLK_ECSPI3>, <&clks IMX6QDL_CLK_ECSPI3>; clock-names = "ipg", "per"; - dmas = <&sdma 7 8 1>, <&sdma 8 8 2>; + dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; dma-names = "rx", "tx"; status = "disabled"; }; @@ -379,7 +451,7 @@ clocks = <&clks IMX6QDL_CLK_ECSPI4>, <&clks IMX6QDL_CLK_ECSPI4>; clock-names = "ipg", "per"; - dmas = <&sdma 9 8 1>, <&sdma 10 8 2>; + dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; dma-names = "rx", "tx"; status = "disabled"; }; @@ -502,6 +574,24 @@ power-domains = <&pd_pu>; resets = <&src 1>; iram = <&ocram>; + status = "disabled"; + }; + + vpu_fsl: vpu_fsl@2040000 { + compatible = "fsl,imx6-vpu"; + reg = <0x2040000 0x3c000>; + reg-names = "vpu_regs"; + interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>, + <0 12 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "vpu_jpu_irq", "vpu_ipi_irq"; + clocks = <&clks IMX6QDL_CLK_VPU_AXI>, + <&clks IMX6QDL_CLK_MMDC_CH0_AXI>, + <&clks IMX6QDL_CLK_OCRAM>; + clock-names = "vpu_clk", "mmdc_ch0_axi", "ocram"; + iramsize = <0x21000>; + iram = <&ocram>; + resets = <&src 1>; + power-domains = <&pd_pu>; }; aipstz@207c000 { /* AIPSTZ1 */ @@ -759,6 +849,7 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; }; reg_pu: regulator-vddpu { @@ -776,6 +867,7 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; }; reg_soc: regulator-vddsoc { @@ -793,6 +885,7 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; }; }; @@ -812,6 +905,20 @@ fsl,anatop = <&anatop>; }; + irq_sec_vio: caam_secvio { + compatible = "fsl,imx6q-caam-secvio"; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + jtag-tamper = "disabled"; + watchdog-tamper = "enabled"; + internal-boot-tamper = "enabled"; + external-pin-tamper = "disabled"; + }; + + caam_snvs: caam-snvs@20cc000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x20cc000 0x4000>; + }; + snvs: snvs@20cc000 { compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; reg = <0x020cc000 0x4000>; @@ -914,13 +1021,23 @@ }; dcic1: dcic@20e4000 { - reg = <0x020e4000 0x4000>; + compatible = "fsl,imx6q-dcic"; + reg = <0x20e4000 0x4000>; interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_DCIC1>, <&clks IMX6QDL_CLK_DCIC1>; + clock-names = "dcic", "disp-axi"; + gpr = <&gpr>; + status = "disabled"; }; dcic2: dcic@20e8000 { - reg = <0x020e8000 0x4000>; + compatible = "fsl,imx6q-dcic"; + reg = <0x20e8000 0x4000>; interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_DCIC2>, <&clks IMX6QDL_CLK_DCIC2>; + clock-names = "dcic", "disp-axi"; + gpr = <&gpr>; + status = "disabled"; }; sdma: sdma@20ec000 { @@ -1039,20 +1156,28 @@ compatible = "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; interrupt-names = "int0", "pps"; - interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>, - <0 119 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = + <&gpc 0 118 IRQ_TYPE_LEVEL_HIGH>, + <&gpc 0 119 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_ENET>, <&clks IMX6QDL_CLK_ENET>, <&clks IMX6QDL_CLK_ENET_REF>; clock-names = "ipg", "ahb", "ptp"; + stop-mode = <&gpr 0x34 27>; + fsl,wakeup_irq = <0>; status = "disabled"; }; - mlb@218c000 { + mlb: mlb@218c000 { + compatible = "fsl,imx6q-mlb150"; reg = <0x0218c000 0x4000>; interrupts = <0 53 IRQ_TYPE_LEVEL_HIGH>, <0 117 IRQ_TYPE_LEVEL_HIGH>, <0 126 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_MLB>; + clock-names = "mlb"; + iram = <&ocram>; + status = "disabled"; }; usdhc1: usdhc@2190000 { @@ -1137,6 +1262,11 @@ reg = <0x021ac000 0x4000>; }; + mmdc0-1@021b0000 { /* MMDC0-1 */ + compatible = "fsl,imx6q-mmdc-combine"; + reg = <0x021b0000 0x8000>; + }; + mmdc0: memory-controller@21b0000 { /* MMDC0 */ compatible = "fsl,imx6q-mmdc"; reg = <0x021b0000 0x4000>; @@ -1183,15 +1313,15 @@ }; mipi_csi: mipi@21dc000 { - compatible = "fsl,imx6-mipi-csi2"; + compatible = "fsl,imx6q-mipi-csi2"; reg = <0x021dc000 0x4000>; #address-cells = <1>; #size-cells = <0>; interrupts = <0 100 0x04>, <0 101 0x04>; clocks = <&clks IMX6QDL_CLK_HSI_TX>, <&clks IMX6QDL_CLK_VIDEO_27M>, - <&clks IMX6QDL_CLK_EIM_PODF>; - clock-names = "dphy", "ref", "pix"; + <&clks IMX6QDL_CLK_EIM_SEL>; + clock-names = "dphy_clk", "cfg_clk", "pixel_clk"; status = "disabled"; }; @@ -1226,6 +1356,7 @@ reg = <0x021e4000 0x4000>; interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_VDOA>; + iram = <&ocram>; }; uart2: serial@21e8000 { @@ -1285,10 +1416,15 @@ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>, <0 5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_IPU1>, - <&clks IMX6QDL_CLK_IPU1_DI0>, - <&clks IMX6QDL_CLK_IPU1_DI1>; - clock-names = "bus", "di0", "di1"; + <&clks IMX6QDL_CLK_IPU1_DI0>, <&clks IMX6QDL_CLK_IPU1_DI1>, + <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, + <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>; + clock-names = "bus", + "di0", "di1", + "di0_sel", "di1_sel", + "ldb_di0", "ldb_di1"; resets = <&src 2>; + bypass_reset = <0>; ipu1_csi0: port@0 { reg = <0>; diff --git a/arch/arm/boot/dts/imx6qp-sabreauto-ecspi.dts b/arch/arm/boot/dts/imx6qp-sabreauto-ecspi.dts new file mode 100644 index 000000000000..b69e758b36ec --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabreauto-ecspi.dts @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2015 Freescale Semiconductor, Inc. + + +#include "imx6qp-sabreauto.dts" + +&ecspi1 { + pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&can2 { + /* max7310_c on i2c3 is gone */ + status = "disabled"; +}; + +&i2c3 { + /* pin conflict with ecspi1 */ + status = "disabled"; +}; + +&uart3 { + /* the uart3 depends on the i2c3, so disable it too. */ + status = "disabled"; +}; + +&usbh1 { + /* max7310_b on i2c3 is gone */ + status = "disabled"; +}; + +&usbotg { + /* max7310_c on i2c3 is gone */ + status = "okay"; + dr_mode = "peripheral"; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabreauto-flexcan1.dts b/arch/arm/boot/dts/imx6qp-sabreauto-flexcan1.dts new file mode 100644 index 000000000000..b57607b0c222 --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabreauto-flexcan1.dts @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6qp-sabreauto.dts" + +&can1{ + status = "okay"; +}; + +&fec { + /* pin conflict with flexcan1 */ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabreauto-gpmi-weim.dts b/arch/arm/boot/dts/imx6qp-sabreauto-gpmi-weim.dts new file mode 100644 index 000000000000..1ca09d7dfca5 --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabreauto-gpmi-weim.dts @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2015 Freescale Semiconductor, Inc. + +#include "imx6qp-sabreauto.dts" + +&ecspi1 { + /* pin conflict with weim */ + status = "disabled"; +}; + +&can2 { + /* max7310_c on i2c3 is gone */ + status = "disabled"; +}; + +&gpmi { + compatible = "fsl,imx6qp-gpmi-nand"; + status = "okay"; +}; + +&i2c3 { + /* pin conflict with weim */ + status = "disabled"; +}; + +&uart3 { + /* pin conflict with gpmi and weim */ + status = "disabled"; +}; + +&usbh1 { + /* max7310_b on i2c3 is gone */ + status = "disabled"; +}; + +&usbotg { + /* max7310_c on i2c3 is gone */ + status = "okay"; + dr_mode = "peripheral"; +}; + +&weim { + pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabreauto.dts b/arch/arm/boot/dts/imx6qp-sabreauto.dts index d4caeeb0af70..e6a69467a4bb 100644 --- a/arch/arm/boot/dts/imx6qp-sabreauto.dts +++ b/arch/arm/boot/dts/imx6qp-sabreauto.dts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ OR MIT // // Copyright 2016 Freescale Semiconductor, Inc. +// Copyright 2020 NXP /dts-v1/; @@ -12,6 +13,62 @@ compatible = "fsl,imx6qp-sabreauto", "fsl,imx6qp"; }; +&pre1 { + status = "okay"; +}; + +&pre2 { + status = "okay"; +}; + +&pre3 { + status = "okay"; +}; + +&pre4 { + status = "okay"; +}; + +&prg1 { + memory-region = <&memory>; + status = "okay"; +}; + +&prg2 { + memory-region = <&memory>; + status = "okay"; +}; + +&mxcfb1 { + prefetch; + status = "okay"; +}; + +&mxcfb2 { + prefetch; + status = "okay"; +}; + +&mxcfb3 { + prefetch; + status = "okay"; +}; + +&mxcfb4 { + prefetch; + status = "okay"; +}; + +&ldb { + lvds-channel@0 { + crtc = "ipu2-di0"; + }; + + lvds-channel@1 { + crtc = "ipu2-di1"; + }; +}; + &i2c2 { max7322: gpio@68 { compatible = "maxim,max7322"; @@ -21,33 +78,13 @@ }; }; -&iomuxc { - imx6qdl-sabreauto { - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b018 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b018 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b018 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b018 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b018 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b018 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b018 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b018 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b018 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b018 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b018 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b018 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; - }; +&pcie { + reset-gpio = <&max7310_c 5 GPIO_ACTIVE_LOW>; + status = "okay"; }; -&pcie { - status = "disabled"; +&sata { + status = "okay"; }; &vgen3_reg { diff --git a/arch/arm/boot/dts/imx6qp-sabresd-btwifi.dts b/arch/arm/boot/dts/imx6qp-sabresd-btwifi.dts new file mode 100644 index 000000000000..e83d04f14600 --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabresd-btwifi.dts @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6qp-sabresd.dts" +#include "imx6qdl-sabresd-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6qp-sabresd-hdcp.dts b/arch/arm/boot/dts/imx6qp-sabresd-hdcp.dts new file mode 100644 index 000000000000..e19ff136c226 --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabresd-hdcp.dts @@ -0,0 +1,39 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * 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 "imx6qp-sabresd.dts" + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +&hdmi_video { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi_hdcp>; + fsl,hdcp; +}; + +&i2c2 { + status = "disable"; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabresd-ldo.dts b/arch/arm/boot/dts/imx6qp-sabresd-ldo.dts new file mode 100644 index 000000000000..f33eb65a793e --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabresd-ldo.dts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6qp-sabresd.dts" + +&wdog1 { + status = "okay"; +}; + +&wdog2 { + status = "disabled"; +}; + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; + +&wdog1 { + status = "okay"; +}; + +&wdog2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabresd-pcie-ep.dts b/arch/arm/boot/dts/imx6qp-sabresd-pcie-ep.dts new file mode 100644 index 000000000000..9f59ff908142 --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-sabresd-pcie-ep.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6qp-sabresd.dts" + +&pcie{ + status = "disabled"; +}; + +&pcie_ep{ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabresd.dts b/arch/arm/boot/dts/imx6qp-sabresd.dts index f1b9cb104fdd..03320e210e24 100644 --- a/arch/arm/boot/dts/imx6qp-sabresd.dts +++ b/arch/arm/boot/dts/imx6qp-sabresd.dts @@ -50,6 +50,76 @@ }; }; +&ov564x { + AVDD-supply = <&vgen6_reg>; /* 2.8v */ + DOVDD-supply = <&sw4_reg>; /* 1.8v */ +}; + +&ov564x_mipi { + AVDD-supply = <&vgen6_reg>; /* 2.8v */ + DOVDD-supply = <&sw4_reg>; /* 1.8v */ +}; + &pcie { - status = "disabled"; + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&pre1 { + status = "okay"; +}; + +&pre2 { + status = "okay"; +}; + +&pre3 { + status = "okay"; +}; + +&pre4 { + status = "okay"; +}; + +&prg1 { + memory-region = <&memory>; + status = "okay"; +}; + +&prg2 { + memory-region = <&memory>; + status = "okay"; +}; + +&mxcfb1 { + prefetch; + status = "okay"; +}; + +&mxcfb2 { + prefetch; + status = "okay"; +}; + +&mxcfb3 { + prefetch; + status = "okay"; +}; + +&mxcfb4 { + prefetch; + status = "okay"; +}; + +&ldb { + lvds-channel@0 { + crtc = "ipu2-di0"; + }; + + lvds-channel@1 { + crtc = "ipu2-di1"; + }; }; diff --git a/arch/arm/boot/dts/imx6qp.dtsi b/arch/arm/boot/dts/imx6qp.dtsi index d91f92f944c5..cd074d1b9b1f 100644 --- a/arch/arm/boot/dts/imx6qp.dtsi +++ b/arch/arm/boot/dts/imx6qp.dtsi @@ -5,6 +5,15 @@ #include "imx6q.dtsi" / { + aliases { + pre0 = &pre1; + pre1 = &pre2; + pre2 = &pre3; + pre3 = &pre4; + prg0 = &prg1; + prg1 = &prg2; + }; + soc { ocram2: sram@940000 { compatible = "mmio-sram"; @@ -20,57 +29,63 @@ aips-bus@2100000 { pre1: pre@21c8000 { - compatible = "fsl,imx6qp-pre"; + compatible = "fsl,imx6q-pre"; reg = <0x021c8000 0x1000>; interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>; clocks = <&clks IMX6QDL_CLK_PRE0>; clock-names = "axi"; - fsl,iram = <&ocram2>; + ocram = <&ocram2>; + status = "disabled"; }; pre2: pre@21c9000 { - compatible = "fsl,imx6qp-pre"; + compatible = "fsl,imx6q-pre"; reg = <0x021c9000 0x1000>; interrupts = <GIC_SPI 97 IRQ_TYPE_EDGE_RISING>; clocks = <&clks IMX6QDL_CLK_PRE1>; clock-names = "axi"; - fsl,iram = <&ocram2>; + ocram = <&ocram2>; + status = "disabled"; }; pre3: pre@21ca000 { - compatible = "fsl,imx6qp-pre"; + compatible = "fsl,imx6q-pre"; reg = <0x021ca000 0x1000>; interrupts = <GIC_SPI 98 IRQ_TYPE_EDGE_RISING>; clocks = <&clks IMX6QDL_CLK_PRE2>; clock-names = "axi"; - fsl,iram = <&ocram3>; + ocram = <&ocram3>; + status = "disabled"; }; pre4: pre@21cb000 { - compatible = "fsl,imx6qp-pre"; + compatible = "fsl,imx6q-pre"; reg = <0x021cb000 0x1000>; interrupts = <GIC_SPI 99 IRQ_TYPE_EDGE_RISING>; clocks = <&clks IMX6QDL_CLK_PRE3>; clock-names = "axi"; - fsl,iram = <&ocram3>; + ocram = <&ocram3>; + status = "disabled"; }; prg1: prg@21cc000 { - compatible = "fsl,imx6qp-prg"; + compatible = "fsl,imx6q-prg"; reg = <0x021cc000 0x1000>; clocks = <&clks IMX6QDL_CLK_PRG0_APB>, <&clks IMX6QDL_CLK_PRG0_AXI>; - clock-names = "ipg", "axi"; - fsl,pres = <&pre1>, <&pre2>, <&pre3>; + clock-names = "apb", "axi"; + gpr = <&gpr>; + status = "disabled"; }; prg2: prg@21cd000 { - compatible = "fsl,imx6qp-prg"; + compatible = "fsl,imx6q-prg"; reg = <0x021cd000 0x1000>; clocks = <&clks IMX6QDL_CLK_PRG1_APB>, <&clks IMX6QDL_CLK_PRG1_AXI>; - clock-names = "ipg", "axi"; - fsl,pres = <&pre4>, <&pre2>, <&pre3>; + clock-names = "apb", "axi"; + gpr = <&gpr>; + status = "disabled"; }; }; }; @@ -87,22 +102,34 @@ &ipu1 { compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu"; + clocks = <&clks IMX6QDL_CLK_IPU1>, + <&clks IMX6QDL_CLK_IPU1_DI0>, <&clks IMX6QDL_CLK_IPU1_DI1>, + <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>, + <&clks IMX6QDL_CLK_PRG0_APB>; + clock-names = "bus", + "di0", "di1", + "di0_sel", "di1_sel", + "ldb_di0", "ldb_di1", "prg"; fsl,prg = <&prg1>; }; &ipu2 { compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu"; + clocks = <&clks IMX6QDL_CLK_IPU2>, + <&clks IMX6QDL_CLK_IPU2_DI0>, <&clks IMX6QDL_CLK_IPU2_DI1>, + <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, + <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>, + <&clks IMX6QDL_CLK_PRG1_APB>; + clock-names = "bus", + "di0", "di1", + "di0_sel", "di1_sel", + "ldb_di0", "ldb_di1", "prg"; fsl,prg = <&prg2>; }; &ldb { - clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>, - <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, - <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, - <&clks IMX6QDL_CLK_LDB_DI0_PODF>, <&clks IMX6QDL_CLK_LDB_DI1_PODF>; - clock-names = "di0_pll", "di1_pll", - "di0_sel", "di1_sel", "di2_sel", "di3_sel", - "di0", "di1"; + compatible = "fsl,imx6qp-ldb", "fsl,imx6q-ldb", "fsl,imx53-ldb"; }; &mmdc0 { @@ -112,3 +139,7 @@ &pcie { compatible = "fsl,imx6qp-pcie", "snps,dw-pcie"; }; + +&pcie_ep { + compatible = "fsl,imx6qp-pcie-ep"; +}; diff --git a/arch/arm/boot/dts/imx6sl-evk-btwifi.dts b/arch/arm/boot/dts/imx6sl-evk-btwifi.dts new file mode 100644 index 000000000000..01867f57d41a --- /dev/null +++ b/arch/arm/boot/dts/imx6sl-evk-btwifi.dts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* NOTE: This DTS file is written for plugging in Murata Wi-Fi/BT EVK into SD1 + * slot using Murata i.MX InterConnect Ver 1.0 Adapter AND wiring in control + * signals with SD Card Extender on SD3 slot. + * Bluetooth UART connect via SD1 EMMC/MMC Plus pinout. + * WL_REG_ON/BT_REG_ON/WL_HOST_WAKE are connected from SD Card Extender on SD3 + * slot. + */ +#include "imx6sl-evk.dts" + +/ { + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + usdhc1_pwrseq: usdhc1_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio5 16 GPIO_ACTIVE_LOW>; + }; +}; + +&iomuxc { + imx6sl-evk-murata-v1_sdext { + /* Only MUX SD1_DAT0..3 lines so UART4 can be MUXed on higher data lines. */ + pinctrl_btreg: btreggrp { + fsl,pins = < + MX6SL_PAD_SD3_DAT3__GPIO5_IO17 0x13069 /* BT_REG_ON */ + >; + }; + + pinctrl_wifi: wifigrp { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + MX6SL_PAD_SD3_DAT1__GPIO5_IO20 0x13069 /* WL_HOST_WAKE */ + MX6SL_PAD_SD3_DAT2__GPIO5_IO16 0x13069 /* WL_REG_ON */ + >; + }; + + pinctrl_usdhc3_1: usdhc3grp-1 { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + >; + }; + }; +}; +/* Murata: declare UART4 interface for Bluetooth. */ +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4_1 + &pinctrl_btreg>; + fsl,uart-has-rtscts; + resets = <&modem_reset>; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart4dte_1>; */ +}; + +&usdhc1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wifi>; + bus-width = <4>; + no-1-8-v; + non-removable; + mmc-pwrseq = <&usdhc1_pwrseq>; + pm-ignore-notify; + cap-power-off-card; + /delete-property/ enable-sdio-wakeup; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3_1>; + bus-width = <1>; + no-1-8-v; +}; diff --git a/arch/arm/boot/dts/imx6sl-evk-csi.dts b/arch/arm/boot/dts/imx6sl-evk-csi.dts new file mode 100644 index 000000000000..589d33f715d4 --- /dev/null +++ b/arch/arm/boot/dts/imx6sl-evk-csi.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +// +//Copyright (C) 2013 Freescale Semiconductor, Inc. + +#include "imx6sl-evk.dts" + +&csi { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&epdc { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6sl-evk-ldo.dts b/arch/arm/boot/dts/imx6sl-evk-ldo.dts new file mode 100644 index 000000000000..5ca3a09df2b9 --- /dev/null +++ b/arch/arm/boot/dts/imx6sl-evk-ldo.dts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6sl-evk.dts" + +&gpc { + /* use ldo-enable, u-boot will check it and configure */ + fsl,ldo-bypass = <0>; +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_pu { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6sl-evk-uart.dts b/arch/arm/boot/dts/imx6sl-evk-uart.dts new file mode 100644 index 000000000000..6179842731a7 --- /dev/null +++ b/arch/arm/boot/dts/imx6sl-evk-uart.dts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6sl-evk.dts" + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4_1>; + fsl,uart-has-rtscts; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart4dte_1>; */ +}; + +&usdhc1 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index bc86cfaaa9c2..319c881d631d 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -12,6 +12,19 @@ model = "Freescale i.MX6 SoloLite EVK Board"; compatible = "fsl,imx6sl-evk", "fsl,imx6sl"; + battery: max8903@0 { + compatible = "fsl,max8903-charger"; + pinctrl-names = "default"; + dok_input = <&gpio4 13 1>; + uok_input = <&gpio4 13 1>; + chg_input = <&gpio4 15 1>; + flt_input = <&gpio4 14 1>; + fsl,dcm_always_high; + fsl,dc_valid; + fsl,adc_disable; + status = "okay"; + }; + chosen { stdout-path = &uart1; }; @@ -21,6 +34,19 @@ reg = <0x80000000 0x40000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + linux,cma-default; + }; + }; + backlight_display: backlight_display { compatible = "pwm-backlight"; pwms = <&pwm1 0 5000000>; @@ -40,6 +66,11 @@ }; }; + pxp_v4l2_out { + compatible = "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + reg_usb_otg1_vbus: regulator-usb-otg1-vbus { compatible = "regulator-fixed"; regulator-name = "usb_otg1_vbus"; @@ -95,7 +126,7 @@ sound { compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962"; model = "wm8962-audio"; - ssi-controller = <&ssi2>; + audio-cpu = <&ssi2>; audio-codec = <&codec>; audio-routing = "Headphone Jack", "HPOUTL", @@ -106,6 +137,8 @@ "IN3R", "AMIC"; mux-int-port = <2>; mux-ext-port = <3>; + codec-master; + hp-det-gpios = <&gpio4 19 1>; }; panel { @@ -128,6 +161,14 @@ status = "okay"; }; +&csi { + port { + csi_ep: endpoint { + remote-endpoint = <&ov5640_ep>; + }; + }; +}; + &ecspi1 { cs-gpios = <&gpio4 11 0>; pinctrl-names = "default"; @@ -143,6 +184,15 @@ }; }; +&epdc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_epdc_0>; + V3P3-supply = <&V3P3_reg>; + VCOM-supply = <&VCOM_reg>; + DISPLAY-supply = <&DISPLAY_reg>; + status = "okay"; +}; + &fec { pinctrl-names = "default", "sleep"; pinctrl-0 = <&pinctrl_fec>; @@ -151,6 +201,10 @@ status = "okay"; }; +&gpc { + fsl,ldo-bypass = <1>; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -257,6 +311,89 @@ }; }; }; + + elan@10 { + compatible = "elan,elan-touch"; + reg = <0x10>; + interrupt-parent = <&gpio2>; + interrupts = <10 2>; + gpio_elan_cs = <&gpio2 9 0>; + gpio_elan_rst = <&gpio4 4 0>; + gpio_intr = <&gpio2 10 0>; + status = "okay"; + }; + + ma8450@1c { + compatible = "fsl,mma8450"; + reg = <0x1c>; + }; + + max17135@48 { + compatible = "maxim,max17135"; + reg = <0x48>; + vneg_pwrup = <1>; + gvee_pwrup = <2>; + vpos_pwrup = <10>; + gvdd_pwrup = <12>; + gvdd_pwrdn = <1>; + vpos_pwrdn = <2>; + gvee_pwrdn = <8>; + vneg_pwrdn = <10>; + gpio_pmic_pwrgood = <&gpio2 13 0>; + gpio_pmic_vcom_ctrl = <&gpio2 3 0>; + gpio_pmic_wakeup = <&gpio2 14 0>; + gpio_pmic_v3p3 = <&gpio2 7 0>; + gpio_pmic_intr = <&gpio2 12 0>; + + regulators { + DISPLAY_reg: DISPLAY { + regulator-name = "DISPLAY"; + }; + + GVDD_reg: GVDD { + /* 20v */ + regulator-name = "GVDD"; + }; + + GVEE_reg: GVEE { + /* -22v */ + regulator-name = "GVEE"; + }; + + HVINN_reg: HVINN { + /* -22v */ + regulator-name = "HVINN"; + }; + + HVINP_reg: HVINP { + /* 20v */ + regulator-name = "HVINP"; + }; + + VCOM_reg: VCOM { + regulator-name = "VCOM"; + /* Real max value: -500000 */ + regulator-max-microvolt = <4325000>; + /* Real min value: -4325000 */ + regulator-min-microvolt = <500000>; + }; + + VNEG_reg: VNEG { + /* -15v */ + regulator-name = "VNEG"; + }; + + VPOS_reg: VPOS { + /* 15v */ + regulator-name = "VPOS"; + }; + + V3P3_reg: V3P3 { + regulator-name = "V3P3"; + }; + }; + }; + }; &i2c2 { @@ -280,6 +417,34 @@ }; }; +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "disabled"; + + ov5640: ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi_0>; + clocks = <&clks IMX6SL_CLK_CSI>; + clock-names = "csi_mclk"; + AVDD-supply = <&vgen6_reg>; /* 2.8v */ + DVDD-supply = <&vgen2_reg>; /* 1.5v*/ + pwn-gpios = <&gpio1 25 1>; + rst-gpios = <&gpio1 26 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + port { + ov5640_ep: endpoint { + remote-endpoint = <&csi_ep>; + }; + }; + }; +}; + &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; @@ -295,6 +460,13 @@ MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 + MX6SL_PAD_EPDC_PWRCTRL3__GPIO2_IO10 0x17000 + MX6SL_PAD_EPDC_PWRCTRL2__GPIO2_IO09 0x80000000 + MX6SL_PAD_KEY_COL6__GPIO4_IO04 0x110b0 + MX6SL_PAD_ECSPI2_MISO__GPIO4_IO14 0x17000 + MX6SL_PAD_ECSPI2_MOSI__GPIO4_IO13 0x17000 + MX6SL_PAD_ECSPI2_SS0__GPIO4_IO15 0x17000 + MX6SL_PAD_FEC_RX_ER__GPIO4_IO19 0x1b0b0 >; }; @@ -316,6 +488,39 @@ >; }; + pinctrl_epdc_0: epdcgrp-0 { + fsl,pins = < + MX6SL_PAD_EPDC_D0__EPDC_DATA00 0x80000000 + MX6SL_PAD_EPDC_D1__EPDC_DATA01 0x80000000 + MX6SL_PAD_EPDC_D2__EPDC_DATA02 0x80000000 + MX6SL_PAD_EPDC_D3__EPDC_DATA03 0x80000000 + MX6SL_PAD_EPDC_D4__EPDC_DATA04 0x80000000 + MX6SL_PAD_EPDC_D5__EPDC_DATA05 0x80000000 + MX6SL_PAD_EPDC_D6__EPDC_DATA06 0x80000000 + MX6SL_PAD_EPDC_D7__EPDC_DATA07 0x80000000 + MX6SL_PAD_EPDC_D8__EPDC_DATA08 0x80000000 + MX6SL_PAD_EPDC_D9__EPDC_DATA09 0x80000000 + MX6SL_PAD_EPDC_D10__EPDC_DATA10 0x80000000 + MX6SL_PAD_EPDC_D11__EPDC_DATA11 0x80000000 + MX6SL_PAD_EPDC_D12__EPDC_DATA12 0x80000000 + MX6SL_PAD_EPDC_D13__EPDC_DATA13 0x80000000 + MX6SL_PAD_EPDC_D14__EPDC_DATA14 0x80000000 + MX6SL_PAD_EPDC_D15__EPDC_DATA15 0x80000000 + MX6SL_PAD_EPDC_GDCLK__EPDC_GDCLK 0x80000000 + MX6SL_PAD_EPDC_GDSP__EPDC_GDSP 0x80000000 + MX6SL_PAD_EPDC_GDOE__EPDC_GDOE 0x80000000 + MX6SL_PAD_EPDC_GDRL__EPDC_GDRL 0x80000000 + MX6SL_PAD_EPDC_SDCLK__EPDC_SDCLK_P 0x80000000 + MX6SL_PAD_EPDC_SDOE__EPDC_SDOE 0x80000000 + MX6SL_PAD_EPDC_SDLE__EPDC_SDLE 0x80000000 + MX6SL_PAD_EPDC_SDSHR__EPDC_SDSHR 0x80000000 + MX6SL_PAD_EPDC_BDR0__EPDC_BDR0 0x80000000 + MX6SL_PAD_EPDC_SDCE0__EPDC_SDCE0 0x80000000 + MX6SL_PAD_EPDC_SDCE1__EPDC_SDCE1 0x80000000 + MX6SL_PAD_EPDC_SDCE2__EPDC_SDCE2 0x80000000 + >; + }; + pinctrl_fec: fecgrp { fsl,pins = < MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 @@ -358,6 +563,13 @@ >; }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6SL_PAD_EPDC_SDCE2__I2C3_SCL 0x4001b8b1 + MX6SL_PAD_EPDC_SDCE3__I2C3_SDA 0x4001b8b1 + >; + }; + pinctrl_kpp: kppgrp { fsl,pins = < MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 @@ -427,6 +639,24 @@ >; }; + pinctrl_uart4_1: uart4grp-1 { + fsl,pins = < + MX6SL_PAD_SD1_DAT4__UART4_RX_DATA 0x1b0b1 + MX6SL_PAD_SD1_DAT5__UART4_TX_DATA 0x1b0b1 + MX6SL_PAD_SD1_DAT7__UART4_CTS_B 0x1b0b1 + MX6SL_PAD_SD1_DAT6__UART4_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart4dte_1: uart4dtegrp-1 { + fsl,pins = < + MX6SL_PAD_SD1_DAT5__UART4_RX_DATA 0x1b0b1 + MX6SL_PAD_SD1_DAT4__UART4_TX_DATA 0x1b0b1 + MX6SL_PAD_SD1_DAT6__UART4_CTS_B 0x1b0b1 + MX6SL_PAD_SD1_DAT7__UART4_RTS_B 0x1b0b1 + >; + }; + pinctrl_usbotg1: usbotg1grp { fsl,pins = < MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 @@ -543,9 +773,34 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 >; }; + + pinctrl_csi_0: csigrp-0 { + fsl,pins = < + MX6SL_PAD_EPDC_GDRL__CSI_MCLK 0x110b0 + MX6SL_PAD_EPDC_GDCLK__CSI_PIXCLK 0x110b0 + MX6SL_PAD_EPDC_GDSP__CSI_VSYNC 0x110b0 + MX6SL_PAD_EPDC_GDOE__CSI_HSYNC 0x110b0 + MX6SL_PAD_EPDC_SDLE__CSI_DATA09 0x110b0 + MX6SL_PAD_EPDC_SDCLK__CSI_DATA08 0x110b0 + MX6SL_PAD_EPDC_D7__CSI_DATA07 0x110b0 + MX6SL_PAD_EPDC_D6__CSI_DATA06 0x110b0 + MX6SL_PAD_EPDC_D5__CSI_DATA05 0x110b0 + MX6SL_PAD_EPDC_D4__CSI_DATA04 0x110b0 + MX6SL_PAD_EPDC_D3__CSI_DATA03 0x110b0 + MX6SL_PAD_EPDC_D2__CSI_DATA02 0x110b0 + MX6SL_PAD_EPDC_D1__CSI_DATA01 0x110b0 + MX6SL_PAD_EPDC_D0__CSI_DATA00 0x110b0 + MX6SL_PAD_EPDC_SDSHR__GPIO1_IO26 0x80000000 + MX6SL_PAD_EPDC_SDOE__GPIO1_IO25 0x80000000 + >; + }; }; }; +&pxp { + status = "okay"; +}; + &kpp { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_kpp>; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 3a96b5538a2a..2a1c686244a4 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -66,11 +66,17 @@ >; clock-latency = <61036>; /* two CLK32 periods */ #cooling-cells = <2>; - clocks = <&clks IMX6SL_CLK_ARM>, <&clks IMX6SL_CLK_PLL2_PFD2>, - <&clks IMX6SL_CLK_STEP>, <&clks IMX6SL_CLK_PLL1_SW>, - <&clks IMX6SL_CLK_PLL1_SYS>; + clocks = <&clks IMX6SL_CLK_ARM>, + <&clks IMX6SL_CLK_PLL2_PFD2>, + <&clks IMX6SL_CLK_STEP>, + <&clks IMX6SL_CLK_PLL1_SW>, + <&clks IMX6SL_CLK_PLL1_SYS>, + <&clks IMX6SL_CLK_PLL1>, + <&clks IMX6SL_PLL1_BYPASS>, + <&clks IMX6SL_PLL1_BYPASS_SRC>; clock-names = "arm", "pll2_pfd2_396m", "step", - "pll1_sw", "pll1_sys"; + "pll1_sw", "pll1_sys", "pll1", "pll1_bypass", + "pll1_bypass_src"; arm-supply = <®_arm>; pu-supply = <®_pu>; soc-supply = <®_soc>; @@ -118,12 +124,51 @@ interrupt-parent = <&gpc>; ranges; - ocram: sram@900000 { + busfreq { /* BUSFREQ */ + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6SL_CLK_PLL2_BUS>, <&clks IMX6SL_CLK_PLL2_PFD2>, + <&clks IMX6SL_CLK_PLL2_198M>, <&clks IMX6SL_CLK_ARM>, + <&clks IMX6SL_CLK_PLL3_USB_OTG>, <&clks IMX6SL_CLK_PERIPH>, + <&clks IMX6SL_CLK_PRE_PERIPH_SEL>, <&clks IMX6SL_CLK_PERIPH_CLK2_PODF>, + <&clks IMX6SL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6SL_CLK_OSC>, + <&clks IMX6SL_CLK_PLL1_SYS>, <&clks IMX6SL_CLK_PERIPH2>, + <&clks IMX6SL_CLK_AHB>, <&clks IMX6SL_CLK_OCRAM_PODF>, + <&clks IMX6SL_CLK_PLL1_SW>, <&clks IMX6SL_CLK_PRE_PERIPH2_SEL>, + <&clks IMX6SL_CLK_PERIPH2_CLK2_SEL>, <&clks IMX6SL_CLK_PERIPH2_CLK2_PODF>, + <&clks IMX6SL_CLK_STEP>, <&clks IMX6SL_PLL2_BYPASS_SRC>, <&clks IMX6SL_PLL2_BYPASS>, + <&clks IMX6SL_CLK_PLL2>, <&clks IMX6SL_CLK_PLL1>, <&clks IMX6SL_PLL1_BYPASS>, + <&clks IMX6SL_PLL1_BYPASS_SRC>; + clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", + "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "pll1_sys", "periph2", "ahb", + "ocram", "pll1_sw", "periph2_pre", "periph2_clk2_sel", "periph2_clk2", "step", "pll2_bypass_src", + "pll2_bypass", "pll2", "pll1", "pll1_bypass", "pll1_bypass_src"; + fsl,max_ddr_freq = <400000000>; + }; + + ocrams: sram@900000 { + compatible = "fsl,lpm-sram"; + reg = <0x900000 0x4000>; + clocks = <&clks IMX6SL_CLK_OCRAM>; + }; + + ocrams_ddr: sram@904000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x904000 0x1000>; + clocks = <&clks IMX6SL_CLK_OCRAM>; + }; + + ocram: sram@905000 { compatible = "mmio-sram"; - reg = <0x00900000 0x20000>; + reg = <0x905000 0x1B000>; clocks = <&clks IMX6SL_CLK_OCRAM>; }; + ocram_optee: sram@918000 { + compatible = "fsl,optee-lpm-sram"; + reg = <0x918000 0x8000>; + overw_reg = <&ocram 0x905000 0x13000>; + }; + intc: interrupt-controller@a01000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; @@ -591,6 +636,7 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; }; reg_pu: regulator-vddpu { @@ -607,6 +653,7 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; }; reg_soc: regulator-vddsoc { @@ -624,6 +671,7 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; }; }; @@ -734,8 +782,14 @@ }; csi: csi@20e4000 { - reg = <0x020e4000 0x4000>; + compatible = "fsl,imx6sl-csi"; + reg = <0x20e4000 0x4000>; interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_DUMMY>, + <&clks IMX6SL_CLK_DUMMY>, + <&clks IMX6SL_CLK_DUMMY>; + clock-names = "disp-axi", "csi_mclk", "disp_dcic"; + status = "disabled"; }; spdc: spdc@20e8000 { @@ -756,13 +810,20 @@ }; pxp: pxp@20f0000 { - reg = <0x020f0000 0x4000>; + compatible = "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; + reg = <0x20f0000 0x4000>; interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_PXP_AXI>, <&clks IMX6SL_CLK_DUMMY>; + clock-names = "pxp-axi", "disp-axi"; + status = "disabled"; }; epdc: epdc@20f4000 { - reg = <0x020f4000 0x4000>; + compatible = "fsl,imx6sl-epdc", "fsl,imx6dl-epdc"; + reg = <0x20f4000 0x4000>; interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_EPDC_AXI>, <&clks IMX6SL_CLK_EPDC_PIX>; + clock-names = "epdc_axi", "epdc_pix"; }; lcdif: lcdif@20f8000 { @@ -936,8 +997,10 @@ }; rngb: rngb@21b4000 { + compatible = "fsl,imx25-rngb"; reg = <0x021b4000 0x4000>; interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_DUMMY>; }; weim: weim@21b8000 { diff --git a/arch/arm/boot/dts/imx6sll-evk-btwifi.dts b/arch/arm/boot/dts/imx6sll-evk-btwifi.dts new file mode 100644 index 000000000000..f025c76cb4c1 --- /dev/null +++ b/arch/arm/boot/dts/imx6sll-evk-btwifi.dts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * NOTE: This DTS file is wrote for plugging in Murata 1MW M.2 + * into SD3 slot by using Murata uSD-to-M.2 Adapter. + * + * By default, OOB IRQ is not enabled since i.MX6SLL EVK board needs to rework. + * How to enable OOB IRQ ? + * HW rework: + * Install R127 on i.MX6SLL EVK board. + * SW change: add below pin for WL_HOST_WAKE + * pinctrl_wifi: wifigrp { + * fsl,pins = < + * ... + * MX6SLL_PAD_KEY_COL1__GPIO3_IO26 0x0b001 + * >; + * }; + * brcmf: bcrmf@1 { + * reg = <1>; + * compatible = "brcm,bcm4329-fmac"; + * interrupt-parent = <&gpio3>; + * interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + * interrupt-names = "host-wake"; + * }; + */ + +#include "imx6sll-evk.dts" + +/ { + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio3 27 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + usdhc1_pwrseq: usdhc1_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>; + }; +}; + +&iomuxc { + pinctrl_wifi: wifigrp { + fsl,pins = < + MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6SLL_PAD_SD3_CLK__SD3_CLK 0x130b9 + MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x170b9 + MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x170b9 + MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x170b9 + MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170b9 + + MX6SLL_PAD_KEY_COL0__GPIO3_IO24 0x17059 /* WL_REG_ON */ + MX6SLL_PAD_KEY_COL1__GPIO3_IO26 0x0b001 + >; + }; +}; + +&lcdif { + status = "disabled"; +}; + +®_sd3_vmmc { + regulator-always-on; +}; + +&uart5 { + resets = <&modem_reset>; + status = "okay"; +}; + +&usdhc3 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wifi>; + bus-width = <4>; + no-1-8-v; + non-removable; + mmc-pwrseq = <&usdhc1_pwrseq>; + pm-ignore-notify; + cap-power-off-card; + /delete-property/ cd-gpios; + /delete-property/ vmmc-supply; + /delete-property/ enable-sdio-wakeup; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&gpio3>; + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "host-wake"; + }; +}; diff --git a/arch/arm/boot/dts/imx6sll-evk-reva.dts b/arch/arm/boot/dts/imx6sll-evk-reva.dts new file mode 100644 index 000000000000..3704e8543f6f --- /dev/null +++ b/arch/arm/boot/dts/imx6sll-evk-reva.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2019 NXP. + * + */ + +/dts-v1/; + +#include "imx6sll-evk.dts" + +&usdhc2 { + compatible = "fsl,imx6sll-usdhc", "fsl,imx6sx-usdhc"; +}; + diff --git a/arch/arm/boot/dts/imx6sll-evk.dts b/arch/arm/boot/dts/imx6sll-evk.dts index 5ace9e6acf85..8755d69c499a 100644 --- a/arch/arm/boot/dts/imx6sll-evk.dts +++ b/arch/arm/boot/dts/imx6sll-evk.dts @@ -24,6 +24,19 @@ reg = <0x80000000 0x80000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + linux,cma-default; + }; + }; + backlight_display: backlight-display { compatible = "pwm-backlight"; pwms = <&pwm1 0 5000000>; @@ -32,6 +45,19 @@ status = "okay"; }; + battery: max8903@0 { + compatible = "fsl,max8903-charger"; + pinctrl-names = "default"; + dok_input = <&gpio4 13 1>; + uok_input = <&gpio4 13 1>; + chg_input = <&gpio4 15 1>; + flt_input = <&gpio4 14 1>; + fsl,dcm_always_high; + fsl,dc_valid; + fsl,adc_disable; + status = "okay"; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -44,6 +70,11 @@ }; }; + pxp_v4l2_out { + compatible = "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + reg_usb_otg1_vbus: regulator-otg1-vbus { compatible = "regulator-fixed"; pinctrl-names = "default"; @@ -106,9 +137,18 @@ regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; enable-active-high; }; + reg_sd2_vmmc: regulator-sd2-vmmc { + compatible = "regulator-fixed"; + regulator-name = "eMMC-VCCQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + reg_sd3_vmmc: regulator-sd3-vmmc { compatible = "regulator-fixed"; pinctrl-names = "default"; @@ -117,28 +157,53 @@ regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; gpio = <&gpio4 4 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; enable-active-high; }; - panel { - compatible = "sii,43wvf1g"; - backlight = <&backlight_display>; - dvdd-supply = <®_lcd_3v3>; - avdd-supply = <®_lcd_5v>; - - port { - panel_in: endpoint { - remote-endpoint = <&display_out>; - }; - }; + sound { + compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962"; + model = "wm8962-audio"; + audio-cpu = <&ssi2>; + audio-codec = <&codec>; + audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "Ext Spk", "SPKOUTL", + "Ext Spk", "SPKOUTR", + "AMIC", "MICBIAS", + "IN3R", "AMIC"; + mux-int-port = <2>; + mux-ext-port = <3>; + codec-master; + hp-det-gpios = <&gpio4 24 1>; }; }; +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux3>; + status = "okay"; +}; + &cpu0 { arm-supply = <&sw1a_reg>; soc-supply = <&sw1c_reg>; }; +&epdc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_epdc0>; + V3P3-supply = <&V3P3_reg>; + VCOM-supply = <&VCOM_reg>; + DISPLAY-supply = <&DISPLAY_reg>; + status = "okay"; +}; + +&gpc { + fsl,ldo-bypass = <1>; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -245,6 +310,98 @@ }; }; }; + + max17135: max17135@48 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_max17135>; + compatible = "maxim,max17135"; + reg = <0x48>; + status = "okay"; + + vneg_pwrup = <1>; + gvee_pwrup = <2>; + vpos_pwrup = <10>; + gvdd_pwrup = <12>; + gvdd_pwrdn = <1>; + vpos_pwrdn = <2>; + gvee_pwrdn = <8>; + vneg_pwrdn = <10>; + gpio_pmic_pwrgood = <&gpio2 13 0>; + gpio_pmic_vcom_ctrl = <&gpio2 3 0>; + gpio_pmic_wakeup = <&gpio2 14 0>; + gpio_pmic_v3p3 = <&gpio2 7 0>; + gpio_pmic_intr = <&gpio2 12 0>; + + regulators { + DISPLAY_reg: DISPLAY { + regulator-name = "DISPLAY"; + }; + + GVDD_reg: GVDD { + /* 20v */ + regulator-name = "GVDD"; + }; + + GVEE_reg: GVEE { + /* -22v */ + regulator-name = "GVEE"; + }; + + HVINN_reg: HVINN { + /* -22v */ + regulator-name = "HVINN"; + }; + + HVINP_reg: HVINP { + /* 20v */ + regulator-name = "HVINP"; + }; + + VCOM_reg: VCOM { + regulator-name = "VCOM"; + /* Real max value: -500000 */ + regulator-max-microvolt = <4325000>; + /* Real min value: -4325000 */ + regulator-min-microvolt = <500000>; + }; + + VNEG_reg: VNEG { + /* -15v */ + regulator-name = "VNEG"; + }; + + VPOS_reg: VPOS { + /* 15v */ + regulator-name = "VPOS"; + }; + + V3P3_reg: V3P3 { + regulator-name = "V3P3"; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + codec: wm8962@1a { + compatible = "wlf,wm8962"; + reg = <0x1a>; + clocks = <&clks IMX6SLL_CLK_EXTERN_AUDIO>; + DCVDD-supply = <&vgen3_reg>; + DBVDD-supply = <®_aud3v>; + AVDD-supply = <&vgen3_reg>; + CPVDD-supply = <&vgen3_reg>; + MICVDD-supply = <®_aud3v>; + PLLVDD-supply = <&vgen3_reg>; + SPKVDD1-supply = <®_aud4v>; + SPKVDD2-supply = <®_aud4v>; + amic-mono; + }; }; &lcdif { @@ -252,9 +409,30 @@ pinctrl-0 = <&pinctrl_lcd>; status = "okay"; - port { - display_out: endpoint { - remote-endpoint = <&panel_in>; + lcd-supply = <®_lcd_3v3>; + display = <&display0>; + + display0: display@0 { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hback-porch = <89>; + hfront-porch = <164>; + vback-porch = <23>; + vfront-porch = <10>; + hsync-len = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; }; }; }; @@ -265,6 +443,10 @@ status = "okay"; }; +&pxp { + status = "okay"; +}; + &snvs_poweroff { status = "okay"; }; @@ -273,12 +455,26 @@ status = "okay"; }; +&ssi2 { + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + fsl,uart-has-rtscts; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart5dte>; */ + status = "disabled"; +}; + &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc1>; @@ -292,6 +488,17 @@ status = "okay"; }; +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + bus-width = <8>; + non-removable; + vqmmc-supply = <®_sd2_vmmc>; + status = "okay"; +}; + &usbotg1 { vbus-supply = <®_usb_otg1_vbus>; pinctrl-names = "default"; @@ -329,6 +536,69 @@ }; &iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX6SLL_PAD_GPIO4_IO24__GPIO4_IO24 0x17059 /* HP DETECT */ + /* CHG_FLT, CHG_UOK/DOK, CHG_STATUS */ + MX6SLL_PAD_ECSPI2_MISO__GPIO4_IO14 0x17000 + MX6SLL_PAD_ECSPI2_MOSI__GPIO4_IO13 0x17000 + MX6SLL_PAD_ECSPI2_SS0__GPIO4_IO15 0x17000 + >; + }; + + pinctrl_audmux3: audmux3grp { + fsl,pins = < + MX6SLL_PAD_AUD_TXC__AUD3_TXC 0x4130b0 + MX6SLL_PAD_AUD_TXFS__AUD3_TXFS 0x4130b0 + MX6SLL_PAD_AUD_TXD__AUD3_TXD 0x4110b0 + MX6SLL_PAD_AUD_RXD__AUD3_RXD 0x4130b0 + MX6SLL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 + >; + }; + + pinctrl_epdc0: epdcgrp0 { + fsl,pins = < + MX6SLL_PAD_EPDC_DATA00__EPDC_DATA00 0x100b1 + MX6SLL_PAD_EPDC_DATA01__EPDC_DATA01 0x100b1 + MX6SLL_PAD_EPDC_DATA02__EPDC_DATA02 0x100b1 + MX6SLL_PAD_EPDC_DATA03__EPDC_DATA03 0x100b1 + MX6SLL_PAD_EPDC_DATA04__EPDC_DATA04 0x100b1 + MX6SLL_PAD_EPDC_DATA05__EPDC_DATA05 0x100b1 + MX6SLL_PAD_EPDC_DATA06__EPDC_DATA06 0x100b1 + MX6SLL_PAD_EPDC_DATA07__EPDC_DATA07 0x100b1 + MX6SLL_PAD_EPDC_DATA08__EPDC_DATA08 0x100b1 + MX6SLL_PAD_EPDC_DATA09__EPDC_DATA09 0x100b1 + MX6SLL_PAD_EPDC_DATA10__EPDC_DATA10 0x100b1 + MX6SLL_PAD_EPDC_DATA11__EPDC_DATA11 0x100b1 + MX6SLL_PAD_EPDC_DATA12__EPDC_DATA12 0x100b1 + MX6SLL_PAD_EPDC_DATA13__EPDC_DATA13 0x100b1 + MX6SLL_PAD_EPDC_DATA14__EPDC_DATA14 0x100b1 + MX6SLL_PAD_EPDC_DATA15__EPDC_DATA15 0x100b1 + MX6SLL_PAD_EPDC_SDCLK__EPDC_SDCLK_P 0x100b1 + MX6SLL_PAD_EPDC_SDLE__EPDC_SDLE 0x100b1 + MX6SLL_PAD_EPDC_SDOE__EPDC_SDOE 0x100b1 + MX6SLL_PAD_EPDC_SDSHR__EPDC_SDSHR 0x100b1 + MX6SLL_PAD_EPDC_SDCE0__EPDC_SDCE0 0x100b1 + MX6SLL_PAD_EPDC_GDCLK__EPDC_GDCLK 0x100b1 + MX6SLL_PAD_EPDC_GDOE__EPDC_GDOE 0x100b1 + MX6SLL_PAD_EPDC_GDRL__EPDC_GDRL 0x100b1 + MX6SLL_PAD_EPDC_GDSP__EPDC_GDSP 0x100b1 + >; + }; + + pinctrl_max17135: max17135grp-1 { + fsl,pins = < + MX6SLL_PAD_EPDC_PWR_STAT__GPIO2_IO13 0x80000000 /* pwrgood */ + MX6SLL_PAD_EPDC_VCOM0__GPIO2_IO03 0x80000000 /* vcom_ctrl */ + MX6SLL_PAD_EPDC_PWR_WAKE__GPIO2_IO14 0x80000000 /* wakeup */ + MX6SLL_PAD_EPDC_PWR_CTRL0__GPIO2_IO07 0x80000000 /* v3p3 */ + MX6SLL_PAD_EPDC_PWR_IRQ__GPIO2_IO12 0x80000000 /* pwr int */ + >; + }; + pinctrl_reg_sd3_vmmc: sd3vmmcgrp { fsl,pins = < MX6SLL_PAD_KEY_COL6__GPIO4_IO04 0x17059 @@ -366,6 +636,25 @@ >; }; + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6SLL_PAD_KEY_ROW1__GPIO3_IO27 0x1b0b1 /* bt reg on */ + MX6SLL_PAD_ECSPI1_MOSI__UART5_DCE_TX 0x1b0b1 + MX6SLL_PAD_ECSPI1_SCLK__UART5_DCE_RX 0x1b0b1 + MX6SLL_PAD_ECSPI1_SS0__UART5_DCE_CTS 0x1b0b1 + MX6SLL_PAD_ECSPI1_MISO__UART5_DCE_RTS 0x1b0b1 + >; + }; + + pinctrl_uart5dte: uart5dtegrp { + fsl,pins = < + MX6SLL_PAD_ECSPI1_MOSI__UART5_DTE_RX 0x1b0b1 + MX6SLL_PAD_ECSPI1_SCLK__UART5_DTE_TX 0x1b0b1 + MX6SLL_PAD_ECSPI1_SS0__UART5_DTE_RTS 0x1b0b1 + MX6SLL_PAD_ECSPI1_MISO__UART5_DTE_CTS 0x1b0b1 + >; + }; + pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX6SLL_PAD_SD1_CMD__SD1_CMD 0x17059 @@ -399,6 +688,54 @@ >; }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6SLL_PAD_SD2_CLK__SD2_CLK 0x13059 + MX6SLL_PAD_SD2_DATA0__SD2_DATA0 0x17059 + MX6SLL_PAD_SD2_DATA1__SD2_DATA1 0x17059 + MX6SLL_PAD_SD2_DATA2__SD2_DATA2 0x17059 + MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x17059 + MX6SLL_PAD_SD2_DATA4__SD2_DATA4 0x17059 + MX6SLL_PAD_SD2_DATA5__SD2_DATA5 0x17059 + MX6SLL_PAD_SD2_DATA6__SD2_DATA6 0x17059 + MX6SLL_PAD_SD2_DATA7__SD2_DATA7 0x17059 + MX6SLL_PAD_GPIO4_IO21__SD2_STROBE 0x413059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2grp_100mhz { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130b9 + MX6SLL_PAD_SD2_DATA0__SD2_DATA0 0x170b9 + MX6SLL_PAD_SD2_DATA1__SD2_DATA1 0x170b9 + MX6SLL_PAD_SD2_DATA2__SD2_DATA2 0x170b9 + MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x170b9 + MX6SLL_PAD_SD2_DATA4__SD2_DATA4 0x170b9 + MX6SLL_PAD_SD2_DATA5__SD2_DATA5 0x170b9 + MX6SLL_PAD_SD2_DATA6__SD2_DATA6 0x170b9 + MX6SLL_PAD_SD2_DATA7__SD2_DATA7 0x170b9 + MX6SLL_PAD_GPIO4_IO21__SD2_STROBE 0x4130b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp_200mhz { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130f9 + MX6SLL_PAD_SD2_DATA0__SD2_DATA0 0x170f9 + MX6SLL_PAD_SD2_DATA1__SD2_DATA1 0x170f9 + MX6SLL_PAD_SD2_DATA2__SD2_DATA2 0x170f9 + MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x170f9 + MX6SLL_PAD_SD2_DATA4__SD2_DATA4 0x170f9 + MX6SLL_PAD_SD2_DATA5__SD2_DATA5 0x170f9 + MX6SLL_PAD_SD2_DATA6__SD2_DATA6 0x170f9 + MX6SLL_PAD_SD2_DATA7__SD2_DATA7 0x170f9 + MX6SLL_PAD_GPIO4_IO21__SD2_STROBE 0x4130f9 + >; + }; + pinctrl_usbotg1: usbotg1grp { fsl,pins = < MX6SLL_PAD_EPDC_PWR_COM__USB_OTG1_ID 0x17059 @@ -448,6 +785,13 @@ >; }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6SLL_PAD_AUD_RXFS__I2C3_SCL 0x4041b8b1 + MX6SLL_PAD_AUD_RXC__I2C3_SDA 0x4041b8b1 + >; + }; + pinctrl_lcd: lcdgrp { fsl,pins = < MX6SLL_PAD_LCD_DATA00__LCD_DATA00 0x79 diff --git a/arch/arm/boot/dts/imx6sll.dtsi b/arch/arm/boot/dts/imx6sll.dtsi index 13c7ba7fa6bc..075b27fb3c4d 100644 --- a/arch/arm/boot/dts/imx6sll.dtsi +++ b/arch/arm/boot/dts/imx6sll.dtsi @@ -65,13 +65,18 @@ >; clock-latency = <61036>; /* two CLK32 periods */ #cooling-cells = <2>; + fsl,low-power-run; clocks = <&clks IMX6SLL_CLK_ARM>, <&clks IMX6SLL_CLK_PLL2_PFD2>, <&clks IMX6SLL_CLK_STEP>, <&clks IMX6SLL_CLK_PLL1_SW>, - <&clks IMX6SLL_CLK_PLL1_SYS>; + <&clks IMX6SLL_CLK_PLL1_SYS>, + <&clks IMX6SLL_CLK_PLL1>, + <&clks IMX6SLL_PLL1_BYPASS>, + <&clks IMX6SLL_PLL1_BYPASS_SRC>; clock-names = "arm", "pll2_pfd2_396m", "step", - "pll1_sw", "pll1_sys"; + "pll1_sw", "pll1_sys", "pll1", "pll1_bypass", + "pll1_bypass_src"; }; }; @@ -120,9 +125,45 @@ interrupt-parent = <&gpc>; ranges; - ocram: sram@900000 { + busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6SLL_CLK_PLL2_PFD2>, <&clks IMX6SLL_CLK_PLL2_198M>, + <&clks IMX6SLL_CLK_PLL2_BUS>, <&clks IMX6SLL_CLK_ARM>, + <&clks IMX6SLL_CLK_PLL3_USB_OTG>, <&clks IMX6SLL_CLK_PERIPH>, + <&clks IMX6SLL_CLK_PERIPH_PRE>, <&clks IMX6SLL_CLK_PERIPH_CLK2>, + <&clks IMX6SLL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6SLL_CLK_OSC>, + <&clks IMX6SLL_CLK_AHB>, <&clks IMX6SLL_CLK_AXI_PODF>, + <&clks IMX6SLL_CLK_PERIPH2>, <&clks IMX6SLL_CLK_PERIPH2_PRE>, + <&clks IMX6SLL_CLK_PERIPH2_CLK2>, <&clks IMX6SLL_CLK_PERIPH2_CLK2_SEL>, + <&clks IMX6SLL_CLK_STEP>, <&clks IMX6SLL_CLK_MMDC_P0_FAST>, <&clks IMX6SLL_PLL1_BYPASS_SRC>, + <&clks IMX6SLL_PLL1_BYPASS>, <&clks IMX6SLL_CLK_PLL1_SYS>, <&clks IMX6SLL_CLK_PLL1_SW>, + <&clks IMX6SLL_CLK_PLL1>; + clock-names = "pll2_pfd2_396m", "pll2_198m", "pll2_bus", "arm", "pll3_usb_otg", + "periph", "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", + "ahb", "ocram", "periph2", "periph2_pre", "periph2_clk2", "periph2_clk2_sel", + "step", "mmdc", "pll1_bypass_src", "pll1_bypass", "pll1_sys", "pll1_sw", "pll1"; + fsl,max_ddr_freq = <400000000>; + }; + + ocrams: sram@900000 { + compatible = "fsl,lpm-sram"; + reg = <0x900000 0x4000>; + }; + + ocrams_ddr: sram@904000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x904000 0x1000>; + }; + + ocram: sram@905000 { compatible = "mmio-sram"; - reg = <0x00900000 0x20000>; + reg = <0x905000 0x1B000>; + }; + + ocram_optee: sram@918000 { + compatible = "fsl,optee-lpm-sram"; + reg = <0x918000 0x8000>; + overw_reg = <&ocram 0x905000 0x13000>; }; intc: interrupt-controller@a01000 { @@ -183,7 +224,7 @@ }; ecspi1: spi@2008000 { - compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi"; + compatible ="fsl,imx6ul-ecspi"; reg = <0x02008000 0x4000>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; @@ -195,7 +236,7 @@ }; ecspi2: spi@200c000 { - compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi"; + compatible = "fsl,imx6ul-ecspi"; reg = <0x0200c000 0x4000>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; @@ -207,7 +248,7 @@ }; ecspi3: spi@2010000 { - compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi"; + compatible = "fsl,imx6ul-ecspi"; reg = <0x02010000 0x4000>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; @@ -219,7 +260,7 @@ }; ecspi4: spi@2014000 { - compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi"; + compatible = "fsl,imx6ul-ecspi"; reg = <0x02014000 0x4000>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; @@ -596,6 +637,7 @@ #interrupt-cells = <3>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&intc>; + fsl,mf-mix-wakeup-irq = <0x7c00000 0x7d00 0x0 0x1400640>; }; iomuxc: pinctrl@20e0000 { @@ -621,7 +663,7 @@ }; sdma: dma-controller@20ec000 { - compatible = "fsl,imx6sll-sdma", "fsl,imx6ul-sdma"; + compatible = "fsl,imx6ul-sdma", "fsl,imx35-sdma"; reg = <0x020ec000 0x4000>; interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SLL_CLK_IPG>, @@ -632,6 +674,26 @@ fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; }; + pxp: pxp@20f0000 { + compatible = "fsl,imx6ull-pxp-dma", "fsl,imx7d-pxp-dma"; + reg = <0x20f0000 0x4000>; + interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SLL_CLK_DUMMY>, + <&clks IMX6SLL_CLK_PXP>; + clock-names = "pxp_ipg", "pxp_axi"; + status = "disabled"; + }; + + epdc: epdc@20f4000 { + compatible = "fsl,imx6sll-epdc", "fsl,imx7d-epdc"; + reg = <0x20f4000 0x4000>; + interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SLL_CLK_EPDC_AXI>, <&clks IMX6SLL_CLK_EPDC_PIX>; + clock-names = "epdc_axi", "epdc_pix"; + status = "disabled"; + }; + lcdif: lcd-controller@20f8000 { compatible = "fsl,imx6sll-lcdif", "fsl,imx28-lcdif"; reg = <0x020f8000 0x4000>; @@ -698,7 +760,7 @@ }; usdhc1: mmc@2190000 { - compatible = "fsl,imx6sll-usdhc", "fsl,imx6sx-usdhc"; + compatible = "fsl,imx6sll-usdhc", "fsl,imx7d-usdhc"; reg = <0x02190000 0x4000>; interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SLL_CLK_USDHC1>, @@ -712,7 +774,7 @@ }; usdhc2: mmc@2194000 { - compatible = "fsl,imx6sll-usdhc", "fsl,imx6sx-usdhc"; + compatible = "fsl,imx6sll-usdhc", "fsl,imx7d-usdhc"; reg = <0x02194000 0x4000>; interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SLL_CLK_USDHC2>, @@ -726,7 +788,7 @@ }; usdhc3: mmc@2198000 { - compatible = "fsl,imx6sll-usdhc", "fsl,imx6sx-usdhc"; + compatible = "fsl,imx6sll-usdhc", "fsl,imx7d-usdhc"; reg = <0x02198000 0x4000>; interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SLL_CLK_USDHC3>, @@ -775,6 +837,13 @@ clocks = <&clks IMX6SLL_CLK_MMDC_P0_IPG>; }; + rngb: rng@21b4000 { + compatible = "fsl,imx25-rngb"; + reg = <0x021b4000 0x4000>; + interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SLL_CLK_DUMMY>; + }; + ocotp: ocotp-ctrl@21bc000 { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/imx6sx-pinfunc.h b/arch/arm/boot/dts/imx6sx-pinfunc.h index aa194a2fdd53..df9a6c5b5ada 100644 --- a/arch/arm/boot/dts/imx6sx-pinfunc.h +++ b/arch/arm/boot/dts/imx6sx-pinfunc.h @@ -66,6 +66,7 @@ #define MX6SX_PAD_GPIO1_IO06__ENET2_MDC 0x002C 0x0374 0x0000 0x2 0x0 #define MX6SX_PAD_GPIO1_IO06__CSI1_MCLK 0x002C 0x0374 0x0000 0x3 0x0 #define MX6SX_PAD_GPIO1_IO06__UART1_RTS_B 0x002C 0x0374 0x082C 0x4 0x0 +#define MX6SX_PAD_GPIO1_IO06__UART1_CTS_B 0x002C 0x0374 0x0000 0x4 0x0 #define MX6SX_PAD_GPIO1_IO06__GPIO1_IO_6 0x002C 0x0374 0x0000 0x5 0x0 #define MX6SX_PAD_GPIO1_IO06__SRC_ANY_PU_RESET 0x002C 0x0374 0x0000 0x6 0x0 #define MX6SX_PAD_GPIO1_IO06__OCOTP_CTRL_WRAPPER_FUSE_LATCHED 0x002C 0x0374 0x0000 0x7 0x0 @@ -75,6 +76,7 @@ #define MX6SX_PAD_GPIO1_IO07__ENET2_MDIO 0x0030 0x0378 0x0770 0x2 0x0 #define MX6SX_PAD_GPIO1_IO07__AUDMUX_MCLK 0x0030 0x0378 0x0000 0x3 0x0 #define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B 0x0030 0x0378 0x0000 0x4 0x0 +#define MX6SX_PAD_GPIO1_IO07__UART1_RTS_B 0x0030 0x0378 0x082C 0x4 0x1 #define MX6SX_PAD_GPIO1_IO07__GPIO1_IO_7 0x0030 0x0378 0x0000 0x5 0x0 #define MX6SX_PAD_GPIO1_IO07__SRC_EARLY_RESET 0x0030 0x0378 0x0000 0x6 0x0 #define MX6SX_PAD_GPIO1_IO07__DCIC2_OUT 0x0030 0x0378 0x0000 0x7 0x0 @@ -84,6 +86,7 @@ #define MX6SX_PAD_GPIO1_IO08__SDMA_EXT_EVENT_0 0x0034 0x037C 0x081C 0x2 0x0 #define MX6SX_PAD_GPIO1_IO08__CCM_PMIC_RDY 0x0034 0x037C 0x069C 0x3 0x1 #define MX6SX_PAD_GPIO1_IO08__UART2_RTS_B 0x0034 0x037C 0x0834 0x4 0x0 +#define MX6SX_PAD_GPIO1_IO08__UART2_CTS_B 0x0034 0x037C 0x0000 0x4 0x0 #define MX6SX_PAD_GPIO1_IO08__GPIO1_IO_8 0x0034 0x037C 0x0000 0x5 0x0 #define MX6SX_PAD_GPIO1_IO08__SRC_SYSTEM_RESET 0x0034 0x037C 0x0000 0x6 0x0 #define MX6SX_PAD_GPIO1_IO08__DCIC1_OUT 0x0034 0x037C 0x0000 0x7 0x0 @@ -93,6 +96,7 @@ #define MX6SX_PAD_GPIO1_IO09__SDMA_EXT_EVENT_1 0x0038 0x0380 0x0820 0x2 0x0 #define MX6SX_PAD_GPIO1_IO09__CCM_OUT0 0x0038 0x0380 0x0000 0x3 0x0 #define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B 0x0038 0x0380 0x0000 0x4 0x0 +#define MX6SX_PAD_GPIO1_IO09__UART2_RTS_B 0x0038 0x0380 0x0834 0x4 0x1 #define MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x0038 0x0380 0x0000 0x5 0x0 #define MX6SX_PAD_GPIO1_IO09__SRC_INT_BOOT 0x0038 0x0380 0x0000 0x6 0x0 #define MX6SX_PAD_GPIO1_IO09__OBSERVE_MUX_OUT_4 0x0038 0x0380 0x0000 0x7 0x0 @@ -200,6 +204,7 @@ #define MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x0064 0x03AC 0x07C0 0x2 0x2 #define MX6SX_PAD_CSI_DATA06__KPP_COL_7 0x0064 0x03AC 0x07D0 0x3 0x0 #define MX6SX_PAD_CSI_DATA06__UART6_RTS_B 0x0064 0x03AC 0x0854 0x4 0x0 +#define MX6SX_PAD_CSI_DATA06__UART6_CTS_B 0x0064 0x03AC 0x0000 0x4 0x0 #define MX6SX_PAD_CSI_DATA06__GPIO1_IO_20 0x0064 0x03AC 0x0000 0x5 0x0 #define MX6SX_PAD_CSI_DATA06__WEIM_DATA_17 0x0064 0x03AC 0x0000 0x6 0x0 #define MX6SX_PAD_CSI_DATA06__DCIC2_OUT 0x0064 0x03AC 0x0000 0x7 0x0 @@ -210,6 +215,7 @@ #define MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x0068 0x03B0 0x07C4 0x2 0x2 #define MX6SX_PAD_CSI_DATA07__KPP_ROW_7 0x0068 0x03B0 0x07DC 0x3 0x0 #define MX6SX_PAD_CSI_DATA07__UART6_CTS_B 0x0068 0x03B0 0x0000 0x4 0x0 +#define MX6SX_PAD_CSI_DATA07__UART6_RTS_B 0x0068 0x03B0 0x0854 0x4 0x1 #define MX6SX_PAD_CSI_DATA07__GPIO1_IO_21 0x0068 0x03B0 0x0000 0x5 0x0 #define MX6SX_PAD_CSI_DATA07__WEIM_DATA_16 0x0068 0x03B0 0x0000 0x6 0x0 #define MX6SX_PAD_CSI_DATA07__DCIC1_OUT 0x0068 0x03B0 0x0000 0x7 0x0 @@ -219,6 +225,7 @@ #define MX6SX_PAD_CSI_HSYNC__ESAI_TX0 0x006C 0x03B4 0x0790 0x1 0x1 #define MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x006C 0x03B4 0x0678 0x2 0x1 #define MX6SX_PAD_CSI_HSYNC__UART4_RTS_B 0x006C 0x03B4 0x0844 0x3 0x2 +#define MX6SX_PAD_CSI_HSYNC__UART4_CTS_B 0x006C 0x03B4 0x0000 0x3 0x0 #define MX6SX_PAD_CSI_HSYNC__MQS_LEFT 0x006C 0x03B4 0x0000 0x4 0x0 #define MX6SX_PAD_CSI_HSYNC__GPIO1_IO_22 0x006C 0x03B4 0x0000 0x5 0x0 #define MX6SX_PAD_CSI_HSYNC__WEIM_DATA_25 0x006C 0x03B4 0x0000 0x6 0x0 @@ -251,6 +258,7 @@ #define MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x0078 0x03C0 0x07A4 0x1 0x1 #define MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x0078 0x03C0 0x0674 0x2 0x1 #define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B 0x0078 0x03C0 0x0000 0x3 0x0 +#define MX6SX_PAD_CSI_VSYNC__UART4_RTS_B 0x0078 0x03C0 0x0844 0x3 0x3 #define MX6SX_PAD_CSI_VSYNC__MQS_RIGHT 0x0078 0x03C0 0x0000 0x4 0x0 #define MX6SX_PAD_CSI_VSYNC__GPIO1_IO_25 0x0078 0x03C0 0x0000 0x5 0x0 #define MX6SX_PAD_CSI_VSYNC__WEIM_DATA_24 0x0078 0x03C0 0x0000 0x6 0x0 @@ -353,6 +361,7 @@ #define MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x009C 0x03E4 0x0000 0x1 0x0 #define MX6SX_PAD_ENET2_RX_CLK__I2C3_SCL 0x009C 0x03E4 0x07B8 0x2 0x1 #define MX6SX_PAD_ENET2_RX_CLK__UART1_RTS_B 0x009C 0x03E4 0x082C 0x3 0x2 +#define MX6SX_PAD_ENET2_RX_CLK__UART1_CTS_B 0x009C 0x03E4 0x0000 0x3 0x0 #define MX6SX_PAD_ENET2_RX_CLK__MLB_DATA 0x009C 0x03E4 0x07EC 0x4 0x1 #define MX6SX_PAD_ENET2_RX_CLK__GPIO2_IO_8 0x009C 0x03E4 0x0000 0x5 0x0 #define MX6SX_PAD_ENET2_RX_CLK__USB_OTG2_OC 0x009C 0x03E4 0x085C 0x6 0x1 @@ -363,6 +372,7 @@ #define MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x00A0 0x03E8 0x076C 0x1 0x1 #define MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA 0x00A0 0x03E8 0x07BC 0x2 0x1 #define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B 0x00A0 0x03E8 0x0000 0x3 0x0 +#define MX6SX_PAD_ENET2_TX_CLK__UART1_RTS_B 0x00A0 0x03E8 0x082C 0x3 0x3 #define MX6SX_PAD_ENET2_TX_CLK__MLB_CLK 0x00A0 0x03E8 0x07E8 0x4 0x1 #define MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9 0x00A0 0x03E8 0x0000 0x5 0x0 #define MX6SX_PAD_ENET2_TX_CLK__USB_OTG2_PWR 0x00A0 0x03E8 0x0000 0x6 0x0 @@ -372,6 +382,7 @@ #define MX6SX_PAD_KEY_COL0__KPP_COL_0 0x00A4 0x03EC 0x0000 0x0 0x0 #define MX6SX_PAD_KEY_COL0__USDHC3_CD_B 0x00A4 0x03EC 0x0000 0x1 0x0 #define MX6SX_PAD_KEY_COL0__UART6_RTS_B 0x00A4 0x03EC 0x0854 0x2 0x2 +#define MX6SX_PAD_KEY_COL0__UART6_CTS_B 0x00A4 0x03EC 0x0000 0x2 0x0 #define MX6SX_PAD_KEY_COL0__ECSPI1_SCLK 0x00A4 0x03EC 0x0710 0x3 0x0 #define MX6SX_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x00A4 0x03EC 0x066C 0x4 0x0 #define MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x00A4 0x03EC 0x0000 0x5 0x0 @@ -390,6 +401,7 @@ #define MX6SX_PAD_KEY_COL2__KPP_COL_2 0x00AC 0x03F4 0x0000 0x0 0x0 #define MX6SX_PAD_KEY_COL2__USDHC4_CD_B 0x00AC 0x03F4 0x0874 0x1 0x1 #define MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x00AC 0x03F4 0x084C 0x2 0x2 +#define MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x00AC 0x03F4 0x0000 0x2 0x0 #define MX6SX_PAD_KEY_COL2__CAN1_TX 0x00AC 0x03F4 0x0000 0x3 0x0 #define MX6SX_PAD_KEY_COL2__CANFD_TX1 0x00AC 0x03F4 0x0000 0x4 0x0 #define MX6SX_PAD_KEY_COL2__GPIO2_IO_12 0x00AC 0x03F4 0x0000 0x5 0x0 @@ -415,6 +427,7 @@ #define MX6SX_PAD_KEY_ROW0__KPP_ROW_0 0x00B8 0x0400 0x0000 0x0 0x0 #define MX6SX_PAD_KEY_ROW0__USDHC3_WP 0x00B8 0x0400 0x0000 0x1 0x0 #define MX6SX_PAD_KEY_ROW0__UART6_CTS_B 0x00B8 0x0400 0x0000 0x2 0x0 +#define MX6SX_PAD_KEY_ROW0__UART6_RTS_B 0x00B8 0x0400 0x0854 0x2 0x3 #define MX6SX_PAD_KEY_ROW0__ECSPI1_MOSI 0x00B8 0x0400 0x0718 0x3 0x0 #define MX6SX_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x00B8 0x0400 0x0660 0x4 0x0 #define MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x00B8 0x0400 0x0000 0x5 0x0 @@ -434,6 +447,7 @@ #define MX6SX_PAD_KEY_ROW2__KPP_ROW_2 0x00C0 0x0408 0x0000 0x0 0x0 #define MX6SX_PAD_KEY_ROW2__USDHC4_WP 0x00C0 0x0408 0x0878 0x1 0x1 #define MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x00C0 0x0408 0x0000 0x2 0x0 +#define MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x00C0 0x0408 0x084C 0x2 0x3 #define MX6SX_PAD_KEY_ROW2__CAN1_RX 0x00C0 0x0408 0x068C 0x3 0x1 #define MX6SX_PAD_KEY_ROW2__CANFD_RX1 0x00C0 0x0408 0x0694 0x4 0x1 #define MX6SX_PAD_KEY_ROW2__GPIO2_IO_17 0x00C0 0x0408 0x0000 0x5 0x0 @@ -816,6 +830,7 @@ #define MX6SX_PAD_NAND_DATA04__USDHC2_DATA4 0x0160 0x04A8 0x0000 0x1 0x0 #define MX6SX_PAD_NAND_DATA04__QSPI2_B_SS1_B 0x0160 0x04A8 0x0000 0x2 0x0 #define MX6SX_PAD_NAND_DATA04__UART3_RTS_B 0x0160 0x04A8 0x083C 0x3 0x0 +#define MX6SX_PAD_NAND_DATA04__UART3_CTS_B 0x0160 0x04A8 0x0000 0x3 0x0 #define MX6SX_PAD_NAND_DATA04__AUDMUX_AUD4_RXFS 0x0160 0x04A8 0x0650 0x4 0x0 #define MX6SX_PAD_NAND_DATA04__GPIO4_IO_8 0x0160 0x04A8 0x0000 0x5 0x0 #define MX6SX_PAD_NAND_DATA04__WEIM_AD_4 0x0160 0x04A8 0x0000 0x6 0x0 @@ -826,6 +841,7 @@ #define MX6SX_PAD_NAND_DATA05__USDHC2_DATA5 0x0164 0x04AC 0x0000 0x1 0x0 #define MX6SX_PAD_NAND_DATA05__QSPI2_B_DQS 0x0164 0x04AC 0x0000 0x2 0x0 #define MX6SX_PAD_NAND_DATA05__UART3_CTS_B 0x0164 0x04AC 0x0000 0x3 0x0 +#define MX6SX_PAD_NAND_DATA05__UART3_RTS_B 0x0164 0x04AC 0x083C 0x3 0x1 #define MX6SX_PAD_NAND_DATA05__AUDMUX_AUD4_RXC 0x0164 0x04AC 0x064C 0x4 0x0 #define MX6SX_PAD_NAND_DATA05__GPIO4_IO_9 0x0164 0x04AC 0x0000 0x5 0x0 #define MX6SX_PAD_NAND_DATA05__WEIM_AD_5 0x0164 0x04AC 0x0000 0x6 0x0 @@ -968,6 +984,7 @@ #define MX6SX_PAD_QSPI1A_SS1_B__SDMA_DEBUG_PC_3 0x019C 0x04E4 0x0000 0x9 0x0 #define MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0 0x01A0 0x04E8 0x0000 0x0 0x0 #define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B 0x01A0 0x04E8 0x0000 0x1 0x0 +#define MX6SX_PAD_QSPI1B_DATA0__UART3_RTS_B 0x01A0 0x04E8 0x083C 0x1 0x4 #define MX6SX_PAD_QSPI1B_DATA0__ECSPI3_MOSI 0x01A0 0x04E8 0x0738 0x2 0x1 #define MX6SX_PAD_QSPI1B_DATA0__ESAI_RX_FS 0x01A0 0x04E8 0x0778 0x3 0x2 #define MX6SX_PAD_QSPI1B_DATA0__CSI1_DATA_22 0x01A0 0x04E8 0x06F4 0x4 0x1 @@ -976,6 +993,7 @@ #define MX6SX_PAD_QSPI1B_DATA0__SIM_M_HADDR_9 0x01A0 0x04E8 0x0000 0x7 0x0 #define MX6SX_PAD_QSPI1B_DATA1__QSPI1_B_DATA_1 0x01A4 0x04EC 0x0000 0x0 0x0 #define MX6SX_PAD_QSPI1B_DATA1__UART3_RTS_B 0x01A4 0x04EC 0x083C 0x1 0x5 +#define MX6SX_PAD_QSPI1B_DATA1__UART3_CTS_B 0x01A4 0x04EC 0x0000 0x1 0x0 #define MX6SX_PAD_QSPI1B_DATA1__ECSPI3_MISO 0x01A4 0x04EC 0x0734 0x2 0x1 #define MX6SX_PAD_QSPI1B_DATA1__ESAI_RX_CLK 0x01A4 0x04EC 0x0788 0x3 0x2 #define MX6SX_PAD_QSPI1B_DATA1__CSI1_DATA_21 0x01A4 0x04EC 0x06F0 0x4 0x1 @@ -1247,6 +1265,7 @@ #define MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x0230 0x0578 0x0000 0x2 0x0 #define MX6SX_PAD_SD1_DATA2__GPT_COMPARE2 0x0230 0x0578 0x0000 0x3 0x0 #define MX6SX_PAD_SD1_DATA2__UART2_CTS_B 0x0230 0x0578 0x0000 0x4 0x0 +#define MX6SX_PAD_SD1_DATA2__UART2_RTS_B 0x0230 0x0578 0x0834 0x4 0x2 #define MX6SX_PAD_SD1_DATA2__GPIO6_IO_4 0x0230 0x0578 0x0000 0x5 0x0 #define MX6SX_PAD_SD1_DATA2__ECSPI4_RDY 0x0230 0x0578 0x0000 0x6 0x0 #define MX6SX_PAD_SD1_DATA2__CCM_OUT0 0x0230 0x0578 0x0000 0x7 0x0 @@ -1256,6 +1275,7 @@ #define MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_RXD 0x0234 0x057C 0x065C 0x2 0x2 #define MX6SX_PAD_SD1_DATA3__GPT_COMPARE3 0x0234 0x057C 0x0000 0x3 0x0 #define MX6SX_PAD_SD1_DATA3__UART2_RTS_B 0x0234 0x057C 0x0834 0x4 0x3 +#define MX6SX_PAD_SD1_DATA3__UART2_CTS_B 0x0234 0x057C 0x0000 0x4 0x0 #define MX6SX_PAD_SD1_DATA3__GPIO6_IO_5 0x0234 0x057C 0x0000 0x5 0x0 #define MX6SX_PAD_SD1_DATA3__ECSPI4_SS1 0x0234 0x057C 0x0000 0x6 0x0 #define MX6SX_PAD_SD1_DATA3__CCM_PMIC_RDY 0x0234 0x057C 0x069C 0x7 0x2 @@ -1326,6 +1346,7 @@ #define MX6SX_PAD_SD2_DATA3__MMDC_DEBUG_31 0x024C 0x0594 0x0000 0x9 0x0 #define MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x0250 0x0598 0x0000 0x0 0x0 #define MX6SX_PAD_SD3_CLK__UART4_CTS_B 0x0250 0x0598 0x0000 0x1 0x0 +#define MX6SX_PAD_SD3_CLK__UART4_RTS_B 0x0250 0x0598 0x0844 0x1 0x0 #define MX6SX_PAD_SD3_CLK__ECSPI4_SCLK 0x0250 0x0598 0x0740 0x2 0x0 #define MX6SX_PAD_SD3_CLK__AUDMUX_AUD6_RXFS 0x0250 0x0598 0x0680 0x3 0x0 #define MX6SX_PAD_SD3_CLK__LCDIF2_VSYNC 0x0250 0x0598 0x0000 0x4 0x0 @@ -1365,6 +1386,7 @@ #define MX6SX_PAD_SD3_DATA1__SDMA_DEBUG_EVT_CHN_LINES_1 0x025C 0x05A4 0x0000 0x9 0x0 #define MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x0260 0x05A8 0x0000 0x0 0x0 #define MX6SX_PAD_SD3_DATA2__UART4_RTS_B 0x0260 0x05A8 0x0844 0x1 0x1 +#define MX6SX_PAD_SD3_DATA2__UART4_CTS_B 0x0260 0x05A8 0x0000 0x1 0x0 #define MX6SX_PAD_SD3_DATA2__ECSPI4_SS0 0x0260 0x05A8 0x074C 0x2 0x0 #define MX6SX_PAD_SD3_DATA2__AUDMUX_AUD6_TXFS 0x0260 0x05A8 0x0688 0x3 0x0 #define MX6SX_PAD_SD3_DATA2__LCDIF2_CLK 0x0260 0x05A8 0x0000 0x4 0x0 @@ -1410,6 +1432,7 @@ #define MX6SX_PAD_SD3_DATA6__CAN2_TX 0x0270 0x05B8 0x0000 0x1 0x0 #define MX6SX_PAD_SD3_DATA6__CANFD_TX2 0x0270 0x05B8 0x0000 0x2 0x0 #define MX6SX_PAD_SD3_DATA6__UART3_RTS_B 0x0270 0x05B8 0x083C 0x3 0x2 +#define MX6SX_PAD_SD3_DATA6__UART3_CTS_B 0x0270 0x05B8 0x0000 0x3 0x0 #define MX6SX_PAD_SD3_DATA6__LCDIF2_DATA_4 0x0270 0x05B8 0x0000 0x4 0x0 #define MX6SX_PAD_SD3_DATA6__GPIO7_IO_8 0x0270 0x05B8 0x0000 0x5 0x0 #define MX6SX_PAD_SD3_DATA6__ENET1_1588_EVENT0_OUT 0x0270 0x05B8 0x0000 0x6 0x0 @@ -1420,6 +1443,7 @@ #define MX6SX_PAD_SD3_DATA7__CAN1_RX 0x0274 0x05BC 0x068C 0x1 0x0 #define MX6SX_PAD_SD3_DATA7__CANFD_RX1 0x0274 0x05BC 0x0694 0x2 0x0 #define MX6SX_PAD_SD3_DATA7__UART3_CTS_B 0x0274 0x05BC 0x0000 0x3 0x0 +#define MX6SX_PAD_SD3_DATA7__UART3_RTS_B 0x0274 0x05BC 0x083C 0x3 0x3 #define MX6SX_PAD_SD3_DATA7__LCDIF2_DATA_5 0x0274 0x05BC 0x0000 0x4 0x0 #define MX6SX_PAD_SD3_DATA7__GPIO7_IO_9 0x0274 0x05BC 0x0000 0x5 0x0 #define MX6SX_PAD_SD3_DATA7__ENET1_1588_EVENT0_IN 0x0274 0x05BC 0x0000 0x6 0x0 @@ -1511,6 +1535,7 @@ #define MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x0298 0x05E0 0x0000 0x0 0x0 #define MX6SX_PAD_SD4_DATA6__RAWNAND_CE3_B 0x0298 0x05E0 0x0000 0x1 0x0 #define MX6SX_PAD_SD4_DATA6__UART5_RTS_B 0x0298 0x05E0 0x084C 0x2 0x0 +#define MX6SX_PAD_SD4_DATA6__UART5_CTS_B 0x0298 0x05E0 0x0000 0x2 0x0 #define MX6SX_PAD_SD4_DATA6__ECSPI3_MISO 0x0298 0x05E0 0x0734 0x3 0x0 #define MX6SX_PAD_SD4_DATA6__LCDIF2_DATA_6 0x0298 0x05E0 0x0000 0x4 0x0 #define MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x0298 0x05E0 0x0000 0x5 0x0 @@ -1521,6 +1546,7 @@ #define MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x029C 0x05E4 0x0000 0x0 0x0 #define MX6SX_PAD_SD4_DATA7__RAWNAND_DATA08 0x029C 0x05E4 0x0000 0x1 0x0 #define MX6SX_PAD_SD4_DATA7__UART5_CTS_B 0x029C 0x05E4 0x0000 0x2 0x0 +#define MX6SX_PAD_SD4_DATA7__UART5_RTS_B 0x029C 0x05E4 0x084C 0x2 0x1 #define MX6SX_PAD_SD4_DATA7__ECSPI3_SS0 0x029C 0x05E4 0x073C 0x3 0x0 #define MX6SX_PAD_SD4_DATA7__LCDIF2_DATA_15 0x029C 0x05E4 0x0000 0x4 0x0 #define MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x029C 0x05E4 0x0000 0x5 0x0 diff --git a/arch/arm/boot/dts/imx6sx-sabreauto.dts b/arch/arm/boot/dts/imx6sx-sabreauto.dts index e4719566133c..8131116c2186 100644 --- a/arch/arm/boot/dts/imx6sx-sabreauto.dts +++ b/arch/arm/boot/dts/imx6sx-sabreauto.dts @@ -66,12 +66,153 @@ enable-active-high; vin-supply = <®_can_en>; }; + + reg_vref_3v3: regulator-adc-verf { + compatible = "regulator-fixed"; + regulator-name = "vref-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_audio: cs42888_supply { + compatible = "regulator-fixed"; + regulator-name = "cs42888_supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + si4763_vio1: vio1_tnr { + compatible = "regulator-fixed"; + regulator-name = "vio1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + si4763_vio2: vio2_tnr { + compatible = "regulator-fixed"; + regulator-name = "vio2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + si4763_vd: f3v3_tnr { + compatible = "regulator-fixed"; + regulator-name = "vd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + si4763_va: f5v_tnr { + compatible = "regulator-fixed"; + regulator-name = "va"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + sound-cs42888 { + compatible = "fsl,imx6-sabreauto-cs42888", + "fsl,imx-audio-cs42888"; + model = "imx-cs42888"; + esai-controller = <&esai>; + asrc-controller = <&asrc>; + audio-codec = <&codec>; + }; + + sound-fm { + compatible = "fsl,imx-audio-si476x", + "fsl,imx-tuner-si476x"; + model = "imx-radio-si4763"; + + ssi-controller = <&ssi2>; + fm-controller = <&si476x_codec>; + mux-int-port = <2>; + mux-ext-port = <5>; + }; + + sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + spdif-controller = <&spdif>; + spdif-in; + }; +}; + +&adc1 { + vref-supply = <®_vref_3v3>; + status = "okay"; +}; + +&adc2 { + vref-supply = <®_vref_3v3>; + status = "okay"; }; &anaclk2 { clock-frequency = <24576000>; }; +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux_3>; + status = "okay"; +}; + +&clks { + assigned-clocks = <&clks IMX6SX_PLL4_BYPASS_SRC>, + <&clks IMX6SX_PLL4_BYPASS>, + <&clks IMX6SX_CLK_PLL4_POST_DIV>; + assigned-clock-parents = <&clks IMX6SX_CLK_LVDS2_IN>, + <&clks IMX6SX_PLL4_BYPASS_SRC>; + assigned-clock-rates = <0>, <0>, <24576000>; +}; + +&esai { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esai_2>; + assigned-clocks = <&clks IMX6SX_CLK_ESAI_SEL>, + <&clks IMX6SX_CLK_ESAI_EXTAL>; + assigned-clock-parents = <&clks IMX6SX_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <0>, <24576000>; + status = "okay"; +}; + +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif_3>; + status = "okay"; +}; + +&ssi2 { + fsl,mode = "i2s-master"; + status = "okay"; +}; + +&csi2 { + status = "okay"; + port { + csi2_ep: endpoint { + remote-endpoint = <&vadc_ep>; + }; + }; +}; + +&dcic1 { + dcic_id = <0>; + dcic_mux = "dcic-lcdif1"; + status = "okay"; +}; + +&dcic2 { + dcic_id = <1>; + dcic_mux = "dcic-lvds"; + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>; @@ -87,11 +228,13 @@ ethphy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; + at803x,eee-disabled; }; ethphy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; + at803x,eee-disabled; }; }; }; @@ -119,12 +262,62 @@ status = "okay"; }; +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand_1>; + nand-on-flash-bbt; + status = "okay"; +}; + +&qspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi1_1>; + status = "okay"; + ddrsmp=<2>; + + flash0: n25q256a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-max-frequency = <29000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + reg = <0>; + }; + + flash1: n25q256a@2 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-max-frequency = <29000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + reg = <2>; + }; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart5 { /* for bluetooth */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + fsl,uart-has-rtscts; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode;*/ + /* pinctrl-0 = <&pinctrl_uart5dte>; */ +}; + &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc3>; @@ -151,6 +344,14 @@ }; &iomuxc { + pinctrl_audmux_3: audmux-3 { + fsl,pins = < + MX6SX_PAD_SD1_CMD__AUDMUX_AUD5_RXC 0x130b0 + MX6SX_PAD_SD1_CLK__AUDMUX_AUD5_RXFS 0x130b0 + MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_RXD 0x130b0 + >; + }; + pinctrl_egalax_int: egalax-intgrp { fsl,pins = < MX6SX_PAD_SD4_RESET_B__GPIO6_IO_22 0x10b0 @@ -193,6 +394,27 @@ >; }; + pinctrl_esai_2: esaigrp-2 { + fsl,pins = < + MX6SX_PAD_CSI_DATA00__ESAI_TX_CLK 0x1b030 + MX6SX_PAD_CSI_DATA01__ESAI_TX_FS 0x1b030 + MX6SX_PAD_CSI_HSYNC__ESAI_TX0 0x1b030 + MX6SX_PAD_CSI_DATA04__ESAI_TX1 0x1b030 + MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3 0x1b030 + MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2 0x1b030 + MX6SX_PAD_CSI_DATA02__ESAI_RX_CLK 0x1b030 + MX6SX_PAD_CSI_DATA03__ESAI_RX_FS 0x1b030 + MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x1b030 + MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1 0x1b030 + >; + }; + + pinctrl_spdif_3: spdifgrp-3 { + fsl,pins = < + MX6SX_PAD_ENET2_COL__SPDIF_IN 0x1b0b0 + >; + }; + pinctrl_flexcan1: flexcan1grp { fsl,pins = < MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b020 @@ -207,6 +429,27 @@ >; }; + pinctrl_gpmi_nand_1: gpmi-nand-1 { + fsl,pins = < + MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 + MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 + MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 + MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 + MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 + MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 + MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 + MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 + MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 + MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 + MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 + MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 + MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 + MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 + MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 + MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 + >; + }; + pinctrl_i2c2: i2c2grp { fsl,pins = < MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 @@ -227,6 +470,23 @@ >; }; + pinctrl_qspi1_1: qspi1grp_1 { + fsl,pins = < + MX6SX_PAD_QSPI1A_DATA0__QSPI1_A_DATA_0 0x70a1 + MX6SX_PAD_QSPI1A_DATA1__QSPI1_A_DATA_1 0x70a1 + MX6SX_PAD_QSPI1A_DATA2__QSPI1_A_DATA_2 0x70a1 + MX6SX_PAD_QSPI1A_DATA3__QSPI1_A_DATA_3 0x70a1 + MX6SX_PAD_QSPI1A_SCLK__QSPI1_A_SCLK 0x70a1 + MX6SX_PAD_QSPI1A_SS0_B__QSPI1_A_SS0_B 0x70a1 + MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0 0x70a1 + MX6SX_PAD_QSPI1B_DATA1__QSPI1_B_DATA_1 0x70a1 + MX6SX_PAD_QSPI1B_DATA2__QSPI1_B_DATA_2 0x70a1 + MX6SX_PAD_QSPI1B_DATA3__QSPI1_B_DATA_3 0x70a1 + MX6SX_PAD_QSPI1B_SCLK__QSPI1_B_SCLK 0x70a1 + MX6SX_PAD_QSPI1B_SS0_B__QSPI1_B_SS0_B 0x70a1 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 @@ -234,6 +494,31 @@ >; }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO07__UART2_RX 0x1b0b1 + MX6SX_PAD_GPIO1_IO06__UART2_TX 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 + MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 + MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 + MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart5dte: uart5dtegrp { + fsl,pins = < + MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 + MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 + MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 + MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 + >; + }; + pinctrl_usdhc3: usdhc3grp { fsl,pins = < MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 @@ -313,6 +598,31 @@ pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; + codec: cs42888@48 { + compatible = "cirrus,cs42888"; + reg = <0x48>; + clocks = <&anaclk2 0>; + clock-names = "mclk"; + VA-supply = <®_audio>; + VD-supply = <®_audio>; + VLS-supply = <®_audio>; + VLC-supply = <®_audio>; + }; + + si4763: si4763@63 { + compatible = "si4761"; + reg = <0x63>; + va-supply = <&si4763_va>; + vd-supply = <&si4763_vd>; + vio1-supply = <&si4763_vio1>; + vio2-supply = <&si4763_vio2>; + revision-a10; /* set to default A10 compatible command set */ + + si476x_codec: si476x-codec { + compatible = "si476x-codec"; + }; + }; + touchscreen@4 { compatible = "eeti,egalax_ts"; reg = <0x04>; @@ -452,6 +762,42 @@ gpio-controller; #gpio-cells = <2>; }; + + mma8451@1c { + compatible = "fsl,mma8451"; + reg = <0x1c>; + position = <7>; + interrupt-parent = <&gpio3>; + interrupts = <24 8>; + interrupt-route = <1>; + }; + + mag3110@e { + compatible = "fsl,mag3110"; + reg = <0xe>; + position = <2>; + interrupt-parent = <&gpio6>; + interrupts = <6 1>; + }; + + isl29023@44 { + compatible = "fsl,isl29023"; + reg = <0x44>; + rext = <499>; + interrupt-parent = <&gpio3>; + interrupts = <23 2>; + }; +}; + +&vadc { + vadc_in = <0>; + csi_id = <1>; + status = "okay"; + port { + vadc_ep: endpoint { + remote-endpoint = <&csi2_ep>; + }; + }; }; &wdog1 { diff --git a/arch/arm/boot/dts/imx6sx-sdb-btwifi.dts b/arch/arm/boot/dts/imx6sx-sdb-btwifi.dts new file mode 100644 index 000000000000..ab4cde5fe76b --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-btwifi.dts @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * NOTE: This DTS file is wrote for plugging in Murata 1MW M.2 + * into SD2 slot by using Murata uSD-to-M.2 Adapter. + * + * By default, OOB IRQ is not enabled since i.MX6SX SDB board needs to rework. + * How to enable OOB IRQ ? + * HW rework: + * Install R328 on i.MX6SX SDB board. + * SW change: + * pinctrl_wifi: wifigrp { + * fsl,pins = < + * MX6SX_PAD_ENET1_RX_CLK__GPIO2_IO_4 0x0b001 + * >; + * }; + * brcmf: bcrmf@1 { + * reg = <1>; + * compatible = "brcm,bcm4329-fmac"; + * interrupt-parent = <&gpio2>; + * interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + * interrupt-names = "host-wake"; + * }; + */ + +#include "imx6sx-sdb.dts" + +/ { + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + usdhc2_pwrseq: usdhc2_pwrseq { + compatible = "mmc-pwrseq-simple"; + }; +}; + +&iomuxc { + imx6sx-sdb-murata-wifibt { + pinctrl_bt: btgrp { + fsl,pins = < + MX6SX_PAD_NAND_DATA06__GPIO4_IO_10 0x13069 /* BT_REG_ON */ + >; + }; + + pinctrl_wifi: wifigrp { + fsl,pins = < + >; + }; + }; +}; + +&uart5 { /* for bluetooth */ + pinctrl-0 = <&pinctrl_uart5 &pinctrl_bt>; + resets = <&modem_reset>; +}; + + +&usdhc2 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2 &pinctrl_wifi>; + bus-width = <4>; + no-1-8-v; /* force 3.3V VIO */ + non-removable; + mmc-pwrseq = <&usdhc2_pwrseq>; + pm-ignore-notify; + cap-power-off-card; + /delete-property/ wakeup-source; + status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb-emmc.dts b/arch/arm/boot/dts/imx6sx-sdb-emmc.dts new file mode 100644 index 000000000000..b829d7dbe368 --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-emmc.dts @@ -0,0 +1,33 @@ +/* + * Copyright 2019 NXP + * + * 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. + */ + +#include "imx6sx-sdb.dts" + +/* + * The eMMC chip on imx6sx sdb board is DNP by default. + * Need do hw rework to burn the eMMC4.5 chip on the eMMC socket on uSDHC4 + * and connect eMMC signals as well as disconnect BOOT SD CARD slot signals + */ +&usdhc4 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc4_1>; + pinctrl-1 = <&pinctrl_usdhc4_1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc4_1_200mhz>; + bus-width = <8>; + auto-cmd23-broken; + /* + * overwrite cd-gpios and wp-gpios since they are reused as eMMC DATA + * signals after rework + */ + cd-gpios = <>; + wp-gpios = <>; + non-removable; + status = "okay"; +}; + diff --git a/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts b/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts new file mode 100644 index 000000000000..23f69ef9b1e6 --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + */ + +#include "imx6sx-sdb.dts" + +/ { + sii902x_reset: sii902x-reset { + status = "okay"; + }; +}; + +&csi1 { + status = "disabled"; +}; + +&lcdif1 { + status = "okay"; +}; + +&i2c1 { + sii902x@39 { + status = "okay"; + }; +}; + +&ov5640 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb-ldo.dts b/arch/arm/boot/dts/imx6sx-sdb-ldo.dts new file mode 100644 index 000000000000..3a8c194ba2d6 --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-ldo.dts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6sx-sdb.dts" + +&cpu0 { + operating-points = < + /* kHz uV */ + 996000 1250000 + 792000 1175000 + 396000 1075000 + 198000 975000 + >; + fsl,soc-operating-points = < + /* ARM kHz SOC uV */ + 996000 1175000 + 792000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,arm-soc-shared = <0>; +}; + +&gpc { + fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb-m4.dts b/arch/arm/boot/dts/imx6sx-sdb-m4.dts new file mode 100644 index 000000000000..80db8b9dbef6 --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-m4.dts @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6sx-sdb.dts" + +/{ + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + m4_reserved: m4@0x9ff00000 { + no-map; + reg = <0x9ff00000 0x100000>; + }; + + rpmsg_reserved: rpmsg@0xbff00000 { + no-map; + reg = <0xbff00000 0x100000>; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; +}; + +/* + * The flollowing modules are conflicting with M4, disable them when m4 + * is running. + */ +&adc1 { + status = "disabled"; +}; + +&adc2 { + status = "disabled"; +}; + +&flexcan1 { + status = "disabled"; +}; + +&flexcan2 { + status = "disabled"; +}; + +&i2c3 { + status = "disabled"; +}; + +&ocram { + reg = <0x00901000 0xf000>; +}; + +&qspi2 { + status = "disabled"; +}; + +&qspi_m4 { + status = "okay"; +}; + +&rpmsg{ + vdev-nums = <1>; + reg = <0xbfff0000 0x10000>; + status = "okay"; +}; + +&uart2 { + status = "disabled"; +}; + +&clks { + fsl,shared-clks-number = <0x23>; + fsl,shared-clks-index = <IMX6SX_CLK_PLL2_BUS IMX6SX_CLK_PLL2_PFD0 + IMX6SX_CLK_PLL2_PFD2 IMX6SX_CLK_PLL3_USB_OTG + IMX6SX_CLK_PLL3_PFD1 IMX6SX_CLK_PLL3_PFD2 + IMX6SX_CLK_PLL3_PFD3 IMX6SX_CLK_PLL4_AUDIO + IMX6SX_CLK_PLL5_VIDEO + IMX6SX_CLK_OCRAM IMX6SX_CLK_CAN1_SERIAL + IMX6SX_CLK_CAN1_IPG IMX6SX_CLK_CAN2_SERIAL + IMX6SX_CLK_CAN2_IPG IMX6SX_CLK_CANFD + IMX6SX_CLK_ECSPI1 IMX6SX_CLK_ECSPI2 + IMX6SX_CLK_ECSPI3 IMX6SX_CLK_ECSPI4 + IMX6SX_CLK_ECSPI5 IMX6SX_CLK_QSPI1 + IMX6SX_CLK_QSPI2 IMX6SX_CLK_SSI1 + IMX6SX_CLK_SSI2 IMX6SX_CLK_SSI3 + IMX6SX_CLK_UART_SERIAL IMX6SX_CLK_UART_IPG + IMX6SX_CLK_PERIPH_CLK2_SEL IMX6SX_CLK_DUMMY + IMX6SX_CLK_I2C1 IMX6SX_CLK_I2C2 + IMX6SX_CLK_I2C3 IMX6SX_CLK_I2C4 + IMX6SX_CLK_EPIT1 IMX6SX_CLK_EPIT2>; + fsl,shared-mem-addr = <0x91F000>; + fsl,shared-mem-size = <0x1000>; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb-mqs.dts b/arch/arm/boot/dts/imx6sx-sdb-mqs.dts new file mode 100644 index 000000000000..3aae33f7f144 --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-mqs.dts @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014 Freescale Semiconductor, Inc. + +#include "imx6sx-sdb.dts" +/ { + + sound { + status = "disabled"; + }; + + sound-mqs { + compatible = "fsl,imx6sx-sdb-mqs", + "fsl,imx-audio-mqs"; + model = "mqs-audio"; + cpu-dai = <&sai1>; + asrc-controller = <&asrc>; + audio-codec = <&mqs>; + }; +}; + +&usdhc2 { + /* pin conflict with mqs*/ + status = "disabled"; +}; + +&mqs { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mqs>; + clocks = <&clks IMX6SX_CLK_SAI1>; + clock-names = "mclk"; + status = "okay"; +}; + +&sai1 { + pinctrl-0 = <>; + status = "okay"; +}; + +&ssi2 { + status = "disabled"; +}; + +&sdma { + gpr = <&gpr>; + /* SDMA event remap for SAI1 */ + fsl,sdma-event-remap = <0 15 1>, <0 16 1>; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb-pcie-ep.dts b/arch/arm/boot/dts/imx6sx-sdb-pcie-ep.dts new file mode 100644 index 000000000000..c6c473ad420b --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-pcie-ep.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx6sx-sdb.dts" + +&pcie{ + status = "disabled"; +}; + +&pcie_ep{ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts b/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts new file mode 100644 index 000000000000..867199915236 --- /dev/null +++ b/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6sx-sdb-reva.dts" + +&gpc { + fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts index 5a63ca615722..6a1dba0fb699 100644 --- a/arch/arm/boot/dts/imx6sx-sdb.dts +++ b/arch/arm/boot/dts/imx6sx-sdb.dts @@ -103,6 +103,23 @@ }; }; +&cpu0 { + operating-points = < + /* kHz uV */ + 996000 1250000 + 792000 1175000 + 396000 1175000 + >; + fsl,soc-operating-points = < + /* ARM kHz SOC uV */ + 996000 1250000 + 792000 1175000 + 396000 1175000 + >; + + fsl,arm-soc-shared = <1>; +}; + &qspi2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_qspi2>; @@ -131,10 +148,12 @@ ®_arm { vin-supply = <&sw1a_reg>; + regulator-allow-bypass; }; ®_soc { vin-supply = <&sw1a_reg>; + regulator-allow-bypass; }; ®_vdd1p1 { diff --git a/arch/arm/boot/dts/imx6sx-sdb.dtsi b/arch/arm/boot/dts/imx6sx-sdb.dtsi index 865528b134d8..fbae20d2a2c0 100644 --- a/arch/arm/boot/dts/imx6sx-sdb.dtsi +++ b/arch/arm/boot/dts/imx6sx-sdb.dtsi @@ -28,6 +28,14 @@ default-brightness-level = <6>; }; + backlight2 { + compatible = "pwm-backlight"; + pwms = <&pwm4 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + fb-names = "mxs-lcdif1"; + }; + gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -56,6 +64,7 @@ regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; enable-active-high; }; @@ -93,6 +102,7 @@ regulator-name = "lcd-3v3"; gpio = <&gpio3 27 0>; enable-active-high; + status = "disabled"; }; reg_peri_3v3: regulator-peri-3v3 { @@ -151,10 +161,22 @@ regulator-max-microvolt = <3300000>; }; + reg_vref_3v3: regulator-adc-verf { + compatible = "regulator-fixed"; + regulator-name = "vref-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + pxp_v4l2_out { + compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + sound { compatible = "fsl,imx6sx-sdb-wm8962", "fsl,imx-audio-wm8962"; model = "wm8962-audio"; - ssi-controller = <&ssi2>; + audio-cpu = <&ssi2>; audio-codec = <&codec>; audio-routing = "Headphone Jack", "HPOUTL", @@ -165,28 +187,78 @@ "IN3R", "AMIC"; mux-int-port = <2>; mux-ext-port = <6>; + codec-master; + hp-det-gpios = <&gpio1 17 1>; }; - panel { - compatible = "sii,43wvf1g"; - backlight = <&backlight_display>; - dvdd-supply = <®_lcd_3v3>; - avdd-supply = <®_lcd_5v>; + sound-spdif { + compatible = "fsl,imx-audio-spdif", + "fsl,imx6sx-sdb-spdif"; + model = "imx-spdif"; + spdif-controller = <&spdif>; + spdif-out; + }; - port { - panel_in: endpoint { - remote-endpoint = <&display_out>; - }; - }; + sii902x_reset: sii902x-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio3 27 1>; + reset-delay-us = <100000>; + #reset-cells = <0>; + status = "disabled"; }; }; +&adc1 { + vref-supply = <®_vref_3v3>; + status = "okay"; +}; + +&adc2 { + vref-supply = <®_vref_3v3>; + status = "okay"; +}; + &audmux { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; +&csi1 { + status = "okay"; + + port { + csi1_ep: endpoint { + remote-endpoint = <&ov5640_ep>; + }; + }; +}; + +&csi2 { + status = "okay"; + port { + csi2_ep: endpoint { + remote-endpoint = <&vadc_ep>; + }; + }; +}; + +&gpc { + fsl,ldo-bypass = <1>; +}; + +&dcic1 { + dcic_id = <0>; + dcic_mux = "dcic-lcdif1"; + status = "okay"; +}; + +&dcic2 { + dcic_id = <1>; + dcic_mux = "dcic-lvds"; + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>; @@ -202,10 +274,12 @@ ethphy1: ethernet-phy@1 { reg = <1>; + at803x,eee-disabled; }; ethphy2: ethernet-phy@2 { reg = <2>; + at803x,eee-disabled; }; }; }; @@ -232,11 +306,99 @@ status = "okay"; }; +&gpc { + fsl,ldo-bypass = <1>; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + ov5640: ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi_0>; + clocks = <&clks IMX6SX_CLK_CSI>; + clock-names = "csi_mclk"; + AVDD-supply = <&vgen3_reg>; /* 2.8v */ + DVDD-supply = <&vgen2_reg>; /* 1.5v*/ + pwn-gpios = <&gpio3 28 1>; + rst-gpios = <&gpio3 27 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + port { + ov5640_ep: endpoint { + remote-endpoint = <&csi1_ep>; + }; + }; + }; + + sii902x@39 { + compatible = "SiI,sii902x"; + interrupt-parent = <&gpio4>; + interrupts = <21 2>; + mode_str ="1280x720M@60"; + bits-per-pixel = <16>; + resets = <&sii902x_reset>; + reg = <0x39>; + status = "disabled"; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + egalax_ts@4 { + compatible = "eeti,egalax_ts"; + reg = <0x4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_egalax_int>; + interrupt-parent = <&gpio4>; + interrupts = <19 2>; + wakeup-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; + }; +}; + + &i2c3 { clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay"; + + isl29023@44 { + compatible = "fsl,isl29023"; + reg = <0x44>; + rext = <499>; + interrupt-parent = <&gpio6>; + interrupts = <5 1>; + shared-interrupt; + }; + + mag3110@e { + compatible = "fsl,mag3110"; + reg = <0xe>; + position = <2>; + interrupt-parent = <&gpio6>; + interrupts = <5 1>; + shared-interrupt; + }; + + mma8451@1c { + compatible = "fsl,mma8451"; + reg = <0x1c>; + position = <1>; + interrupt-parent = <&gpio6>; + interrupts = <2 8>; + interrupt-route = <2>; + }; }; &i2c4 { @@ -271,11 +433,65 @@ &lcdif1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcd>; + lcd-supply = <®_lcd_3v3>; + display = <&display0>; + status = "disabled"; + + display0: display@0 { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hback-porch = <89>; + hfront-porch = <164>; + vback-porch = <23>; + vfront-porch = <10>; + hsync-len = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + +&lcdif2 { + display = <&display1>; + disp-dev = "ldb"; status = "okay"; + display1: display@1 { + bits-per-pixel = <16>; + bus-width = <18>; + }; +}; - port { - display_out: endpoint { - remote-endpoint = <&panel_in>; +&ldb { + status = "okay"; + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + crtc = "lcdif2"; + status = "okay"; + display-timings { + native-mode = <&timing1>; + timing1: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; }; }; }; @@ -286,6 +502,16 @@ status = "okay"; }; +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; + status = "okay"; +}; + +&pxp { + status = "okay"; +}; + &snvs_poweroff { status = "okay"; }; @@ -296,7 +522,20 @@ status = "disabled"; }; +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif>; + status = "okay"; +}; + &ssi2 { + assigned-clocks = <&clks IMX6SX_CLK_PLL4>, + <&clks IMX6SX_PLL4_BYPASS>, + <&clks IMX6SX_CLK_SSI2_SEL>; + assigned-clock-parents = <&clks IMX6SX_CLK_OSC>, + <&clks IMX6SX_CLK_PLL4>, + <&clks IMX6SX_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <737280000>, <0>, <0>; status = "okay"; }; @@ -311,6 +550,9 @@ pinctrl-0 = <&pinctrl_uart5>; uart-has-rtscts; status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode;*/ + /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ }; &usbotg1 { @@ -374,6 +616,24 @@ &iomuxc { imx6x-sdb { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog &pinctrl_can_gpios>; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX6SX_PAD_SD1_DATA0__GPIO6_IO_2 0x17059 + MX6SX_PAD_SD1_DATA3__GPIO6_IO_5 0xb000 + MX6SX_PAD_CSI_DATA03__GPIO1_IO_17 0x17059 + >; + }; + + pinctrl_can_gpios: can-gpios { + fsl,pins = < + MX6SX_PAD_QSPI1B_DATA1__GPIO4_IO_25 0x17059 + MX6SX_PAD_QSPI1B_DATA3__GPIO4_IO_27 0x17059 + >; + }; + pinctrl_audmux: audmuxgrp { fsl,pins = < MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x130b0 @@ -384,11 +644,38 @@ >; }; + pinctrl_csi_0: csigrp-0 { + fsl,pins = < + MX6SX_PAD_LCD1_DATA07__CSI1_MCLK 0x110b0 + MX6SX_PAD_LCD1_DATA06__CSI1_PIXCLK 0x110b0 + MX6SX_PAD_LCD1_DATA04__CSI1_VSYNC 0x110b0 + MX6SX_PAD_LCD1_DATA05__CSI1_HSYNC 0x110b0 + MX6SX_PAD_LCD1_DATA17__CSI1_DATA_0 0x110b0 + MX6SX_PAD_LCD1_DATA16__CSI1_DATA_1 0x110b0 + MX6SX_PAD_LCD1_DATA15__CSI1_DATA_2 0x110b0 + MX6SX_PAD_LCD1_DATA14__CSI1_DATA_3 0x110b0 + MX6SX_PAD_LCD1_DATA13__CSI1_DATA_4 0x110b0 + MX6SX_PAD_LCD1_DATA12__CSI1_DATA_5 0x110b0 + MX6SX_PAD_LCD1_DATA11__CSI1_DATA_6 0x110b0 + MX6SX_PAD_LCD1_DATA10__CSI1_DATA_7 0x110b0 + MX6SX_PAD_LCD1_DATA09__CSI1_DATA_8 0x110b0 + MX6SX_PAD_LCD1_DATA08__CSI1_DATA_9 0x110b0 + MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x80000000 + MX6SX_PAD_LCD1_VSYNC__GPIO3_IO_28 0x80000000 + >; + }; + + pinctrl_egalax_int: egalax_intgrp { + fsl,pins = < + MX6SX_PAD_QSPI1A_DATA3__GPIO4_IO_19 0x80000000 + >; + }; + pinctrl_enet1: enet1grp { fsl,pins = < MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 - MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b1 + MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b9 MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 @@ -457,6 +744,13 @@ >; }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 + MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 + >; + }; + pinctrl_i2c3: i2c3grp { fsl,pins = < MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 @@ -529,6 +823,12 @@ >; }; + pinctrl_pwm4: pwm4grp-1 { + fsl,pins = < + MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 + >; + }; + pinctrl_qspi2: qspi2grp { fsl,pins = < MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x70f1 @@ -552,6 +852,13 @@ >; }; + pinctrl_mqs: mqsgrp { + fsl,pins = < + MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x120b0 + MX6SX_PAD_SD2_CMD__MQS_LEFT 0x120b0 + >; + }; + pinctrl_sai1: sai1grp { fsl,pins = < MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x130b0 @@ -562,6 +869,12 @@ >; }; + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x1b0b0 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 @@ -578,6 +891,15 @@ >; }; + pinctrl_uart5dte_1: uart5dtegrp-1 { + fsl,pins = < + MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 + MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 + MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 + MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 + >; + }; + pinctrl_usb_otg1: usbotg1grp { fsl,pins = < MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x10b0 @@ -667,6 +989,51 @@ >; }; + pinctrl_usdhc4_1: usdhc4grp-1 { + fsl,pins = < + MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 + MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 + MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 + MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 + MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 + MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 + MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x17059 + MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x17059 + MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x17059 + MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x17059 + >; + }; + + pinctrl_usdhc4_1_100mhz: usdhc4grp-1-100mhz { + fsl,pins = < + MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170b9 + MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100b9 + MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170b9 + MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170b9 + MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170b9 + MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170b9 + MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170b9 + MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170b9 + MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170b9 + MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc4_1_200mhz: usdhc4grp-1-200mhz { + fsl,pins = < + MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170f9 + MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100f9 + MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170f9 + MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170f9 + MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170f9 + MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170f9 + MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170f9 + MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170f9 + MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170f9 + MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170f9 + >; + }; + pinctrl_wdog: wdoggrp { fsl,pins = < MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x30b0 @@ -674,3 +1041,14 @@ }; }; }; + +&vadc { + vadc_in = <0>; + csi_id = <1>; + status = "okay"; + port { + vadc_ep: endpoint { + remote-endpoint = <&csi2_ep>; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index 531a52c1e987..7da572cbee48 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -82,14 +82,32 @@ <&clks IMX6SX_CLK_PLL2_PFD2>, <&clks IMX6SX_CLK_STEP>, <&clks IMX6SX_CLK_PLL1_SW>, - <&clks IMX6SX_CLK_PLL1_SYS>; + <&clks IMX6SX_CLK_PLL1_SYS>, + <&clks IMX6SX_CLK_PLL1>, + <&clks IMX6SX_PLL1_BYPASS>, + <&clks IMX6SX_PLL1_BYPASS_SRC>; clock-names = "arm", "pll2_pfd2_396m", "step", - "pll1_sw", "pll1_sys"; + "pll1_sw", "pll1_sys", "pll1", + "pll1_bypass", "pll1_bypass_src"; arm-supply = <®_arm>; soc-supply = <®_soc>; }; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + linux,cma-default; + }; + }; + ckil: clock-ckil { compatible = "fixed-clock"; #clock-cells = <0>; @@ -160,18 +178,61 @@ interrupt-parent = <&gpc>; ranges; - ocram_s: sram@8f8000 { - compatible = "mmio-sram"; - reg = <0x008f8000 0x4000>; + busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6SX_CLK_PLL2_BUS>, <&clks IMX6SX_CLK_PLL2_PFD2>, + <&clks IMX6SX_CLK_PLL2_198M>, <&clks IMX6SX_CLK_ARM>, + <&clks IMX6SX_CLK_PLL3_USB_OTG>, <&clks IMX6SX_CLK_PERIPH>, + <&clks IMX6SX_CLK_PERIPH_PRE>, <&clks IMX6SX_CLK_PERIPH_CLK2>, + <&clks IMX6SX_CLK_PERIPH_CLK2_SEL>, <&clks IMX6SX_CLK_OSC>, + <&clks IMX6SX_CLK_PLL1_SYS>, <&clks IMX6SX_CLK_PERIPH2>, + <&clks IMX6SX_CLK_AHB>, <&clks IMX6SX_CLK_OCRAM_PODF>, + <&clks IMX6SX_CLK_PLL1_SW>, <&clks IMX6SX_CLK_PERIPH2_PRE>, + <&clks IMX6SX_CLK_PERIPH2_CLK2_SEL>, <&clks IMX6SX_CLK_PERIPH2_CLK2>, + <&clks IMX6SX_CLK_STEP>, <&clks IMX6SX_CLK_MMDC_PODF>, + <&clks IMX6SX_CLK_M4>; + clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", + "pll3_usb_otg", "periph", "periph_pre", "periph_clk2", + "periph_clk2_sel", "osc", "pll1_sys", "periph2", + "ahb", "ocram", "pll1_sw", "periph2_pre", + "periph2_clk2_sel", "periph2_clk2", "step", "mmdc", + "m4"; + fsl,max_ddr_freq = <400000000>; + }; + + ocrams: sram@8f8000 { + compatible = "fsl,lpm-sram"; + reg = <0x8f8000 0x4000>; clocks = <&clks IMX6SX_CLK_OCRAM_S>; }; - ocram: sram@900000 { + ocrams_ddr: sram@900000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x900000 0x1000>; + clocks = <&clks IMX6SX_CLK_OCRAM>; + }; + + ocram: sram@901000 { compatible = "mmio-sram"; - reg = <0x00900000 0x20000>; + reg = <0x901000 0x1F000>; clocks = <&clks IMX6SX_CLK_OCRAM>; }; + ocram_mf: sram-mf@900000 { + compatible = "fsl,mega-fast-sram"; + reg = <0x900000 0x20000>; + clocks = <&clks IMX6SX_CLK_OCRAM>; + }; + + ocram_optee { + compatible = "fsl,optee-lpm-sram"; + reg = <0x8f8000 0x4000>; + overw_reg = <&ocrams_ddr 0x904000 0x1000>, + <&ocram 0x905000 0x1b000>, + <&ocrams 0x900000 0x4000>; + overw_clock = <&ocrams &clks IMX6SX_CLK_OCRAM>; + }; + intc: interrupt-controller@a01000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; @@ -200,6 +261,23 @@ <&clks IMX6SX_CLK_GPU>; clock-names = "bus", "core", "shader"; power-domains = <&pd_pu>; + status = "disabled"; + }; + + gpu3d: gpu3d@1800000 { + compatible = "fsl,imx6sx-gpu", "fsl,imx6q-gpu"; + reg = <0x1800000 0x4000>, <0x80000000 0x0>, + <0x0 0x8000000>; + reg-names = "iobase_3d", "phys_baseaddr", "contiguous_mem"; + interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "irq_3d"; + clocks = <&clks IMX6SX_CLK_GPU_AXI_PODF>, <&clks IMX6SX_CLK_GPU>, + <&clks 0>; + clock-names = "gpu3d_axi_clk", "gpu3d_clk", + "gpu3d_shader_clk"; + resets = <&src 0>; + reset-names = "gpu3d"; + power-domains = <&pd_pu>; }; dma_apbh: dma-apbh@1804000 { @@ -215,6 +293,11 @@ clocks = <&clks IMX6SX_CLK_APBH_DMA>; }; + caam_sm: caam-sm@100000 { + compatible = "fsl,imx6q-caam-sm"; + reg = <0x100000 0x8000>; + }; + gpmi: gpmi-nand@1806000{ compatible = "fsl,imx6sx-gpmi-nand"; #address-cells = <1>; @@ -333,6 +416,7 @@ }; esai: esai@2024000 { + compatible = "fsl,imx35-esai"; reg = <0x02024000 0x4000>; interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_ESAI_IPG>, @@ -342,6 +426,9 @@ <&clks IMX6SX_CLK_SPBA>; clock-names = "core", "mem", "extal", "fsys", "spba"; + dmas = <&sdma 23 21 0>, + <&sdma 24 21 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -388,18 +475,27 @@ }; asrc: asrc@2034000 { + compatible = "fsl,imx53-asrc"; reg = <0x02034000 0x4000>; - interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6SX_CLK_ASRC_MEM>, - <&clks IMX6SX_CLK_ASRC_IPG>, - <&clks IMX6SX_CLK_SPDIF>, - <&clks IMX6SX_CLK_SPBA>; - clock-names = "mem", "ipg", "asrck", "spba"; - dmas = <&sdma 17 20 1>, <&sdma 18 20 1>, - <&sdma 19 20 1>, <&sdma 20 20 1>, - <&sdma 21 20 1>, <&sdma 22 20 1>; + interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SX_CLK_ASRC_IPG>, + <&clks IMX6SX_CLK_ASRC_MEM>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks IMX6SX_CLK_SPDIF>, <&clks 0>, <&clks 0>, + <&clks IMX6SX_CLK_SPBA>; + clock-names = "mem", "ipg", "asrck_0", + "asrck_1", "asrck_2", "asrck_3", "asrck_4", + "asrck_5", "asrck_6", "asrck_7", "asrck_8", + "asrck_9", "asrck_a", "asrck_b", "asrck_c", + "asrck_d", "asrck_e", "asrck_f", "spba"; + dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, + <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", - "txa", "txb", "txc"; + "txa", "txb", "txc"; + fsl,asrc-rate = <48000>; + fsl,asrc-width = <16>; status = "okay"; }; }; @@ -559,6 +655,12 @@ gpio-ranges = <&iomuxc 0 148 10>, <&iomuxc 10 169 2>; }; + mqs: mqs { + compatible = "fsl,imx6sx-mqs"; + gpr = <&gpr>; + status = "disabled"; + }; + kpp: kpp@20b8000 { compatible = "fsl,imx6sx-kpp", "fsl,imx21-kpp"; reg = <0x020b8000 0x4000>; @@ -712,6 +814,20 @@ fsl,anatop = <&anatop>; }; + irq_sec_vio: caam_secvio { + compatible = "fsl,imx6q-caam-secvio"; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + jtag-tamper = "disabled"; + watchdog-tamper = "enabled"; + internal-boot-tamper = "enabled"; + external-pin-tamper = "disabled"; + }; + + caam_snvs: caam-snvs@20cc000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x20cc000 0x4000>; + }; + snvs: snvs@20cc000 { compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; reg = <0x020cc000 0x4000>; @@ -767,6 +883,7 @@ #interrupt-cells = <3>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&intc>; + fsl,mf-mix-wakeup-irq = <0x7c00000 0x3d00 0x0 0x400240>; clocks = <&clks IMX6SX_CLK_IPG>; clock-names = "ipg"; @@ -817,6 +934,30 @@ reg = <0x020e4000 0x4000>; }; + ldb: ldb@20e0014 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6sx-ldb", "fsl,imx53-ldb"; + gpr = <&gpr>; + status = "disabled"; + clocks = <&clks IMX6SX_CLK_LDB_DI0>, + <&clks IMX6SX_CLK_LCDIF1_SEL>, + <&clks IMX6SX_CLK_LCDIF2_SEL>, + <&clks IMX6SX_CLK_LDB_DI0_DIV_3_5>, + <&clks IMX6SX_CLK_LDB_DI0_DIV_7>, + <&clks IMX6SX_CLK_LDB_DI0_DIV_SEL>; + clock-names = "ldb_di0", + "di0_sel", + "di1_sel", + "ldb_di0_div_3_5", + "ldb_di0_div_7", + "ldb_di0_div_sel"; + lvds-channel@0 { + reg = <0>; + status = "disabled"; + }; + }; + sdma: sdma@20ec000 { compatible = "fsl,imx6sx-sdma", "fsl,imx6q-sdma"; reg = <0x020ec000 0x4000>; @@ -928,6 +1069,8 @@ "enet_clk_ref", "enet_out"; fsl,num-tx-queues = <3>; fsl,num-rx-queues = <3>; + stop-mode = <&gpr 0x10 3>; + fsl,wakeup_irq = <0>; status = "disabled"; }; @@ -949,6 +1092,8 @@ <&clks IMX6SX_CLK_USDHC1>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "disabled"; }; @@ -961,6 +1106,8 @@ <&clks IMX6SX_CLK_USDHC2>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "disabled"; }; @@ -973,6 +1120,8 @@ <&clks IMX6SX_CLK_USDHC3>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "disabled"; }; @@ -985,6 +1134,8 @@ <&clks IMX6SX_CLK_USDHC4>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "disabled"; }; @@ -1037,6 +1188,10 @@ <&clks IMX6SX_CLK_ENET_PTP>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; + fsl,num-tx-queues=<3>; + fsl,num-rx-queues=<3>; + stop-mode = <&gpr 0x10 4>; + fsl,wakeup_irq = <0>; status = "disabled"; }; @@ -1125,6 +1280,12 @@ status = "disabled"; }; + qspi_m4: qspi-m4 { + compatible = "fsl,imx6sx-qspi-m4-restore"; + reg = <0x021e4000 0x4000>; + status = "disabled"; + }; + uart2: serial@21e8000 { compatible = "fsl,imx6sx-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; @@ -1203,21 +1364,46 @@ ranges; csi1: csi@2214000 { + compatible = "fsl,imx6s-csi"; reg = <0x02214000 0x4000>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_DISPLAY_AXI>, <&clks IMX6SX_CLK_CSI>, <&clks IMX6SX_CLK_DCIC1>; - clock-names = "disp-axi", "csi_mclk", "dcic"; + clock-names = "disp-axi", "csi_mclk", "disp_dcic"; + power-domains = <&pd_disp>; + status = "disabled"; + }; + + dcic1: dcic@220c000 { + compatible = "fsl,imx6sx-dcic"; + reg = <0x220c000 0x4000>; + interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SX_CLK_DCIC1>, + <&clks IMX6SX_CLK_DISPLAY_AXI>; + clock-names = "dcic", "disp-axi"; + gpr = <&gpr>; + status = "disabled"; + }; + + dcic2: dcic@2210000 { + compatible = "fsl,imx6sx-dcic"; + reg = <0x2210000 0x4000>; + interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SX_CLK_DCIC2>, + <&clks IMX6SX_CLK_DISPLAY_AXI>; + clock-names = "dcic", "disp-axi"; + gpr = <&gpr>; status = "disabled"; }; pxp: pxp@2218000 { - compatible = "fsl,imx6sx-pxp", "fsl,imx6ull-pxp"; + compatible = "fsl,imx6sx-pxp-dma", "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; reg = <0x02218000 0x4000>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6SX_CLK_PXP_AXI>; - clock-names = "axi"; + clocks = <&clks IMX6SX_CLK_PXP_AXI>, + <&clks IMX6SX_CLK_DISPLAY_AXI>; + clock-names = "pxp-axi", "disp-axi"; power-domains = <&pd_disp>; status = "disabled"; }; @@ -1273,6 +1459,7 @@ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_IPG>; clock-names = "adc"; + num-channels = <4>; fsl,adck-max-frequency = <30000000>, <40000000>, <20000000>; status = "disabled"; @@ -1284,6 +1471,7 @@ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_IPG>; clock-names = "adc"; + num-channels = <4>; fsl,adck-max-frequency = <30000000>, <40000000>, <20000000>; status = "disabled"; @@ -1309,6 +1497,27 @@ status = "disabled"; }; + sema4: sema4@02290000 { /* sema4 */ + compatible = "fsl,imx6sx-sema4"; + reg = <0x02290000 0x4000>; + interrupts = <0 116 0x04>; + status = "okay"; + }; + + mu: mu@02294000 { /* mu */ + compatible = "fsl,imx6sx-mu"; + reg = <0x02294000 0x4000>; + interrupts = <0 90 0x04>; + #mbox-cells = <2>; + }; + + mu_lp: mu_lp@02294000 { /* mu */ + compatible = "fsl,imx6sx-mu-lp"; + reg = <0x02294000 0x4000>; + interrupts = <0 90 0x04>; + status = "okay"; + }; + uart6: serial@22a0000 { compatible = "fsl,imx6sx-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; @@ -1391,5 +1600,36 @@ power-domain-names = "pcie", "pcie_phy"; status = "disabled"; }; + + pcie_ep: pcie_ep@8ffc000 { + compatible = "fsl,imx6sx-pcie-ep"; + reg = <0x08ffc000 0x04000>, <0x08000000 0xf00000>; + reg-names = "regs", "addr_space"; + num-lanes = <1>; + clocks = <&clks IMX6SX_CLK_PCIE_AXI>, + <&clks IMX6SX_CLK_LVDS1_OUT>, + <&clks IMX6SX_CLK_PCIE_REF_125M>, + <&clks IMX6SX_CLK_DISPLAY_AXI>; + clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_inbound_axi"; + power-domains = <&pd_disp>, <&pd_pci>; + power-domain-names = "pcie", "pcie_phy"; + num-ib-windows = <4>; + num-ob-windows = <4>; + status = "disabled"; + }; + }; + + rpmsg: rpmsg{ + compatible = "fsl,imx6sx-rpmsg"; + /* up to now, the following channels are used in imx rpmsg + * - tx1/rx1: messages channel. + * - general interrupt1: remote proc finish re-init rpmsg stack + * when A core is partition reset. + */ + mbox-names = "tx", "rx", "rxdb"; + mboxes = <&mu 0 1 + &mu 1 1 + &mu 3 1>; + status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-btwifi-oob.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-btwifi-oob.dts new file mode 100644 index 000000000000..90e0045fa2e4 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-btwifi-oob.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ul-14x14-evk-btwifi.dts" +#include "imx6ul-evk-btwifi-oob.dtsi" diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-btwifi.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-btwifi.dts new file mode 100644 index 000000000000..4613799a97c7 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-btwifi.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ul-14x14-evk.dts" +#include "imx6ul-evk-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-csi.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-csi.dts new file mode 100644 index 000000000000..9a1f453551d6 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-csi.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2015 Freescale Semiconductor, Inc. + +#include "imx6ul-14x14-evk.dts" + + +&csi { + status = "okay"; +}; + +&ov5640 { + status = "okay"; +}; + +&sim2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-ecspi-slave.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-ecspi-slave.dts new file mode 100644 index 000000000000..16f82a32c2e2 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-ecspi-slave.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 NXP + +/* + * DTS file for ECSPI Slave Certification at i.mx6ul 14x14 evk board. + * NOTE: Because Ethernet2 use the same pins with ecspi4, so disable + * fec1/fec2 for ECSPI4 test. + */ + +#include "imx6ul-14x14-evk-ecspi.dts" + +/delete-node/&spidev0; + +&ecspi4 { + #address-cells = <0>; + spi-slave; +}; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-ecspi.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-ecspi.dts new file mode 100644 index 000000000000..7ca5e4224357 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-ecspi.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 NXP + +/* + * DTS file for ECSPI Certification at i.mx6ul 14x14 evk board. + * NOTE: Because Ethernet2 use the same pins with ecspi4, so disable + * fec1/fec2 for ECSPI4 test. + */ + +#include "imx6ul-14x14-evk.dts" + +&iomuxc { + pinctrl_ecspi4: ecspi4grp { + fsl,pins = < + MX6UL_PAD_ENET2_TX_DATA1__ECSPI4_SCLK 0x70a1 + MX6UL_PAD_ENET2_TX_EN__ECSPI4_MOSI 0x70a1 + MX6UL_PAD_ENET2_TX_CLK__ECSPI4_MISO 0x70a1 + MX6UL_PAD_ENET2_RX_ER__ECSPI4_SS0 0x70a1 + >; + }; +}; + +&ecspi4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi4>; + status = "okay"; + + spidev0: spi@0 { + reg = <0>; + compatible = "rohm,dh2228fv"; + spi-max-frequency = <20000000>; + }; +}; + +&fec1 { + status = "disabled"; +}; + +&fec2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-emmc.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-emmc.dts new file mode 100644 index 000000000000..bc4e53f25565 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-emmc.dts @@ -0,0 +1,21 @@ +/* + * Copyright 2019 NXP + * + * 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. + */ + +#include "imx6ul-14x14-evk.dts" + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2_8bit>; + pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-gpmi-weim.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-gpmi-weim.dts new file mode 100644 index 000000000000..b7fe014619d4 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-evk-gpmi-weim.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2015 Freescale Semiconductor, Inc. + +#include "imx6ul-14x14-evk.dts" + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand_1>; + status = "okay"; + nand-on-flash-bbt; +}; + +&iomuxc { + pinctrl_gpmi_nand_1: gpmi-nand-1 { + fsl,pins = < + MX6UL_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 + MX6UL_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 + MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 + MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 + MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 + MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 + MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 + MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 + MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 + MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 + MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 + MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 + MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 + MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 + MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 + MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 + >; + }; +}; + +&qspi { + status = "disabled"; +}; + +&usdhc2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi index aa86341adaaa..9c8e1c938340 100644 --- a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi +++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi @@ -12,6 +12,19 @@ reg = <0x80000000 0x20000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0xa000000>; + linux,cma-default; + }; + }; + backlight_display: backlight-display { compatible = "pwm-backlight"; pwms = <&pwm1 0 5000000>; @@ -20,6 +33,10 @@ status = "okay"; }; + pxp_v4l2 { + compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; reg_sd1_vmmc: regulator-sd1-vmmc { compatible = "regulator-fixed"; @@ -27,6 +44,7 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; enable-active-high; }; @@ -61,22 +79,63 @@ "LINPUT3", "Mic Jack", "RINPUT1", "Mic Jack", "RINPUT2", "Mic Jack"; + status = "disabled"; simple-audio-card,cpu { sound-dai = <&sai2>; + status = "disabled"; }; dailink_master: simple-audio-card,codec { sound-dai = <&codec>; clocks = <&clks IMX6UL_CLK_SAI2>; + status = "disabled"; }; }; + sound-wm8960 { + compatible = "fsl,imx6ul-evk-wm8960", + "fsl,imx-audio-wm8960"; + model = "wm8960-audio"; + cpu-dai = <&sai2>; + audio-codec = <&codec>; + asrc-controller = <&asrc>; + codec-master; + gpr = <&gpr 4 0x100000 0x100000>; + /* + * hp-det = <hp-det-pin hp-det-polarity>; + * hp-det-pin: JD1 JD2 or JD3 + * hp-det-polarity = 0: hp detect high for headphone + * hp-det-polarity = 1: hp detect high for speaker + */ + hp-det = <3 0>; + hp-det-gpios = <&gpio5 4 0>; + mic-det-gpios = <&gpio5 4 0>; + audio-routing = + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "LINPUT2", "Mic Jack", + "LINPUT3", "Mic Jack", + "RINPUT1", "Main MIC", + "RINPUT2", "Main MIC", + "Mic Jack", "MICB", + "Main MIC", "MICB", + "CPU-Playback", "ASRC-Playback", + "Playback", "CPU-Playback", + "ASRC-Capture", "CPU-Capture", + "CPU-Capture", "Capture"; + }; + spi4 { compatible = "spi-gpio"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi4>; status = "okay"; + pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; gpio-sck = <&gpio5 11 0>; gpio-mosi = <&gpio5 10 0>; cs-gpios = <&gpio5 7 0>; @@ -90,20 +149,10 @@ #gpio-cells = <2>; reg = <0>; registers-number = <1>; + registers-default = /bits/ 8 <0x57>; spi-max-frequency = <100000>; }; }; - - panel { - compatible = "innolux,at043tn24"; - backlight = <&backlight_display>; - - port { - panel_in: endpoint { - remote-endpoint = <&display_out>; - }; - }; - }; }; &clks { @@ -111,6 +160,16 @@ assigned-clock-rates = <786432000>; }; +&csi { + status = "disabled"; + + port { + csi1_ep: endpoint { + remote-endpoint = <&ov5640_ep>; + }; + }; +}; + &i2c2 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -122,6 +181,28 @@ compatible = "wlf,wm8960"; reg = <0x1a>; wlf,shared-lrclk; + clocks = <&clks IMX6UL_CLK_SAI2>; + clock-names = "mclk"; + }; + + ov5640: ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi1>; + clocks = <&clks IMX6UL_CLK_CSI>; + clock-names = "csi_mclk"; + pwn-gpios = <&gpio_spi 6 1>; + rst-gpios = <&gpio_spi 5 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + status = "disabled"; + port { + ov5640_ep: endpoint { + remote-endpoint = <&csi1_ep>; + }; + }; }; }; @@ -183,6 +264,15 @@ mag3110@e { compatible = "fsl,mag3110"; reg = <0x0e>; + position = <2>; + }; + + fxls8471@1e { + compatible = "fsl,fxls8471"; + reg = <0x1e>; + position = <0>; + interrupt-parent = <&gpio5>; + interrupts = <0 8>; }; }; @@ -192,11 +282,31 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcdif_dat &pinctrl_lcdif_ctrl>; + display = <&display0>; status = "okay"; - port { - display_out: endpoint { - remote-endpoint = <&panel_in>; + display0: display@0 { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0 { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; }; }; }; @@ -207,6 +317,10 @@ status = "okay"; }; +&pxp { + status = "okay"; +}; + &qspi { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_qspi>; @@ -242,6 +356,22 @@ status = "okay"; }; +&sim2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sim2>; + assigned-clocks = <&clks IMX6UL_CLK_SIM_SEL>; + assigned-clock-parents = <&clks IMX6UL_CLK_SIM_PODF>; + assigned-clock-rates = <240000000>; + /* GPIO_ACTIVE_HIGH/LOW:sim card voltage control + * NCN8025:Vcc = ACTIVE_HIGH?5V:3V + * TDA8035:Vcc = ACTIVE_HIGH?5V:1.8V + */ + pinctrl-assert-gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>; + port = <1>; + sven_low_active; + status = "okay"; +}; + &tsc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tsc>; @@ -261,11 +391,16 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart2>; uart-has-rtscts; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart2dte>; */ status = "okay"; }; &usbotg1 { dr_mode = "otg"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_otg1>; status = "okay"; }; @@ -298,7 +433,7 @@ &usdhc2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc2>; - no-1-8-v; + non-removable; keep-power-in-suspend; wakeup-source; status = "okay"; @@ -499,10 +634,25 @@ >; }; + pinctrl_uart2dte: uart2dtegrp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS 0x1b0b1 + MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS 0x1b0b1 + >; + }; + + pinctrl_usb_otg1: usbotg1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x17059 + >; + }; + pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 - MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071 MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 @@ -547,6 +697,51 @@ >; }; + pinctrl_usdhc2_8bit: usdhc2grp_8bit { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10069 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059 + MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x17059 + MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x17059 + MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x17059 + MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x17059 + >; + }; + + pinctrl_usdhc2_8bit_100mhz: usdhc2grp_8bit_100mhz { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100b9 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170b9 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9 + MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170b9 + MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170b9 + MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170b9 + MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc2_8bit_200mhz: usdhc2grp_8bit_200mhz { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100f9 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170f9 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9 + MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170f9 + MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170f9 + MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170f9 + MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170f9 + >; + }; + pinctrl_wdog: wdoggrp { fsl,pins = < MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0 diff --git a/arch/arm/boot/dts/imx6ul-9x9-evk-btwifi-oob.dts b/arch/arm/boot/dts/imx6ul-9x9-evk-btwifi-oob.dts new file mode 100644 index 000000000000..8a8ece34d775 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-9x9-evk-btwifi-oob.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ul-9x9-evk-btwifi.dts" +#include "imx6ul-evk-btwifi-oob.dtsi" diff --git a/arch/arm/boot/dts/imx6ul-9x9-evk-btwifi.dts b/arch/arm/boot/dts/imx6ul-9x9-evk-btwifi.dts new file mode 100644 index 000000000000..de89052d97fc --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-9x9-evk-btwifi.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ul-9x9-evk.dts" +#include "imx6ul-evk-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6ul-9x9-evk-ldo.dts b/arch/arm/boot/dts/imx6ul-9x9-evk-ldo.dts new file mode 100644 index 000000000000..715efcb9512e --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-9x9-evk-ldo.dts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ul-9x9-evk.dts" + +&cpu0 { + operating-points = < + /* kHz uV */ + 696000 1275000 + 528000 1175000 + 396000 1025000 + 198000 950000 + >; + fsl,soc-operating-points = < + /* KHz uV */ + 696000 1275000 + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,arm-soc-shared = <0>; +}; + +&gpc { + fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6ul-9x9-evk.dts b/arch/arm/boot/dts/imx6ul-9x9-evk.dts new file mode 100644 index 000000000000..4350a2f4b257 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-9x9-evk.dts @@ -0,0 +1,813 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/dts-v1/; + +#include <dt-bindings/input/input.h> +#include "imx6ul.dtsi" + +/ { + model = "Freescale i.MX6 UltraLite 9x9 EVK Board"; + compatible = "fsl,imx6ul-9x9-evk", "fsl,imx6ul"; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + status = "okay"; + }; + + chosen { + stdout-path = &uart1; + }; + + memory { + reg = <0x80000000 0x10000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0xa000000>; + linux,cma-default; + }; + }; + + pxp_v4l2 { + compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_can_3v3: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "can-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio_spi 3 GPIO_ACTIVE_LOW>; + }; + + reg_gpio_dvfs: regulator-gpio { + compatible = "regulator-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvfs>; + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1400000>; + regulator-name = "gpio_dvfs"; + regulator-type = "voltage"; + gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>; + states = <1300000 0x1 1400000 0x0>; + }; + + reg_sd1_vmmc: regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6ul-evk-wm8960", + "fsl,imx-audio-wm8960"; + model = "wm8960-audio"; + cpu-dai = <&sai2>; + audio-codec = <&codec>; + asrc-controller = <&asrc>; + codec-master; + gpr = <&gpr 4 0x100000 0x100000>; + /* + * hp-det = <hp-det-pin hp-det-polarity>; + * hp-det-pin: JD1 JD2 or JD3 + * hp-det-polarity = 0: hp detect high for headphone + * hp-det-polarity = 1: hp detect high for speaker + */ + hp-det = <3 0>; + hp-det-gpios = <&gpio5 4 0>; + mic-det-gpios = <&gpio5 4 0>; + audio-routing = + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "LINPUT2", "Mic Jack", + "LINPUT3", "Mic Jack", + "RINPUT1", "Main MIC", + "RINPUT2", "Main MIC", + "Mic Jack", "MICB", + "Main MIC", "MICB", + "CPU-Playback", "ASRC-Playback", + "Playback", "CPU-Playback", + "ASRC-Capture", "CPU-Capture", + "CPU-Capture", "Capture"; + }; + + spi4 { + compatible = "spi-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi4>; + pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; + status = "okay"; + gpio-sck = <&gpio5 11 0>; + gpio-mosi = <&gpio5 10 0>; + cs-gpios = <&gpio5 7 0>; + num-chipselects = <1>; + #address-cells = <1>; + #size-cells = <0>; + + gpio_spi: gpio_spi@0 { + compatible = "fairchild,74hc595"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + registers-number = <1>; + registers-default = /bits/ 8 <0x57>; + spi-max-frequency = <100000>; + }; + }; +}; + +&clks { + assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <786432000>; +}; + +&cpu0 { + /* + * on i.MX6UL, no seperated VDD_ARM_IN and VDD_SOC_IN, + * to align with other platform and use the same cpufreq + * driver, still use the seperated OPP define for arm + * and soc. + */ + operating-points = < + /* kHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,soc-operating-points = < + /* KHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,arm-soc-shared = <1>; +}; + +®_arm { + vin-supply = <&sw1c_reg>; + regulator-allow-bypass; +}; + +®_soc { + vin-supply = <&sw1c_reg>; + regulator-allow-bypass; +}; + +&csi { + status = "disabled"; + + port { + csi1_ep: endpoint { + remote-endpoint = <&ov5640_ep>; + }; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + phy-mode = "rmii"; + phy-handle = <ðphy0>; + status = "okay"; +}; + +&fec2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet2>; + phy-mode = "rmii"; + phy-handle = <ðphy1>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&gpc { + fsl,cpu_pupscr_sw2iso = <0xf>; + fsl,cpu_pupscr_sw = <0x0>; + fsl,cpu_pdnscr_iso2sw = <0x1>; + fsl,cpu_pdnscr_iso = <0x1>; + fsl,ldo-bypass = <1>; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: pfuze3000@8 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + regulator-always-on; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + mag3110@e { + compatible = "fsl,mag3110"; + reg = <0x0e>; + position = <2>; + }; + + fxls8471@1e { + compatible = "fsl,fxls8471"; + reg = <0x1e>; + position = <0>; + interrupt-parent = <&gpio5>; + interrupts = <0 8>; + }; +}; + +&i2c2 { + clock_frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + codec: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + clocks = <&clks IMX6UL_CLK_SAI2>; + clock-names = "mclk"; + wlf,shared-lrclk; + }; + + ov5640: ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi1>; + clocks = <&clks IMX6UL_CLK_CSI>; + clock-names = "csi_mclk"; + pwn-gpios = <&gpio_spi 6 1>; + rst-gpios = <&gpio_spi 5 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + status = "disabled"; + port { + ov5640_ep: endpoint { + remote-endpoint = <&csi1_ep>; + }; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog_1>; + imx6ul-evk { + pinctrl_csi1: csi1grp { + fsl,pins = < + MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088 + MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088 + MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088 + MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088 + MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088 + MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088 + MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088 + MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088 + MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088 + MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088 + MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088 + MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088 + >; + }; + + pinctrl_dvfs: dvfsgrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x79 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 + MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0 + MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0 + MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 + MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 + MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0 + MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031 + MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x80000000 + >; + }; + + pinctrl_flexcan1: flexcan1grp{ + fsl,pins = < + MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020 + MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020 + >; + }; + + pinctrl_flexcan2: flexcan2grp{ + fsl,pins = < + MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020 + MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020 + >; + }; + + pinctrl_hog_1: hoggrp-1 { + fsl,pins = < + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */ + MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */ + MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */ + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0 + MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0 + MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0 + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 + MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 + MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 + MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 + /* used for lcd reset */ + MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79 + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 + MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 + MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 + MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 + MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 + MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 + MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 + MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 + MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 + MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 + MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 + MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 + MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 + MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 + MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 + MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 + MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 + MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 + MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79 + MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79 + MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79 + MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79 + MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79 + MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 + >; + }; + + pinctrl_qspi: qspigrp { + fsl,pins = < + MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK 0x70a1 + MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x70a1 + MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01 0x70a1 + MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02 0x70a1 + MX6UL_PAD_NAND_CLE__QSPI_A_DATA03 0x70a1 + MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B 0x70a1 + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088 + MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088 + MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088 + MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x11088 + MX6UL_PAD_JTAG_TMS__SAI2_MCLK 0x17088 + MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x17059 + >; + }; + + pinctrl_sim2_1: sim2grp-1 { + fsl,pins = < + MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD 0xb808 + MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK 0x31 + MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B 0xb808 + MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN 0xb808 + MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD 0xb809 + MX6UL_PAD_CSI_DATA02__GPIO4_IO23 0x3008 + >; + }; + + pinctrl_spi4: spi4grp { + fsl,pins = < + MX6UL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1 + MX6UL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1 + MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1 + MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000 + >; + }; + + pinctrl_tsc: tscgrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 + MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0 + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0 + MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 + MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1 + MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1 + >; + }; + + pinctrl_uart2dte: uart2dtegrp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS 0x1b0b1 + MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS 0x1b0b1 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x17059 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0 + >; + }; + }; +}; + +&lcdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcdif_dat + &pinctrl_lcdif_ctrl>; + display = <&display0>; + status = "okay"; + + display0: display { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&pxp { + status = "okay"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "okay"; + ddrsmp=<0>; + + flash0: n25q256a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a"; + spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; + reg = <0>; + }; +}; + +&sai2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2>; + + assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>, + <&clks IMX6UL_CLK_SAI2>; + assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <0>, <12288000>; + + status = "okay"; +}; + +&sim2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sim2_1>; + assigned-clocks = <&clks IMX6UL_CLK_SIM_SEL>; + assigned-clock-parents = <&clks IMX6UL_CLK_SIM_PODF>; + assigned-clock-rates = <240000000>; + pinctrl-assert-gpios = <&gpio4 23 GPIO_ACTIVE_LOW>; + port = <1>; + sven_low_active; + status = "okay"; +}; + +&tsc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc>; + xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; + measure_delay_time = <0xffff>; + pre_charge_time = <0xfff>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + fsl,uart-has-rtscts; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart2dte>; */ + status = "okay"; +}; + +&usbotg1 { + dr_mode = "otg"; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usbotg2 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd1_vmmc>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + no-1-8-v; + non-removable; + keep-power-in-suspend; + enable-sdio-wakeup; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; diff --git a/arch/arm/boot/dts/imx6ul-evk-btwifi-oob.dtsi b/arch/arm/boot/dts/imx6ul-evk-btwifi-oob.dtsi new file mode 100644 index 000000000000..e1f16574a24e --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-evk-btwifi-oob.dtsi @@ -0,0 +1,30 @@ +/* + * Copyright 2017-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +&pinctrl_wifi { + fsl,pins = < + /* MUXing for WL_HOST_WAKE */ + MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15 0x0b001 /* input: 100K Pull-up */ + >; +}; + +/* + * For WL_HOST_WAKE (OOB_IRQ) to function correctly, we must disable + * the secondary ethernet port (FEC2). Hardware re-work is to remove + * R1633 and populate R1704 with 0 Ohm resistor. + * Refer to Murata Hardware Reference Manual for more details. + */ +&fec2 { + status = "disabled"; +}; + +&brcmf { + interrupt-parent = <&gpio2>; + interrupts = <15 IRQ_TYPE_LEVEL_LOW>; /* M.2 WL_HOST_WAKE is active low */ + interrupt-names = "host-wake"; +}; diff --git a/arch/arm/boot/dts/imx6ul-evk-btwifi.dtsi b/arch/arm/boot/dts/imx6ul-evk-btwifi.dtsi new file mode 100644 index 000000000000..b3dfefec7fae --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-evk-btwifi.dtsi @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * NOTE: This DTS file is written for plugging in Murata Wi-Fi/BT EVK into Slot + * SD1 and using Murata i.MX InterConnect Ver 2.0 Adapter. Bluetooth UART & + * control signals are connected via ribbon cable (J1701 connector). + */ + +/ { + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio_spi 4 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + usdhc1_pwrseq: usdhc1_pwrseq { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wifi>; + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + }; +}; + +&iomuxc { + pinctrl_wifi: wifigrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x03029 + >; + }; +}; + +®_sd1_vmmc { + regulator-always-on; +}; + +&uart2 { + resets = <&modem_reset>; +}; + +&usdhc1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + no-1-8-v; + non-removable; + pm-ignore-notify; + mmc-pwrseq = <&usdhc1_pwrseq>; + cap-power-off-card; + /delete-property/ wakeup-source; + /delete-property/ enable-sdio-wakeup; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&gpio_spi { + /* Murata: modify default setting so that BT_nPWD/BT_REG_ON + * is low (0V) during kernel boot. + */ + registers-default = /bits/ 8 <0x47>; +}; diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi index f008036e9294..3a9985cb0dd9 100644 --- a/arch/arm/boot/dts/imx6ul.dtsi +++ b/arch/arm/boot/dts/imx6ul.dtsi @@ -82,10 +82,15 @@ <&clks IMX6UL_CA7_SECONDARY_SEL>, <&clks IMX6UL_CLK_STEP>, <&clks IMX6UL_CLK_PLL1_SW>, - <&clks IMX6UL_CLK_PLL1_SYS>; + <&clks IMX6UL_CLK_PLL1_SYS>, + <&clks IMX6UL_PLL1_BYPASS>, + <&clks IMX6UL_CLK_PLL1>, + <&clks IMX6UL_PLL1_BYPASS_SRC>, + <&clks IMX6UL_CLK_OSC>; clock-names = "arm", "pll2_bus", "pll2_pfd2_396m", "secondary_sel", "step", "pll1_sw", - "pll1_sys"; + "pll1_sys", "pll1_bypass", "pll1", + "pll1_bypass_src", "osc"; arm-supply = <®_arm>; soc-supply = <®_soc>; nvmem-cells = <&cpu_speed_grade>; @@ -154,9 +159,43 @@ interrupt-parent = <&gpc>; ranges; - ocram: sram@900000 { + busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6UL_CLK_PLL2_PFD2>, <&clks IMX6UL_CLK_PLL2_198M>, + <&clks IMX6UL_CLK_PLL2_BUS>, <&clks IMX6UL_CLK_ARM>, + <&clks IMX6UL_CLK_PLL3_USB_OTG>, <&clks IMX6UL_CLK_PERIPH>, + <&clks IMX6UL_CLK_PERIPH_PRE>, <&clks IMX6UL_CLK_PERIPH_CLK2>, + <&clks IMX6UL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6UL_CLK_OSC>, + <&clks IMX6UL_CLK_AHB>, <&clks IMX6UL_CLK_AXI>, + <&clks IMX6UL_CLK_PERIPH2>, <&clks IMX6UL_CLK_PERIPH2_PRE>, + <&clks IMX6UL_CLK_PERIPH2_CLK2>, <&clks IMX6UL_CLK_PERIPH2_CLK2_SEL>, + <&clks IMX6UL_CLK_STEP>, <&clks IMX6UL_CLK_MMDC_P0_FAST>; + clock-names = "pll2_pfd2_396m", "pll2_198m", "pll2_bus", "arm", "pll3_usb_otg", + "periph", "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", + "ahb", "ocram", "periph2", "periph2_pre", "periph2_clk2", "periph2_clk2_sel", + "step", "mmdc"; + fsl,max_ddr_freq = <400000000>; + }; + + ocrams: sram@900000 { + compatible = "fsl,lpm-sram"; + reg = <0x900000 0x4000>; + }; + + ocrams_ddr: sram@904000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x904000 0x1000>; + }; + + ocram: sram@905000 { compatible = "mmio-sram"; - reg = <0x00900000 0x20000>; + reg = <0x00905000 0x1B000>; + }; + + ocram_optee: sram@918000 { + compatible = "fsl,optee-lpm-sram"; + reg = <0x918000 0x8000>; + overw_reg = <&ocram 0x905000 0x13000>; }; intc: interrupt-controller@a01000 { @@ -184,6 +223,11 @@ clocks = <&clks IMX6UL_CLK_APBHDMA>; }; + caam_sm: caam-sm@100000 { + compatible = "fsl,imx7d-caam-sm", "fsl,imx6q-caam-sm"; + reg = <0x100000 0x8000>; + }; + gpmi: gpmi-nand@1806000 { compatible = "fsl,imx6q-gpmi-nand"; #address-cells = <1>; @@ -351,6 +395,31 @@ dma-names = "rx", "tx"; status = "disabled"; }; + + asrc: asrc@2034000 { + compatible = "fsl,imx53-asrc"; + reg = <0x2034000 0x4000>; + interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6UL_CLK_ASRC_IPG>, + <&clks IMX6UL_CLK_ASRC_MEM>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks IMX6UL_CLK_SPDIF>, <&clks 0>, <&clks 0>, + <&clks IMX6UL_CLK_SPBA>; + clock-names = "mem", "ipg", "asrck_0", + "asrck_1", "asrck_2", "asrck_3", "asrck_4", + "asrck_5", "asrck_6", "asrck_7", "asrck_8", + "asrck_9", "asrck_a", "asrck_b", "asrck_c", + "asrck_d", "asrck_e", "asrck_f", "spba"; + dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, + <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; + dma-names = "rxa", "rxb", "rxc", + "txa", "txb", "txc"; + fsl,asrc-rate = <48000>; + fsl,asrc-width = <16>; + status = "okay"; + }; }; tsc: tsc@2040000 { @@ -520,6 +589,9 @@ "enet_clk_ref", "enet_out"; fsl,num-tx-queues = <1>; fsl,num-rx-queues = <1>; + stop-mode = <&gpr 0x10 4>; + fsl,magic-packet; + fsl,wakeup_irq = <0>; status = "disabled"; }; @@ -631,6 +703,20 @@ fsl,anatop = <&anatop>; }; + irq_sec_vio: caam_secvio { + compatible = "fsl,imx6q-caam-secvio"; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + jtag-tamper = "disabled"; + watchdog-tamper = "enabled"; + internal-boot-tamper = "enabled"; + external-pin-tamper = "disabled"; + }; + + caam_snvs: caam-snvs@20cc000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x20cc000 0x4000>; + }; + snvs: snvs@20cc000 { compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; reg = <0x020cc000 0x4000>; @@ -691,6 +777,7 @@ #interrupt-cells = <3>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&intc>; + fsl,mf-mix-wakeup-irq = <0x7c00000 0x7d00 0x0 0x1400640>; }; iomuxc: iomuxc@20e0000 { @@ -855,6 +942,16 @@ "enet_clk_ref", "enet_out"; fsl,num-tx-queues = <1>; fsl,num-rx-queues = <1>; + stop-mode = <&gpr 0x10 3>; + fsl,magic-packet; + fsl,wakeup_irq = <0>; + status = "disabled"; + }; + + sim1: sim@0218c000 { + compatible = "fsl,imx6ul-sim"; + reg = <0x0218c000 0x4000>; + interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; @@ -934,6 +1031,15 @@ clocks = <&clks IMX6UL_CLK_MMDC_P0_IPG>; }; + sim2: sim@021b4000 { + compatible = "fsl,imx6ul-sim"; + reg = <0x021b4000 0x4000>; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6UL_CLK_SIM2>; + clock-names = "sim"; + status = "disabled"; + }; + weim: weim@21b8000 { #address-cells = <2>; #size-cells = <1>; @@ -966,11 +1072,13 @@ }; csi: csi@21c4000 { - compatible = "fsl,imx6ul-csi", "fsl,imx7-csi"; + compatible = "fsl,imx6ul-csi", "fsl,imx7-csi", "fsl,imx6s-csi"; reg = <0x021c4000 0x4000>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6UL_CLK_CSI>; - clock-names = "mclk"; + clocks = <&clks IMX6UL_CLK_DUMMY>, + <&clks IMX6UL_CLK_CSI>, + <&clks IMX6UL_CLK_DUMMY>; + clock-names = "disp-axi", "csi_mclk", "disp_dcic"; status = "disabled"; }; @@ -986,11 +1094,13 @@ }; pxp: pxp@21cc000 { - compatible = "fsl,imx6ul-pxp"; - reg = <0x021cc000 0x4000>; + compatible = "fsl,imx6ul-pxp-dma", "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; + reg = <0x21cc000 0x4000>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6UL_CLK_PXP>; - clock-names = "axi"; + clocks = <&clks IMX6UL_CLK_PXP>, + <&clks IMX6UL_CLK_DUMMY>; + clock-names = "pxp-axi", "disp-axi"; + status = "disabled"; }; qspi: spi@21e0000 { diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-btwifi-oob.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-btwifi-oob.dts new file mode 100644 index 000000000000..85ea147de16f --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-14x14-evk-btwifi-oob.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ull-14x14-evk-btwifi.dts" +#include "imx6ul-evk-btwifi-oob.dtsi" diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-btwifi.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-btwifi.dts new file mode 100644 index 000000000000..8a0a85d2e197 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-14x14-evk-btwifi.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ull-14x14-evk.dts" +#include "imx6ul-evk-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-emmc.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-emmc.dts new file mode 100644 index 000000000000..d6dc9121b747 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-14x14-evk-emmc.dts @@ -0,0 +1,21 @@ +/* + * Copyright 2019 NXP + * + * 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. + */ + +#include "imx6ull-14x14-evk.dts" + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2_8bit>; + pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-gpmi-weim.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-gpmi-weim.dts new file mode 100644 index 000000000000..4391182e613c --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-14x14-evk-gpmi-weim.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2016 Freescale Semiconductor, Inc. + +#include "imx6ull-14x14-evk.dts" + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand_1>; + status = "okay"; + nand-on-flash-bbt; +}; + +&iomuxc { + pinctrl_gpmi_nand_1: gpmi-nand-1 { + fsl,pins = < + MX6UL_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 + MX6UL_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 + MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 + MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 + MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 + MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 + MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 + MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 + MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 + MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 + MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 + MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 + MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 + MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 + MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 + MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 + >; + }; +}; + +&qspi { + status = "disabled"; +}; + +&usdhc2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk.dts b/arch/arm/boot/dts/imx6ull-14x14-evk.dts index 74aaa8a56a3d..bb8f91034db4 100644 --- a/arch/arm/boot/dts/imx6ull-14x14-evk.dts +++ b/arch/arm/boot/dts/imx6ull-14x14-evk.dts @@ -8,11 +8,22 @@ #include "imx6ul-14x14-evk.dtsi" / { - model = "Freescale i.MX6 UltraLiteLite 14x14 EVK Board"; + model = "Freescale i.MX6 ULL 14x14 EVK Board"; compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull"; }; &clks { - assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>; - assigned-clock-rates = <320000000>; + assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>, + <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <320000000>, <786432000>; }; + +&csi { + status = "okay"; +}; + +&ov5640 { + status = "okay"; +}; + +/delete-node/ &sim2; diff --git a/arch/arm/boot/dts/imx6ull-9x9-evk-btwifi-oob.dts b/arch/arm/boot/dts/imx6ull-9x9-evk-btwifi-oob.dts new file mode 100644 index 000000000000..8d00a908ee94 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-9x9-evk-btwifi-oob.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ull-9x9-evk-btwifi.dts" +#include "imx6ul-evk-btwifi-oob.dtsi" diff --git a/arch/arm/boot/dts/imx6ull-9x9-evk-btwifi.dts b/arch/arm/boot/dts/imx6ull-9x9-evk-btwifi.dts new file mode 100644 index 000000000000..c8a51006213f --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-9x9-evk-btwifi.dts @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ull-9x9-evk.dts" +#include "imx6ul-evk-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6ull-9x9-evk-ldo.dts b/arch/arm/boot/dts/imx6ull-9x9-evk-ldo.dts new file mode 100644 index 000000000000..a878fe5bbb78 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-9x9-evk-ldo.dts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx6ull-9x9-evk.dts" +&cpu0 { + operating-points = < + /* kHz uV */ + 528000 1175000 + 396000 1025000 + 198000 950000 + >; + fsl,soc-operating-points = < + /* KHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,arm-soc-shared = <0>; +}; + +&gpc { + fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ +}; + +®_arm { + /delete-property/ vin-supply; +}; + +®_soc { + /delete-property/ vin-supply; +}; diff --git a/arch/arm/boot/dts/imx6ull-9x9-evk.dts b/arch/arm/boot/dts/imx6ull-9x9-evk.dts new file mode 100644 index 000000000000..9514086b21c8 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-9x9-evk.dts @@ -0,0 +1,813 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/dts-v1/; + +#include <dt-bindings/input/input.h> +#include "imx6ull.dtsi" + +/ { + model = "Freescale i.MX6 ULL 9x9 EVK Board"; + compatible = "fsl,imx6ull-9x9-evk", "fsl,imx6ull"; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + status = "okay"; + }; + + chosen { + stdout-path = &uart1; + }; + + memory { + reg = <0x80000000 0x10000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0xa000000>; + linux,cma-default; + }; + }; + + pxp_v4l2 { + compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_can_3v3: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "can-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio_spi 3 GPIO_ACTIVE_LOW>; + }; + + reg_gpio_dvfs: regulator-gpio { + compatible = "regulator-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvfs>; + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1400000>; + regulator-name = "gpio_dvfs"; + regulator-type = "voltage"; + gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>; + states = <1300000 0x1 1400000 0x0>; + }; + + reg_sd1_vmmc: regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6ul-evk-wm8960", + "fsl,imx-audio-wm8960"; + model = "wm8960-audio"; + cpu-dai = <&sai2>; + audio-codec = <&codec>; + asrc-controller = <&asrc>; + codec-master; + gpr = <&gpr 4 0x100000 0x100000>; + /* + * hp-det = <hp-det-pin hp-det-polarity>; + * hp-det-pin: JD1 JD2 or JD3 + * hp-det-polarity = 0: hp detect high for headphone + * hp-det-polarity = 1: hp detect high for speaker + */ + hp-det = <3 0>; + hp-det-gpios = <&gpio5 4 0>; + mic-det-gpios = <&gpio5 4 0>; + audio-routing = + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "LINPUT2", "Mic Jack", + "LINPUT3", "Mic Jack", + "RINPUT1", "Main MIC", + "RINPUT2", "Main MIC", + "Mic Jack", "MICB", + "Main MIC", "MICB", + "CPU-Playback", "ASRC-Playback", + "Playback", "CPU-Playback", + "ASRC-Capture", "CPU-Capture", + "CPU-Capture", "Capture"; + }; + + spi4 { + compatible = "spi-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi4>; + pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; + status = "okay"; + gpio-sck = <&gpio5 11 0>; + gpio-mosi = <&gpio5 10 0>; + cs-gpios = <&gpio5 7 0>; + num-chipselects = <1>; + #address-cells = <1>; + #size-cells = <0>; + + gpio_spi: gpio_spi@0 { + compatible = "fairchild,74hc595"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + registers-number = <1>; + registers-default = /bits/ 8 <0x57>; + spi-max-frequency = <100000>; + }; + }; +}; + +&clks { + assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <786432000>; +}; + +&cpu0 { + /* + * on i.MX6ULL, no seperated VDD_ARM_IN and VDD_SOC_IN, + * to align with other platform and use the same cpufreq + * driver, still use the seperated OPP define for arm + * and soc. + */ + operating-points = < + /* kHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,soc-operating-points = < + /* KHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,arm-soc-shared = <1>; +}; + +®_arm { + vin-supply = <&sw1c_reg>; + regulator-allow-bypass; +}; + +®_soc { + vin-supply = <&sw1c_reg>; + regulator-allow-bypass; +}; + +&csi { + status = "okay"; + + port { + csi1_ep: endpoint { + remote-endpoint = <&ov5640_ep>; + }; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + phy-mode = "rmii"; + phy-handle = <ðphy0>; + status = "okay"; +}; + +&fec2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet2>; + phy-mode = "rmii"; + phy-handle = <ðphy1>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&gpc { + fsl,cpu_pupscr_sw2iso = <0xf>; + fsl,cpu_pupscr_sw = <0x0>; + fsl,cpu_pdnscr_iso2sw = <0x1>; + fsl,cpu_pdnscr_iso = <0x1>; + fsl,ldo-bypass = <1>; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: pfuze3000@8 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + regulator-always-on; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + mag3110@e { + compatible = "fsl,mag3110"; + reg = <0x0e>; + position = <2>; + }; + + fxls8471@1e { + compatible = "fsl,fxls8471"; + reg = <0x1e>; + position = <0>; + interrupt-parent = <&gpio5>; + interrupts = <0 8>; + }; +}; + +&i2c2 { + clock_frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + codec: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + clocks = <&clks IMX6UL_CLK_SAI2>; + clock-names = "mclk"; + wlf,shared-lrclk; + }; + + ov5640: ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi1>; + clocks = <&clks IMX6UL_CLK_CSI>; + clock-names = "csi_mclk"; + pwn-gpios = <&gpio_spi 6 1>; + rst-gpios = <&gpio_spi 5 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + status = "okay"; + port { + ov5640_ep: endpoint { + remote-endpoint = <&csi1_ep>; + }; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog_1>; + imx6ul-evk { + pinctrl_csi1: csi1grp { + fsl,pins = < + MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088 + MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088 + MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088 + MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088 + MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088 + MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088 + MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088 + MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088 + MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088 + MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088 + MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088 + MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 + MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0 + MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0 + MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 + MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 + MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0 + MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031 + >; + }; + + pinctrl_flexcan1: flexcan1grp{ + fsl,pins = < + MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020 + MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020 + >; + }; + + pinctrl_flexcan2: flexcan2grp{ + fsl,pins = < + MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020 + MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020 + >; + }; + + pinctrl_hog_1: hoggrp-1 { + fsl,pins = < + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */ + MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */ + MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */ + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0 + MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0 + MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0 + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 + MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 + MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 + MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 + MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 + MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 + MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 + MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 + MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 + MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 + MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 + MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 + MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 + MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 + MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 + MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 + MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 + MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 + MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 + MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 + MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 + MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79 + MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79 + MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79 + MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79 + MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79 + MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 + >; + }; + + pinctrl_qspi: qspigrp { + fsl,pins = < + MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK 0x70a1 + MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x70a1 + MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01 0x70a1 + MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02 0x70a1 + MX6UL_PAD_NAND_CLE__QSPI_A_DATA03 0x70a1 + MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B 0x70a1 + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088 + MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088 + MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088 + MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x11088 + MX6UL_PAD_JTAG_TMS__SAI2_MCLK 0x17088 + >; + }; + + pinctrl_tsc: tscgrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 + MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0 + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0 + MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 + MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1 + MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1 + >; + }; + + pinctrl_uart2dte: uart2dtegrp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS 0x1b0b1 + MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS 0x1b0b1 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x17059 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0 + >; + }; + }; +}; + +&iomuxc_snvs { + pinctrl-names = "default_snvs"; + pinctrl-0 = <&pinctrl_hog_2>; + imx6ull-evk { + pinctrl_hog_2: hoggrp-2 { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x80000000 + >; + }; + + pinctrl_dvfs: dvfsgrp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x79 + >; + }; + + pinctrl_lcdif_reset: lcdifresetgrp { + fsl,pins = < + /* used for lcd reset */ + MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79 + >; + }; + + pinctrl_spi4: spi4grp { + fsl,pins = < + MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1 + MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1 + MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1 + MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000 + >; + }; + + pinctrl_sai2_hp_det_b: sai2_hp_det_grp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x17059 + >; + }; + }; +}; + +&lcdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcdif_dat + &pinctrl_lcdif_ctrl + &pinctrl_lcdif_reset>; + display = <&display0>; + status = "okay"; + + display0: display { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&pxp { + status = "okay"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "okay"; + ddrsmp=<0>; + + flash0: n25q256a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a"; + spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; + reg = <0>; + }; +}; + +&sai2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2 + &pinctrl_sai2_hp_det_b>; + + assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>, + <&clks IMX6UL_CLK_SAI2>; + assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <0>, <12288000>; + + status = "okay"; +}; + +&tsc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc>; + xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; + measure_delay_time = <0xffff>; + pre_charge_time = <0xfff>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + fsl,uart-has-rtscts; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart2dte>; */ + status = "okay"; +}; + +&usbotg1 { + dr_mode = "otg"; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usbotg2 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd1_vmmc>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + no-1-8-v; + non-removable; + keep-power-in-suspend; + enable-sdio-wakeup; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; diff --git a/arch/arm/boot/dts/imx6ull.dtsi b/arch/arm/boot/dts/imx6ull.dtsi index b7e67d121322..f9ce39bf55be 100644 --- a/arch/arm/boot/dts/imx6ull.dtsi +++ b/arch/arm/boot/dts/imx6ull.dtsi @@ -13,6 +13,7 @@ &cpu0 { clock-frequency = <900000000>; + fsl,low-power-run; operating-points = < /* kHz uV */ 900000 1275000 @@ -36,21 +37,50 @@ }; &pxp { - compatible = "fsl,imx6ull-pxp"; + compatible = "fsl,imx6ull-pxp-dma", "fsl,imx7d-pxp-dma"; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>; + <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_PXP>; + clock-names = "pxp_ipg", "pxp_axi"; + status = "disabled"; }; &usdhc1 { compatible = "fsl,imx6ull-usdhc", "fsl,imx6sx-usdhc"; + assigned-clocks = <&clks IMX6UL_CLK_USDHC1_SEL>, <&clks IMX6UL_CLK_USDHC1>; + assigned-clock-parents = <&clks IMX6UL_CLK_PLL2_PFD2>; + assigned-clock-rates = <0>, <132000000>; }; &usdhc2 { compatible = "fsl,imx6ull-usdhc", "fsl,imx6sx-usdhc"; + assigned-clocks = <&clks IMX6UL_CLK_USDHC2_SEL>, <&clks IMX6UL_CLK_USDHC2>; + assigned-clock-parents = <&clks IMX6UL_CLK_PLL2_PFD2>; + assigned-clock-rates = <0>, <132000000>; }; / { soc { + busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6UL_CLK_PLL2_PFD2>, <&clks IMX6UL_CLK_PLL2_198M>, + <&clks IMX6UL_CLK_PLL2_BUS>, <&clks IMX6UL_CLK_ARM>, + <&clks IMX6UL_CLK_PLL3_USB_OTG>, <&clks IMX6UL_CLK_PERIPH>, + <&clks IMX6UL_CLK_PERIPH_PRE>, <&clks IMX6UL_CLK_PERIPH_CLK2>, + <&clks IMX6UL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6UL_CLK_OSC>, + <&clks IMX6UL_CLK_AHB>, <&clks IMX6UL_CLK_AXI>, + <&clks IMX6UL_CLK_PERIPH2>, <&clks IMX6UL_CLK_PERIPH2_PRE>, + <&clks IMX6UL_CLK_PERIPH2_CLK2>, <&clks IMX6UL_CLK_PERIPH2_CLK2_SEL>, + <&clks IMX6UL_CLK_STEP>, <&clks IMX6UL_CLK_MMDC_P0_FAST>, <&clks IMX6UL_PLL1_BYPASS_SRC>, + <&clks IMX6UL_PLL1_BYPASS>, <&clks IMX6UL_CLK_PLL1_SYS>, <&clks IMX6UL_CLK_PLL1_SW>, + <&clks IMX6UL_CLK_PLL1>; + clock-names = "pll2_pfd2_396m", "pll2_198m", "pll2_bus", "arm", "pll3_usb_otg", + "periph", "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", + "ahb", "ocram", "periph2", "periph2_pre", "periph2_clk2", "periph2_clk2_sel", + "step", "mmdc", "pll1_bypass_src", "pll1_bypass", "pll1_sys", "pll1_sw", "pll1"; + fsl,max_ddr_freq = <400000000>; + }; + aips3: aips-bus@2200000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -68,6 +98,13 @@ clock-names = "dcp"; }; + rngb: rng@2284000 { + compatible = "fsl,imx25-rngb"; + reg = <0x02284000 0x4000>; + interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6UL_CLK_DUMMY>; + }; + iomuxc_snvs: iomuxc-snvs@2290000 { compatible = "fsl,imx6ull-iomuxc-snvs"; reg = <0x02290000 0x4000>; @@ -83,6 +120,18 @@ clock-names = "ipg", "per"; status = "disabled"; }; + + epdc: epdc@228c000 { + compatible = "fsl,imx7d-epdc"; + interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x228c000 0x4000>; + clocks = <&clks IMX6ULL_CLK_EPDC_ACLK>, + <&clks IMX6ULL_CLK_EPDC_PIX>; + clock-names = "epdc_axi", "epdc_pix"; + /* Need to fix epdc-ram */ + /* epdc-ram = <&gpr 0x4 30>; */ + status = "disabled"; + }; }; }; }; diff --git a/arch/arm/boot/dts/imx6ulz-14x14-evk-btwifi.dts b/arch/arm/boot/dts/imx6ulz-14x14-evk-btwifi.dts new file mode 100644 index 000000000000..bac48ee3ae95 --- /dev/null +++ b/arch/arm/boot/dts/imx6ulz-14x14-evk-btwifi.dts @@ -0,0 +1,16 @@ +/* + * Copyright 2018 NXP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "imx6ulz-14x14-evk.dts" +#include "imx6ul-evk-btwifi.dtsi" diff --git a/arch/arm/boot/dts/imx6ulz-14x14-evk-emmc.dts b/arch/arm/boot/dts/imx6ulz-14x14-evk-emmc.dts new file mode 100644 index 000000000000..e477952759ea --- /dev/null +++ b/arch/arm/boot/dts/imx6ulz-14x14-evk-emmc.dts @@ -0,0 +1,25 @@ +/* + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "imx6ulz-14x14-evk.dts" + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2_8bit>; + pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6ulz-14x14-evk-gpmi-weim.dts b/arch/arm/boot/dts/imx6ulz-14x14-evk-gpmi-weim.dts new file mode 100644 index 000000000000..12635e83e348 --- /dev/null +++ b/arch/arm/boot/dts/imx6ulz-14x14-evk-gpmi-weim.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2018 NXP + +#include "imx6ulz-14x14-evk.dts" + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand_1>; + status = "okay"; + nand-on-flash-bbt; +}; + +&iomuxc { + pinctrl_gpmi_nand_1: gpmi-nand-1 { + fsl,pins = < + MX6UL_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 + MX6UL_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 + MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 + MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 + MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 + MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 + MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 + MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 + MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 + MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 + MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 + MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 + MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 + MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 + MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 + MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 + >; + }; +}; + +&qspi { + status = "disabled"; +}; + +&usdhc2 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6ulz-14x14-evk.dts b/arch/arm/boot/dts/imx6ulz-14x14-evk.dts index 483d9732c002..7deda307425b 100644 --- a/arch/arm/boot/dts/imx6ulz-14x14-evk.dts +++ b/arch/arm/boot/dts/imx6ulz-14x14-evk.dts @@ -20,3 +20,20 @@ /delete-node/ panel; }; + +&iomuxc { + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */ + MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */ + MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */ + >; + }; +}; + diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-val-sai.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-val-sai.dts new file mode 100644 index 000000000000..a256004559c4 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-val-sai.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + */ + +#include "imx7d-12x12-lpddr3-val.dts" + +/ { + sound { + compatible = "fsl,imx7d-12x12-lpddr3-arm2-wm8958", + "fsl,imx-audio-wm8958"; + model = "wm8958-audio"; + cpu-dai = <&sai1>; + audio-codec = <&codec>; + codec-master; + hp-det-gpios = <&gpio1 12 1>; + }; +}; + +&iomuxc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_hog_1 &pinctrl_hog_headphone_det>; + pinctrl-1 = <&pinctrl_hog_1 &pinctrl_hog_sd2_vselect>; +}; + +&sai1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_sai1>; + pinctrl-1 = <&pinctrl_sai1>; + status = "okay"; +}; + +&sdma { + status = "okay"; +}; + +&sim1 { + status = "disabled"; +}; + +&usdhc2 { + no-1-8-v; +}; diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-val.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-val.dts new file mode 100644 index 000000000000..422e60865b1a --- /dev/null +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-val.dts @@ -0,0 +1,1015 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + */ + +/dts-v1/; + +#include "imx7d.dtsi" + +/ { + model = "Freescale i.MX7D LPDDR3 12x12 Validation Board"; + compatible = "fsl,imx7d-12x12-lpddr3-val", "fsl,imx7d"; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + status = "okay"; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_gpio_keys>; + pinctrl-1 = <&pinctrl_gpio_keys_sleep>; + + volume-up { + label = "Volume Up"; + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEDOWN>; + }; + }; + + pxp_v4l2_out { + compatible = "fsl,imx7d-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_aud_1v8: aud_1v8 { + compatible = "regulator-fixed"; + regulator-name = "AUD_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio1 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_can1_3v3: can1-3v3 { + compatible = "regulator-fixed"; + regulator-name = "can1-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 10 GPIO_ACTIVE_LOW>; + }; + + reg_can2_3v3: can2-3v3 { + compatible = "regulator-fixed"; + regulator-name = "can2-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 11 GPIO_ACTIVE_LOW>; + }; + + reg_coedc_5v: coedc_5v { + compatible = "regulator-fixed"; + regulator-name = "CODEC_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_sd1_vmmc: sd1_vmmc{ + compatible = "regulator-fixed"; + regulator-name = "VCC_SD1"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_sd2_vmmc: sd2_vmmc{ + compatible = "regulator-fixed"; + regulator-name = "VCC_SD2"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usb_otg1_vbus: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usb_otg2_vbus: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "usb_otg2_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_vref_1v8: regulator@2 { + compatible = "regulator-fixed"; + regulator-name = "vref-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + reg_mipi_dsi_pwr_on: mipi_dsi_pwr_on { + compatible = "regulator-fixed"; + regulator-name = "mipi_dsi_pwr_on"; + gpio = <&gpio4 16 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; + + memory { + reg = <0x80000000 0x80000000>; + }; +}; + +&adc1 { + vref-supply = <®_vref_1v8>; + status = "okay"; +}; + +&cpu0 { + arm-supply = <&sw1a_reg>; +}; + +&epdc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_epdc_0>; + pinctrl-1 = <&pinctrl_epdc_0>; + V3P3-supply = <&V3P3_reg>; + VCOM-supply = <&VCOM_reg>; + DISPLAY-supply = <&DISPLAY_reg>; + status = "okay"; +}; + +&epxp { + status = "okay"; +}; + +&ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 19 0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_ecspi1_1 &pinctrl_ecspi1_cs_1>; + pinctrl-1 = <&pinctrl_ecspi1_1 &pinctrl_ecspi1_cs_1>; + status = "disabled"; + + spi_flash1: m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p32"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&fec1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_enet1>; + pinctrl-1 = <&pinctrl_enet1>; + assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, + <&clks IMX7D_ENET1_TIME_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <100000000>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy1>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@5 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <5>; + }; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; +}; + +&fec2 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_enet2>; + pinctrl-1 = <&pinctrl_enet2>; + pinctrl-assert-gpios = <&max7322 0 GPIO_ACTIVE_HIGH>; + assigned-clocks = <&clks IMX7D_ENET2_TIME_ROOT_SRC>, + <&clks IMX7D_ENET2_TIME_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <100000000>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "disabled"; +}; + +&flexcan1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_flexcan1>; + pinctrl-1 = <&pinctrl_flexcan1>; + xceiver-supply = <®_can1_3v3>; + status = "disabled"; +}; + +&flexcan2 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_flexcan2>; + pinctrl-1 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can2_3v3>; + status = "disabled"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_i2c1_1>; + pinctrl-1 = <&pinctrl_i2c1_1>; + status = "okay"; + + pmic: pfuze3000@8 { + compatible = "fsl,pfuze3000"; + reg = <0x8>; + fsl,lpsr-mode; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1850000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_i2c3_1>; + pinctrl-1 = <&pinctrl_i2c3_1>; + status = "okay"; + + max7322: gpio@68 { + compatible = "maxim,max7322"; + reg = <0x68>; + gpio-controller; + #gpio-cells = <2>; + }; + + max17135@48 { + compatible = "maxim,max17135"; + reg = <0x48>; + vneg_pwrup = <1>; + gvee_pwrup = <2>; + vpos_pwrup = <10>; + gvdd_pwrup = <12>; + gvdd_pwrdn = <1>; + vpos_pwrdn = <2>; + gvee_pwrdn = <8>; + vneg_pwrdn = <10>; + gpio_pmic_pwrgood = <&gpio2 31 0>; + gpio_pmic_vcom_ctrl = <&gpio4 14 0>; + gpio_pmic_wakeup = <&gpio4 23 0>; + gpio_pmic_v3p3 = <&gpio4 20 0>; + gpio_pmic_intr = <&gpio4 18 0>; + + regulators { + DISPLAY_reg: DISPLAY { + regulator-name = "DISPLAY"; + }; + + GVDD_reg: GVDD { + /* 20v */ + regulator-name = "GVDD"; + }; + + GVEE_reg: GVEE { + /* -22v */ + regulator-name = "GVEE"; + }; + + HVINN_reg: HVINN { + /* -22v */ + regulator-name = "HVINN"; + }; + + HVINP_reg: HVINP { + /* 20v */ + regulator-name = "HVINP"; + }; + + VCOM_reg: VCOM { + regulator-name = "VCOM"; + /* Real max value: -500000 */ + regulator-max-microvolt = <4325000>; + /* Real min value: -4325000 */ + regulator-min-microvolt = <500000>; + }; + + VNEG_reg: VNEG { + /* -15v */ + regulator-name = "VNEG"; + }; + + VPOS_reg: VPOS { + /* 15v */ + regulator-name = "VPOS"; + }; + + V3P3_reg: V3P3 { + regulator-name = "V3P3"; + }; + }; + }; + + codec: wm8958@1a { + compatible = "wlf,wm8958"; + reg = <0x1a>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>, + <&clks IMX7D_CLK_DUMMY>; + clock-names = "mclk1", "mclk2"; + + DBVDD1-supply = <®_aud_1v8>; + DBVDD2-supply = <®_aud_1v8>; + DBVDD3-supply = <®_aud_1v8>; + AVDD2-supply = <®_aud_1v8>; + CPVDD-supply = <®_aud_1v8>; + SPKVDD1-supply = <®_coedc_5v>; + SPKVDD2-supply = <®_coedc_5v>; + wlf,ldo1ena; + wlf,ldo2ena; + }; +}; + +&iomuxc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_hog_1 &pinctrl_hog_sd2_vselect &pinctrl_hog_mipi>; + pinctrl-1 = <&pinctrl_hog_1 &pinctrl_hog_sd2_vselect &pinctrl_hog_mipi>; + + imx7d-12x12-lpddr3-arm2 { + + pinctrl_bt: btgrp-1 { + fsl,pins = < + MX7D_PAD_ENET1_CRS__GPIO7_IO14 0x80000000 /* BT REG on */ + >; + }; + + pinctrl_ecspi1_cs_1: ecspi1_cs_grp-1 { + fsl,pins = < + MX7D_PAD_ECSPI1_SS0__GPIO4_IO19 0x2 + >; + }; + + pinctrl_ecspi1_1: ecspi1grp-1 { + fsl,pins = < + MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO 0x2 + MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x2 + MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x2 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX7D_PAD_GPIO1_IO10__ENET1_MDIO 0x3 + MX7D_PAD_GPIO1_IO11__ENET1_MDC 0x3 + MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 + MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 + MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 + MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 + MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 + MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 + MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 + MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 + MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 + MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 + MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 + MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x1 + MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x1 + MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x1 + MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x1 + MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x1 + MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x1 + MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x1 + MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x1 + MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x1 + MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x1 + MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x1 + MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x1 + >; + }; + + pinctrl_epdc_0: epdcgrp-0 { + fsl,pins = < + MX7D_PAD_EPDC_DATA00__EPDC_DATA0 0x2 + MX7D_PAD_EPDC_DATA01__EPDC_DATA1 0x2 + MX7D_PAD_EPDC_DATA02__EPDC_DATA2 0x2 + MX7D_PAD_EPDC_DATA03__EPDC_DATA3 0x2 + MX7D_PAD_EPDC_DATA04__EPDC_DATA4 0x2 + MX7D_PAD_EPDC_DATA05__EPDC_DATA5 0x2 + MX7D_PAD_EPDC_DATA06__EPDC_DATA6 0x2 + MX7D_PAD_EPDC_DATA07__EPDC_DATA7 0x2 + MX7D_PAD_EPDC_DATA08__EPDC_DATA8 0x2 + MX7D_PAD_EPDC_DATA09__EPDC_DATA9 0x2 + MX7D_PAD_EPDC_DATA10__EPDC_DATA10 0x2 + MX7D_PAD_EPDC_DATA11__EPDC_DATA11 0x2 + MX7D_PAD_EPDC_DATA12__EPDC_DATA12 0x2 + MX7D_PAD_EPDC_DATA13__EPDC_DATA13 0x2 + MX7D_PAD_EPDC_DATA14__EPDC_DATA14 0x2 + MX7D_PAD_EPDC_DATA15__EPDC_DATA15 0x2 + MX7D_PAD_EPDC_SDCLK__EPDC_SDCLK 0x2 + MX7D_PAD_EPDC_SDLE__EPDC_SDLE 0x2 + MX7D_PAD_EPDC_SDOE__EPDC_SDOE 0x2 + MX7D_PAD_EPDC_SDSHR__EPDC_SDSHR 0x2 + MX7D_PAD_EPDC_SDCE0__EPDC_SDCE0 0x2 + MX7D_PAD_EPDC_SDCE1__EPDC_SDCE1 0x2 + MX7D_PAD_EPDC_SDCE2__EPDC_SDCE2 0x2 + MX7D_PAD_EPDC_SDCE3__EPDC_SDCE3 0x2 + MX7D_PAD_EPDC_GDCLK__EPDC_GDCLK 0x2 + MX7D_PAD_EPDC_GDOE__EPDC_GDOE 0x2 + MX7D_PAD_EPDC_GDRL__EPDC_GDRL 0x2 + MX7D_PAD_EPDC_GDSP__EPDC_GDSP 0x2 + MX7D_PAD_EPDC_BDR0__EPDC_BDR0 0x2 + MX7D_PAD_EPDC_BDR1__EPDC_BDR1 0x2 + MX7D_PAD_ECSPI1_MISO__GPIO4_IO18 0x80000000 /* pwr int */ + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX7D_PAD_SAI1_RX_DATA__FLEXCAN1_RX 0x59 + MX7D_PAD_SAI1_TX_BCLK__FLEXCAN1_TX 0x59 + MX7D_PAD_GPIO1_IO10__GPIO1_IO10 0x59 /* STBY */ + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX7D_PAD_SAI1_TX_SYNC__FLEXCAN2_RX 0x59 + MX7D_PAD_SAI1_TX_DATA__FLEXCAN2_TX 0x59 + MX7D_PAD_GPIO1_IO11__GPIO1_IO11 0x59 /* STBY */ + >; + }; + + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + MX7D_PAD_GPIO1_IO14__GPIO1_IO14 0x32 + MX7D_PAD_GPIO1_IO15__GPIO1_IO15 0x32 + >; + }; + + pinctrl_gpio_keys_sleep: gpio_keysgrp_sleep { + fsl,pins = < + MX7D_PAD_GPIO1_IO14__GPIO1_IO14 0x14 + MX7D_PAD_GPIO1_IO15__GPIO1_IO15 0x14 + >; + }; + + pinctrl_hog_1: hoggrp-1 { + fsl,pins = < + MX7D_PAD_I2C4_SCL__GPIO4_IO14 0x80000000 + MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31 0x80000000 + MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20 0x80000000 + MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21 0x80000000 + MX7D_PAD_ECSPI2_MISO__GPIO4_IO22 0x80000000 + MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x80000000 + MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0x59 + MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x59 + MX7D_PAD_SD1_WP__GPIO5_IO1 0x59 + MX7D_PAD_SD2_CD_B__GPIO5_IO9 0x59 + MX7D_PAD_SD2_WP__GPIO5_IO10 0x59 + MX7D_PAD_SD2_RESET_B__GPIO5_IO11 0x59 + MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x59 + >; + }; + + pinctrl_hog_mipi: hoggrp_mipi { + fsl,pins = < + MX7D_PAD_ECSPI1_SCLK__GPIO4_IO16 0x59 + MX7D_PAD_ECSPI1_MOSI__GPIO4_IO17 0x59 + >; + }; + + pinctrl_hog_sd2_vselect: hoggrp_sd2vselect { + fsl,pins = < + MX7D_PAD_GPIO1_IO12__SD2_VSELECT 0x59 + >; + }; + + pinctrl_hog_headphone_det: hoggrp_headphone_det { + fsl,pins = < + MX7D_PAD_GPIO1_IO12__GPIO1_IO12 0x59 + >; + }; + + pinctrl_i2c1_1: i2c1grp-1 { + fsl,pins = < + MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f + MX7D_PAD_I2C1_SCL__I2C1_SCL 0x4000007f + >; + }; + + pinctrl_i2c2_1: i2c2grp-1 { + fsl,pins = < + MX7D_PAD_I2C2_SDA__I2C2_SDA 0x4000007f + MX7D_PAD_I2C2_SCL__I2C2_SCL 0x4000007f + >; + }; + + pinctrl_i2c3_1: i2c3grp-1 { + fsl,pins = < + MX7D_PAD_I2C3_SDA__I2C3_SDA 0x4000007f + MX7D_PAD_I2C3_SCL__I2C3_SCL 0x4000007f + >; + }; + + pinctrl_i2c4_1: i2c4grp-1 { + fsl,pins = < + MX7D_PAD_I2C4_SDA__I2C4_SDA 0x4000007f + MX7D_PAD_I2C4_SCL__I2C4_SCL 0x4000007f + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX7D_PAD_LCD_DATA00__LCD_DATA0 0x79 + MX7D_PAD_LCD_DATA01__LCD_DATA1 0x79 + MX7D_PAD_LCD_DATA02__LCD_DATA2 0x79 + MX7D_PAD_LCD_DATA03__LCD_DATA3 0x79 + MX7D_PAD_LCD_DATA04__LCD_DATA4 0x79 + MX7D_PAD_LCD_DATA05__LCD_DATA5 0x79 + MX7D_PAD_LCD_DATA06__LCD_DATA6 0x79 + MX7D_PAD_LCD_DATA07__LCD_DATA7 0x79 + MX7D_PAD_LCD_DATA08__LCD_DATA8 0x79 + MX7D_PAD_LCD_DATA09__LCD_DATA9 0x79 + MX7D_PAD_LCD_DATA10__LCD_DATA10 0x79 + MX7D_PAD_LCD_DATA11__LCD_DATA11 0x79 + MX7D_PAD_LCD_DATA12__LCD_DATA12 0x79 + MX7D_PAD_LCD_DATA13__LCD_DATA13 0x79 + MX7D_PAD_LCD_DATA14__LCD_DATA14 0x79 + MX7D_PAD_LCD_DATA15__LCD_DATA15 0x79 + MX7D_PAD_LCD_DATA16__LCD_DATA16 0x79 + MX7D_PAD_LCD_DATA17__LCD_DATA17 0x79 + MX7D_PAD_LCD_DATA18__LCD_DATA18 0x79 + MX7D_PAD_LCD_DATA19__LCD_DATA19 0x79 + MX7D_PAD_LCD_DATA20__LCD_DATA20 0x79 + MX7D_PAD_LCD_DATA21__LCD_DATA21 0x79 + MX7D_PAD_LCD_DATA22__LCD_DATA22 0x79 + MX7D_PAD_LCD_DATA23__LCD_DATA23 0x79 + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX7D_PAD_LCD_CLK__LCD_CLK 0x79 + MX7D_PAD_LCD_ENABLE__LCD_ENABLE 0x79 + MX7D_PAD_LCD_VSYNC__LCD_VSYNC 0x79 + MX7D_PAD_LCD_HSYNC__LCD_HSYNC 0x79 + >; + }; + + pinctrl_mqs: mqsgrp { + fsl,pins = < + MX7D_PAD_SAI1_RX_SYNC__MQS_RIGHT 0x0 + MX7D_PAD_SAI1_RX_BCLK__MQS_LEFT 0x0 + >; + }; + + pinctrl_pcie: pciegrp { + fsl,pins = < + MX7D_PAD_SAI2_TX_SYNC__GPIO6_IO19 0x2 + MX7D_PAD_SAI2_RX_DATA__GPIO6_IO21 0x2 + >; + }; + + pinctrl_sai1: sai1grp { + fsl,pins = < + MX7D_PAD_SAI1_MCLK__SAI1_MCLK 0x1f + MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK 0x1f + MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC 0x1f + MX7D_PAD_SAI1_RX_SYNC__SAI1_RX_SYNC 0x1f + MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0 0x1f + MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0 0 + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + MX7D_PAD_SAI2_TX_BCLK__SAI2_TX_BCLK 0x1f + MX7D_PAD_SAI2_TX_SYNC__SAI2_TX_SYNC 0x1f + MX7D_PAD_SAI2_RX_DATA__SAI2_RX_DATA0 0x1f + MX7D_PAD_SAI2_TX_DATA__SAI2_TX_DATA0 0 + >; + }; + + pinctrl_uart1_1: uart1grp-1 { + fsl,pins = < + MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 + MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x79 + >; + }; + + pinctrl_uart3_1: uart3grp-1 { + fsl,pins = < + MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX 0x79 + MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX 0x79 + MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS 0x79 + MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS 0x79 + >; + }; + + pinctrl_uart3dte_1: uart3dtegrp-1 { + fsl,pins = < + MX7D_PAD_UART3_TX_DATA__UART3_DTE_RX 0x79 + MX7D_PAD_UART3_RX_DATA__UART3_DTE_TX 0x79 + MX7D_PAD_UART3_RTS_B__UART3_DTE_CTS 0x79 + MX7D_PAD_UART3_CTS_B__UART3_DTE_RTS 0x79 + >; + }; + + pinctrl_usdhc1_1: usdhc1grp-1 { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x59 + MX7D_PAD_SD1_CLK__SD1_CLK 0x19 + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x59 + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x59 + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x59 + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x59 + >; + }; + + pinctrl_usdhc2_1: usdhc2grp-1 { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x59 + MX7D_PAD_SD2_CLK__SD2_CLK 0x19 + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x59 + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x59 + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x59 + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x59 + >; + }; + + pinctrl_usdhc2_1_100mhz: usdhc2grp-1_100mhz { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x5a + MX7D_PAD_SD2_CLK__SD2_CLK 0x1a + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x5a + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x5a + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x5a + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x5a + >; + }; + + pinctrl_usdhc2_1_200mhz: usdhc2grp-1_200mhz { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x5b + MX7D_PAD_SD2_CLK__SD2_CLK 0x1b + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x5b + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x5b + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x5b + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x5b + >; + }; + + pinctrl_usdhc3_1: usdhc3grp-1 { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x59 + MX7D_PAD_SD3_CLK__SD3_CLK 0x19 + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x59 + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x59 + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x59 + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x59 + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x59 + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x59 + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x59 + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x59 + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x19 + >; + }; + + pinctrl_usdhc3_1_100mhz: usdhc3grp-1_100mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5a + MX7D_PAD_SD3_CLK__SD3_CLK 0x1a + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5a + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5a + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5a + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5a + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5a + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5a + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5a + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5a + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1a + >; + }; + + pinctrl_usdhc3_1_200mhz: usdhc3grp-1_200mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5b + MX7D_PAD_SD3_CLK__SD3_CLK 0x1b + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5b + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5b + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5b + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5b + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5b + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5b + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5b + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5b + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1b + >; + }; + + pinctrl_sim1_1: sim1grp-1 { + fsl,pins = < + MX7D_PAD_SAI1_TX_SYNC__SIM1_PORT1_RST_B 0x77 + MX7D_PAD_SAI1_RX_SYNC__SIM1_PORT1_PD 0x77 + MX7D_PAD_SAI1_TX_DATA__SIM1_PORT1_SVEN 0x77 + MX7D_PAD_SAI1_TX_BCLK__SIM1_PORT1_CLK 0x73 + MX7D_PAD_SAI1_RX_DATA__SIM1_PORT1_TRXD 0x73 + >; + }; + + }; +}; + +&iomuxc_lpsr { + imx7d-12x12-lpddr3-arm2 { + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO01__PWM1_OUT 0x30 + >; + }; + }; + + imx7d-sdb { + pinctrl_usbotg1_vbus: usbotg1vbusgrp { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5 0x14 + >; + }; + + pinctrl_usbotg2_vbus: usbotg2vbusgrp { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7 0x14 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B 0x74 + >; + }; + }; +}; + +&lcdif { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lcdif_dat + &pinctrl_lcdif_ctrl>; + pinctrl-1 = <&pinctrl_lcdif_dat + &pinctrl_lcdif_ctrl>; + display = <&display0>; + status = "okay"; + + display0: display@0 { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hback-porch = <89>; + hfront-porch = <164>; + vback-porch = <23>; + vfront-porch = <10>; + hsync-len = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + +&ocrams { + fsl,enable-lpsr; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + reset-gpio = <&gpio6 21 GPIO_ACTIVE_LOW>; + power-on-gpio = <&gpio6 19 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&sim1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_sim1_1>; + pinctrl-1 = <&pinctrl_sim1_1>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-1 = <&pinctrl_uart1_1>; + assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_uart3_1 + &pinctrl_bt>; + pinctrl-1 = <&pinctrl_uart3_1 + &pinctrl_bt>; + fsl,uart-has-rtscts; + assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>; + status = "okay"; + /* for DTE mode, add below change */ + /* fsl,dte-mode;*/ + /* pinctrl-0 = <&pinctrl_uart3dte_1>; */ +}; + +&usbotg1 { + vbus-supply = <®_usb_otg1_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg1_vbus>; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usbotg2 { + vbus-supply = <®_usb_otg2_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg2_vbus>; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_usdhc1_1>; + pinctrl-1 = <&pinctrl_usdhc1_1>; + cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; + no-1-8-v; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd1_vmmc>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; + pinctrl-0 = <&pinctrl_usdhc2_1>; + pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>; + pinctrl-3 = <&pinctrl_usdhc2_1>; + cd-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio5 10 GPIO_ACTIVE_HIGH>; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd2_vmmc>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; + pinctrl-0 = <&pinctrl_usdhc3_1>; + pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>; + pinctrl-3 = <&pinctrl_usdhc3_1>; + assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>; + assigned-clock-rates = <400000000>; + bus-width = <8>; + auto-cmd23-broken; + non-removable; + keep-power-in-suspend; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-epdc.dts b/arch/arm/boot/dts/imx7d-sdb-epdc.dts new file mode 100644 index 000000000000..2d3df3dcd5f8 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-epdc.dts @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + */ +#include "imx7d-sdb.dts" +#include "imx7d-sdb-epdc.dtsi" diff --git a/arch/arm/boot/dts/imx7d-sdb-epdc.dtsi b/arch/arm/boot/dts/imx7d-sdb-epdc.dtsi new file mode 100644 index 000000000000..8dda20b53c5a --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-epdc.dtsi @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + */ + +&epdc { + status = "okay"; +}; + +&fec1 { + status = "okay"; +}; + +&fec2 { + status = "disabled"; +}; + +®_can2_3v3 { + status = "disabled"; +}; + +®_fec2_3v3 { + status = "disabled"; +}; + +&flexcan2 { + status = "disabled"; +}; + +&max17135 { + status = "okay"; +}; + +&sii902x { + status = "disabled"; +}; + +&sim1 { + status = "disabled"; +}; + +&uart5 { + status = "disabled"; +}; + +&i2c3 { + elan@10 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_epdc_elan_touch>; + compatible = "elan,elan-touch"; + reg = <0x10>; + interrupt-parent = <&gpio6>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + gpio_elan_cs = <&gpio6 13 0>; + gpio_elan_rst = <&gpio6 15 0>; + gpio_intr = <&gpio6 12 0>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-gpmi-weim.dts b/arch/arm/boot/dts/imx7d-sdb-gpmi-weim.dts new file mode 100644 index 000000000000..346e38cca609 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-gpmi-weim.dts @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "imx7d-sdb.dts" +#include "imx7d-sdb-gpmi-weim.dtsi" diff --git a/arch/arm/boot/dts/imx7d-sdb-gpmi-weim.dtsi b/arch/arm/boot/dts/imx7d-sdb-gpmi-weim.dtsi new file mode 100644 index 000000000000..a614cbf05aa8 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-gpmi-weim.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +&gpmi{ + status = "okay"; +}; + +/* &sai1{ */ + /* status = "disabled"; */ +/* }; */ + +&usdhc3{ + status = "disabled"; +}; + +&uart5{ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-m4.dts b/arch/arm/boot/dts/imx7d-sdb-m4.dts new file mode 100644 index 000000000000..7aa803559ef5 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-m4.dts @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "imx7d-sdb.dts" +#include "imx7d-sdb-m4.dtsi" diff --git a/arch/arm/boot/dts/imx7d-sdb-m4.dtsi b/arch/arm/boot/dts/imx7d-sdb-m4.dtsi new file mode 100644 index 000000000000..601a236f5372 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-m4.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/ { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + m4_reserved: m4@0x9ff00000 { + no-map; + reg = <0x9ff00000 0x100000>; + }; + + rpmsg_reserved: rpmsg@0xbff00000 { + no-map; + reg = <0xbff00000 0x100000>; + }; + }; + m4_tcm: tcml@007f8000 { + compatible = "fsl, m4_tcml"; + reg = <0x007f8000 0x8000>; + }; +}; + +&adc1 { + status = "disabled"; +}; + +&adc2 { + status = "disabled"; +}; + +&flexcan1 { + status = "disabled"; +}; + +&flexcan2 { + status = "disabled"; +}; + +&i2c2 { + status = "disabled"; +}; + +&gpt3 { + status = "disabled"; +}; + +&gpt4 { + status = "disabled"; +}; + +&ocram { + reg = <0x00901000 0xf000>; +}; + +®_can2_3v3 { + status = "disabled"; +}; + +&rpmsg{ + vdev-nums = <1>; + reg = <0xbfff0000 0x10000>; + status = "okay"; +}; + +&uart2 { + status = "disabled"; +}; + +&wdog3{ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-mipi-dsi.dts b/arch/arm/boot/dts/imx7d-sdb-mipi-dsi.dts new file mode 100644 index 000000000000..327d976e4066 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-mipi-dsi.dts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7d-sdb.dts" + +/ { + mipi_dsi_reset: mipi-dsi-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; +}; + +&lcdif { + disp-dev = "mipi_dsi_samsung"; + disp-videomode = "TRUULY-WVGA-SYNC-LOW"; +}; + +&mipi_dsi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mipi_dsi_reset>; + lcd_panel = "TRULY-WVGA-TFT3P5581E"; + resets = <&mipi_dsi_reset>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-pcie-ep.dts b/arch/arm/boot/dts/imx7d-sdb-pcie-ep.dts new file mode 100644 index 000000000000..78ebede8bfea --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-pcie-ep.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include "imx7d-sdb.dts" + +&pcie{ + status = "disabled"; +}; + +&pcie_ep{ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-qspi.dts b/arch/arm/boot/dts/imx7d-sdb-qspi.dts new file mode 100644 index 000000000000..a46990554d28 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-qspi.dts @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "imx7d-sdb.dts" +#include "imx7d-sdb-qspi.dtsi" diff --git a/arch/arm/boot/dts/imx7d-sdb-qspi.dtsi b/arch/arm/boot/dts/imx7d-sdb-qspi.dtsi new file mode 100644 index 000000000000..513c597ff078 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-qspi.dtsi @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* disable epdc, conflict with qspi */ +&epdc { + status = "disabled"; +}; + +&iomuxc { + qspi1 { + pinctrl_qspi1_1: qspi1grp_1 { + fsl,pins = < + MX7D_PAD_EPDC_DATA00__QSPI_A_DATA0 0x51 + MX7D_PAD_EPDC_DATA01__QSPI_A_DATA1 0x51 + MX7D_PAD_EPDC_DATA02__QSPI_A_DATA2 0x51 + MX7D_PAD_EPDC_DATA03__QSPI_A_DATA3 0x51 + MX7D_PAD_EPDC_DATA05__QSPI_A_SCLK 0x51 + MX7D_PAD_EPDC_DATA06__QSPI_A_SS0_B 0x51 + >; + }; + }; +}; + +&qspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi1_1>; + status = "okay"; + ddrsmp=<0>; + + flash0: mx25l51245g@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-max-frequency = <29000000>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; + reg = <0>; + }; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb-usd-wifi.dts b/arch/arm/boot/dts/imx7d-sdb-usd-wifi.dts new file mode 100644 index 000000000000..9c0642fdff41 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-usd-wifi.dts @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2020 NXP + */ + +#include "imx7d-sdb.dts" + +/ { + reg_sd2_vmmc: regulator-sd2-vmmc { + compatible = "regulator-fixed"; + regulator-name = "VDD_SD2"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_brcm_reg>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; +}; + +®_sd1_vmmc { + regulator-always-on; +}; + +&usdhc1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + /delete-property/ cd-gpios; + /delete-property/ wp-gpios; + no-1-8-v; + pm-ignore-notify; + keep-power-in-suspend; + non-removable; + cap-power-off-card; + + brcmf2: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&usdhc2 { + status = "disabled"; +}; + +&usdhc2_pwrseq { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 869efbc4af42..096cc16697b7 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -19,6 +19,26 @@ reg = <0x80000000 0x80000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + linux,cma-default; + }; + }; + + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio4 23 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -56,6 +76,7 @@ #gpio-cells = <2>; reg = <0>; registers-number = <1>; + registers-default = /bits/ 8 <0x74>; /* Enable PERI_3V3, SENSOR_RST_B and HDMI_RST*/ spi-max-frequency = <100000>; }; }; @@ -87,16 +108,15 @@ regulator-max-microvolt = <1800000>; }; - reg_brcm: regulator-brcm { + reg_sd1_vmmc: regulator-sd1-vmmc { compatible = "regulator-fixed"; - gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>; - enable-active-high; - regulator-name = "brcm_reg"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_brcm_reg>; + regulator-name = "VDD_SD1"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>; startup-delay-us = <200000>; + off-on-delay-us = <20000>; + enable-active-high; }; reg_lcd_3v3: regulator-lcd-3v3 { @@ -135,16 +155,48 @@ status = "okay"; }; - panel { - compatible = "innolux,at043tn24"; - backlight = <&backlight>; - power-supply = <®_lcd_3v3>; + pxp_v4l2_out { + compatible = "fsl,imx7d-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; - port { - panel_in: endpoint { - remote-endpoint = <&display_out>; - }; - }; + sound { + compatible = "fsl,imx7d-evk-wm8960", "fsl,imx-audio-wm8960"; + model = "wm8960-audio"; + cpu-dai = <&sai1>; + audio-codec = <&codec>; + codec-master; + /* JD2: hp detect high for headphone*/ + hp-det = <2 0>; + hp-det-gpios = <&gpio2 28 0>; + audio-routing = + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "LINPUT1", "Main MIC", + "Main MIC", "MICB"; + assigned-clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_SRC>, + <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; + assigned-clock-rates = <0>, <12288000>; + }; + + sound-hdmi { + compatible = "fsl,imx7d-sdb-sii902x", + "fsl,imx-audio-sii902x"; + model = "sii902x-audio"; + cpu-dai = <&sai3>; + hdmi-controller = <&sii902x>; + }; + + usdhc2_pwrseq: usdhc2_pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_brcm_reg>; + reset-gpios = <&gpio4 21 GPIO_ACTIVE_LOW>; }; }; @@ -162,6 +214,23 @@ cpu-supply = <&sw1a_reg>; }; +&clks { + assigned-clocks = <&clks IMX7D_PLL_AUDIO_POST_DIV>; + assigned-clock-rates = <884736000>; +}; + +&csi1 { + csi-mux-mipi = <&gpr 0x14 4>; + fsl,mipi-mode; + status = "okay"; + + port { + csi_ep: endpoint { + remote-endpoint = <&csi_mipi_ep>; + }; + }; +}; + &ecspi3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi3>; @@ -187,13 +256,32 @@ }; }; +&epdc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_epdc0 &pinctrl_enet2_reg>; + V3P3-supply = <&V3P3_reg>; + VCOM-supply = <&VCOM_reg>; + DISPLAY-supply = <&DISPLAY_reg>; + en-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + +&epxp { + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>; - assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, - <&clks IMX7D_ENET1_TIME_ROOT_CLK>; - assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; - assigned-clock-rates = <0>, <100000000>; + assigned-clocks = <&clks IMX7D_ENET_PHY_REF_ROOT_SRC>, + <&clks IMX7D_ENET_AXI_ROOT_SRC>, + <&clks IMX7D_ENET1_TIME_ROOT_SRC>, + <&clks IMX7D_ENET1_TIME_ROOT_CLK>, + <&clks IMX7D_ENET_AXI_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_25M_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_250M_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <0>, <0>, <100000000>, <250000000>; phy-mode = "rgmii"; phy-handle = <ðphy0>; fsl,magic-packet; @@ -217,10 +305,15 @@ &fec2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet2>; - assigned-clocks = <&clks IMX7D_ENET2_TIME_ROOT_SRC>, - <&clks IMX7D_ENET2_TIME_ROOT_CLK>; - assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; - assigned-clock-rates = <0>, <100000000>; + assigned-clocks = <&clks IMX7D_ENET_PHY_REF_ROOT_SRC>, + <&clks IMX7D_ENET_AXI_ROOT_SRC>, + <&clks IMX7D_ENET2_TIME_ROOT_SRC>, + <&clks IMX7D_ENET2_TIME_ROOT_CLK>, + <&clks IMX7D_ENET_AXI_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_25M_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_250M_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <0>, <0>, <100000000>, <250000000>; phy-mode = "rgmii"; phy-handle = <ðphy1>; phy-supply = <®_fec2_3v3>; @@ -235,6 +328,31 @@ status = "okay"; }; +&mipi_csi { + clock-frequency = <240000000>; + status = "okay"; + port { + mipi_sensor_ep: endpoint@1 { + remote-endpoint = <&ov5640_mipi_ep>; + data-lanes = <2>; + csis-hs-settle = <13>; + csis-clk-settle = <2>; + csis-wclk; + }; + + csi_mipi_ep: endpoint@2 { + remote-endpoint = <&csi_ep>; + }; + }; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand_1>; + status = "disabled"; + nand-on-flash-bbt; +}; + &i2c1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; @@ -336,6 +454,16 @@ pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; + fxas2100x@20 { + compatible = "fsl,fxas2100x"; + reg = <0x20>; + }; + + fxos8700@1e { + compatible = "fsl,fxos8700"; + reg = <0x1e>; + }; + mpl3115@60 { compatible = "fsl,mpl3115"; reg = <0x60>; @@ -346,6 +474,88 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay"; + + sii902x: sii902x@39 { + compatible = "SiI,sii902x"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sii902x>; + interrupt-parent = <&gpio2>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + mode_str ="1280x720M@60"; + bits-per-pixel = <16>; + reg = <0x39>; + status = "okay"; + }; + + max17135: max17135@48 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_max17135>; + compatible = "maxim,max17135"; + reg = <0x48>; + status = "disabled"; + + vneg_pwrup = <1>; + gvee_pwrup = <2>; + vpos_pwrup = <10>; + gvdd_pwrup = <12>; + gvdd_pwrdn = <1>; + vpos_pwrdn = <2>; + gvee_pwrdn = <8>; + vneg_pwrdn = <10>; + gpio_pmic_pwrgood = <&gpio2 31 0>; + gpio_pmic_vcom_ctrl = <&gpio4 14 0>; + gpio_pmic_wakeup = <&gpio2 23 0>; + gpio_pmic_v3p3 = <&gpio2 30 0>; + gpio_pmic_intr = <&gpio2 22 0>; + + regulators { + DISPLAY_reg: DISPLAY { + regulator-name = "DISPLAY"; + }; + + GVDD_reg: GVDD { + /* 20v */ + regulator-name = "GVDD"; + }; + + GVEE_reg: GVEE { + /* -22v */ + regulator-name = "GVEE"; + }; + + HVINN_reg: HVINN { + /* -22v */ + regulator-name = "HVINN"; + }; + + HVINP_reg: HVINP { + /* 20v */ + regulator-name = "HVINP"; + }; + + VCOM_reg: VCOM { + regulator-name = "VCOM"; + /* Real max value: -500000 */ + regulator-max-microvolt = <4325000>; + /* Real min value: -4325000 */ + regulator-min-microvolt = <500000>; + }; + + VNEG_reg: VNEG { + /* -15v */ + regulator-name = "VNEG"; + }; + + VPOS_reg: VPOS { + /* 15v */ + regulator-name = "VPOS"; + }; + + V3P3_reg: V3P3 { + regulator-name = "V3P3"; + }; + }; + }; }; &i2c4 { @@ -360,16 +570,54 @@ clock-names = "mclk"; wlf,shared-lrclk; }; + + ov5640_mipi: ov5640_mipi@3c { + compatible = "ovti,ov5640_mipi"; + reg = <0x3c>; + clocks = <&clks IMX7D_CLK_DUMMY>; + clock-names = "csi_mclk"; + csi_id = <0>; + pwn-gpios = <&extended_io 6 GPIO_ACTIVE_HIGH>; + AVDD-supply = <&vgen6_reg>; + mclk = <24000000>; + mclk_source = <0>; + port { + ov5640_mipi_ep: endpoint { + remote-endpoint = <&mipi_sensor_ep>; + }; + }; + }; }; &lcdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcdif>; + lcd-supply = <®_lcd_3v3>; + display = <&display0>; status = "okay"; - port { - display_out: endpoint { - remote-endpoint = <&panel_in>; + display0: display@0 { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0 { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; }; }; }; @@ -387,6 +635,38 @@ vin-supply = <&sw2_reg>; }; +&sai1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai1>; + assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>, + <&clks IMX7D_SAI1_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; + assigned-clock-rates = <0>, <36864000>; + status = "okay"; +}; + +&sai3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai3 &pinctrl_sai3_mclk>; + assigned-clocks = <&clks IMX7D_SAI3_ROOT_SRC>, + <&clks IMX7D_SAI3_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; + assigned-clock-rates = <0>, <36864000>; + status = "okay"; +}; + +&sim1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sim1_1>; + port = <0>; + sven_low_active; + status = "okay"; +}; + +&snvs_poweroff { + status = "okay"; +}; + &snvs_pwrkey { status = "okay"; }; @@ -395,7 +675,18 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + assigned-clocks = <&clks IMX7D_UART5_ROOT_SRC>; assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart5dte>; */ status = "okay"; }; @@ -405,6 +696,7 @@ assigned-clocks = <&clks IMX7D_UART6_ROOT_SRC>; assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>; uart-has-rtscts; + resets = <&modem_reset>; status = "okay"; }; @@ -420,26 +712,35 @@ }; &usdhc1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_usdhc1_gpio>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_usdhc1_gpio>; cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; - wakeup-source; - keep-power-in-suspend; + vmmc-supply = <®_sd1_vmmc>; status = "okay"; }; &usdhc2 { + #address-cells = <1>; + #size-cells = <0>; pinctrl-names = "default", "state_100mhz", "state_200mhz"; - pinctrl-0 = <&pinctrl_usdhc2>; - pinctrl-1 = <&pinctrl_usdhc2_100mhz>; - pinctrl-2 = <&pinctrl_usdhc2_200mhz>; - wakeup-source; + pinctrl-0 = <&pinctrl_usdhc2 &pinctrl_wifi>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz &pinctrl_wifi>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz &pinctrl_wifi>; keep-power-in-suspend; non-removable; - vmmc-supply = <®_brcm>; + mmc-pwrseq = <&usdhc2_pwrseq>; fsl,tuning-step = <2>; + pm-ignore-notify; + cap-power-off-card; status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; }; &usdhc3 { @@ -450,8 +751,8 @@ assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>; assigned-clock-rates = <400000000>; bus-width = <8>; - fsl,tuning-step = <2>; non-removable; + auto-cmd23-broken; status = "okay"; }; @@ -472,6 +773,19 @@ >; }; + pinctrl_epdc_elan_touch: epdc_elan_touch_grp { + fsl,pins = < + MX7D_PAD_SAI1_RX_DATA__GPIO6_IO12 0x59 + MX7D_PAD_SAI1_TX_DATA__GPIO6_IO15 0x1b + MX7D_PAD_SAI1_TX_BCLK__GPIO6_IO13 0x80000000 + >; + }; + pinctrl_mipi_dsi_reset: mipi_dsi_reset_grp { + fsl,pins = < + MX7D_PAD_SAI1_TX_DATA__GPIO6_IO15 0x1b + >; + }; + pinctrl_ecspi3: ecspi3grp { fsl,pins = < MX7D_PAD_SAI2_TX_SYNC__ECSPI3_MISO 0x2 @@ -517,9 +831,34 @@ >; }; - pinctrl_enet2_reg: enet2reggrp { + pinctrl_epdc0: epdcgrp0 { fsl,pins = < - MX7D_PAD_LPSR_GPIO1_IO04__GPIO1_IO4 0x14 + MX7D_PAD_EPDC_DATA00__EPDC_DATA0 0x2 + MX7D_PAD_EPDC_DATA01__EPDC_DATA1 0x2 + MX7D_PAD_EPDC_DATA02__EPDC_DATA2 0x2 + MX7D_PAD_EPDC_DATA03__EPDC_DATA3 0x2 + MX7D_PAD_EPDC_DATA04__EPDC_DATA4 0x2 + MX7D_PAD_EPDC_DATA05__EPDC_DATA5 0x2 + MX7D_PAD_EPDC_DATA06__EPDC_DATA6 0x2 + MX7D_PAD_EPDC_DATA07__EPDC_DATA7 0x2 + MX7D_PAD_EPDC_DATA08__EPDC_DATA8 0x2 + MX7D_PAD_EPDC_DATA09__EPDC_DATA9 0x2 + MX7D_PAD_EPDC_DATA10__EPDC_DATA10 0x2 + MX7D_PAD_EPDC_DATA11__EPDC_DATA11 0x2 + MX7D_PAD_EPDC_DATA12__EPDC_DATA12 0x2 + MX7D_PAD_EPDC_DATA13__EPDC_DATA13 0x2 + MX7D_PAD_EPDC_DATA14__EPDC_DATA14 0x2 + MX7D_PAD_EPDC_DATA15__EPDC_DATA15 0x2 + MX7D_PAD_EPDC_SDCLK__EPDC_SDCLK 0x2 + MX7D_PAD_EPDC_SDLE__EPDC_SDLE 0x2 + MX7D_PAD_EPDC_SDOE__EPDC_SDOE 0x2 + MX7D_PAD_EPDC_SDSHR__EPDC_SDSHR 0x2 + MX7D_PAD_EPDC_SDCE0__EPDC_SDCE0 0x2 + MX7D_PAD_EPDC_SDCE1__EPDC_SDCE1 0x2 + MX7D_PAD_EPDC_GDCLK__EPDC_GDCLK 0x2 + MX7D_PAD_EPDC_GDOE__EPDC_GDOE 0x2 + MX7D_PAD_EPDC_GDRL__EPDC_GDRL 0x2 + MX7D_PAD_EPDC_GDSP__EPDC_GDSP 0x2 >; }; @@ -543,6 +882,27 @@ >; }; + pinctrl_gpmi_nand_1: gpmi-nand-1 { + fsl,pins = < + MX7D_PAD_SD3_CLK__NAND_CLE 0x71 + MX7D_PAD_SD3_CMD__NAND_ALE 0x71 + MX7D_PAD_SAI1_MCLK__NAND_WP_B 0x71 + MX7D_PAD_SAI1_TX_BCLK__NAND_CE0_B 0x71 + MX7D_PAD_SAI1_RX_DATA__NAND_CE1_B 0x71 + MX7D_PAD_SAI1_TX_DATA__NAND_READY_B 0x74 + MX7D_PAD_SD3_STROBE__NAND_RE_B 0x71 + MX7D_PAD_SD3_RESET_B__NAND_WE_B 0x71 + MX7D_PAD_SD3_DATA0__NAND_DATA00 0x71 + MX7D_PAD_SD3_DATA1__NAND_DATA01 0x71 + MX7D_PAD_SD3_DATA2__NAND_DATA02 0x71 + MX7D_PAD_SD3_DATA3__NAND_DATA03 0x71 + MX7D_PAD_SD3_DATA4__NAND_DATA04 0x71 + MX7D_PAD_SD3_DATA5__NAND_DATA05 0x71 + MX7D_PAD_SD3_DATA6__NAND_DATA06 0x71 + MX7D_PAD_SD3_DATA7__NAND_DATA07 0x71 + >; + }; + pinctrl_hog: hoggrp { fsl,pins = < MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x34 /* bt reg on */ @@ -611,6 +971,43 @@ >; }; + pinctrl_max17135: max17135grp-1 { + fsl,pins = < + MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31 0x80000000 /* pwrgood */ + MX7D_PAD_I2C4_SCL__GPIO4_IO14 0x80000000 /* vcom_ctrl */ + MX7D_PAD_EPDC_SDCE3__GPIO2_IO23 0x80000000 /* wakeup */ + MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30 0x80000000 /* v3p3 */ + MX7D_PAD_EPDC_SDCE2__GPIO2_IO22 0x80000000 /* pwr int */ + >; + }; + + pinctrl_sai1: sai1grp { + fsl,pins = < + MX7D_PAD_SAI1_MCLK__SAI1_MCLK 0x1f + MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK 0x1f + MX7D_PAD_ENET1_CRS__SAI1_TX_SYNC 0x1f + MX7D_PAD_ENET1_COL__SAI1_TX_DATA0 0x30 + MX7D_PAD_ENET1_TX_CLK__SAI1_RX_DATA0 0x1f + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + MX7D_PAD_SAI2_TX_BCLK__SAI2_TX_BCLK 0x1f + MX7D_PAD_SAI2_TX_SYNC__SAI2_TX_SYNC 0x1f + MX7D_PAD_SAI2_TX_DATA__SAI2_TX_DATA0 0x30 + MX7D_PAD_SAI2_RX_DATA__SAI2_RX_DATA0 0x1f + >; + }; + + pinctrl_sai3: sai3grp { + fsl,pins = < + MX7D_PAD_UART3_TX_DATA__SAI3_TX_BCLK 0x1f + MX7D_PAD_UART3_CTS_B__SAI3_TX_SYNC 0x1f + MX7D_PAD_UART3_RTS_B__SAI3_TX_DATA0 0x30 + >; + }; + pinctrl_spi4: spi4grp { fsl,pins = < MX7D_PAD_GPIO1_IO09__GPIO1_IO9 0x59 @@ -625,6 +1022,22 @@ >; }; + pinctrl_sii902x: hdmigrp-1 { + fsl,pins = < + MX7D_PAD_EPDC_DATA13__GPIO2_IO13 0x59 + >; + }; + + pinctrl_sim1_1: sim1grp-1 { + fsl,pins = < + MX7D_PAD_EPDC_DATA10__SIM1_PORT1_RST_B 0x77 + MX7D_PAD_EPDC_DATA12__SIM1_PORT1_PD 0x77 + MX7D_PAD_EPDC_DATA11__SIM1_PORT1_SVEN 0x77 + MX7D_PAD_EPDC_DATA09__SIM1_PORT1_CLK 0x73 + MX7D_PAD_EPDC_DATA08__SIM1_PORT1_TRXD 0x73 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 @@ -636,8 +1049,13 @@ fsl,pins = < MX7D_PAD_SAI1_TX_BCLK__UART5_DCE_TX 0x79 MX7D_PAD_SAI1_RX_DATA__UART5_DCE_RX 0x79 - MX7D_PAD_SAI1_TX_SYNC__UART5_DCE_CTS 0x79 - MX7D_PAD_SAI1_TX_DATA__UART5_DCE_RTS 0x79 + >; + }; + + pinctrl_uart5dte: uart5dtegrp { + fsl,pins = < + MX7D_PAD_SAI1_TX_BCLK__UART5_DTE_RX 0x79 + MX7D_PAD_SAI1_RX_DATA__UART5_DTE_TX 0x79 >; }; @@ -650,6 +1068,15 @@ >; }; + pinctrl_usdhc1_gpio: usdhc1_gpiogrp { + fsl,pins = < + MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x59 /* CD */ + MX7D_PAD_SD1_WP__GPIO5_IO1 0x59 /* WP */ + MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0x59 /* vmmc */ + MX7D_PAD_GPIO1_IO08__SD1_VSELECT 0x59 /* VSELECT */ + >; + }; + pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX7D_PAD_SD1_CMD__SD1_CMD 0x59 @@ -658,9 +1085,28 @@ MX7D_PAD_SD1_DATA1__SD1_DATA1 0x59 MX7D_PAD_SD1_DATA2__SD1_DATA2 0x59 MX7D_PAD_SD1_DATA3__SD1_DATA3 0x59 - MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x59 /* CD */ - MX7D_PAD_SD1_WP__GPIO5_IO1 0x59 /* WP */ - MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0x59 /* vmmc */ + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp_100mhz { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x5a + MX7D_PAD_SD1_CLK__SD1_CLK 0x1a + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x5a + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x5a + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x5a + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x5a + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp_200mhz { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x5b + MX7D_PAD_SD1_CLK__SD1_CLK 0x1b + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x5b + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x5b + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x5b + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x5b >; }; @@ -745,6 +1191,12 @@ MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1b >; }; + + pinctrl_wifi: wifigrp { + fsl,pins = < + MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20 0x19 /* WL_HOST_WAKE */ + >; + }; }; }; @@ -755,6 +1207,12 @@ }; &iomuxc_lpsr { + pinctrl_enet2_reg: enet2reggrp { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO04__GPIO1_IO4 0x80000000 + >; + }; + pinctrl_wdog: wdoggrp { fsl,pins = < MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B 0x74 @@ -772,4 +1230,11 @@ MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7 0x14 >; }; + + pinctrl_sai3_mclk: sai3grp_mclk { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO03__SAI3_MCLK 0x1f + >; + }; + }; diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index 9c8dd32cc035..435100a25aa0 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -22,7 +22,6 @@ reg = <1>; clock-frequency = <996000000>; operating-points-v2 = <&cpu0_opp_table>; - cpu-idle-states = <&cpu_sleep_wait>; }; }; @@ -69,6 +68,56 @@ }; soc { + busfreq { + compatible = "fsl,imx_busfreq"; + fsl,max_ddr_freq = <533000000>; + clocks = <&clks IMX7D_OSC_24M_CLK>, <&clks IMX7D_MAIN_AXI_ROOT_SRC>, + <&clks IMX7D_AHB_CHANNEL_ROOT_SRC>, <&clks IMX7D_PLL_SYS_PFD0_392M_CLK>, + <&clks IMX7D_DRAM_ROOT_SRC>, <&clks IMX7D_DRAM_ALT_ROOT_SRC>, + <&clks IMX7D_PLL_DRAM_MAIN_CLK>, <&clks IMX7D_DRAM_ALT_ROOT_CLK>, + <&clks IMX7D_PLL_SYS_PFD2_270M_CLK>, <&clks IMX7D_PLL_SYS_PFD1_332M_CLK>, + <&clks IMX7D_AHB_CHANNEL_ROOT_DIV>, <&clks IMX7D_MAIN_AXI_ROOT_DIV>; + clock-names = "osc", "axi_sel", "ahb_sel", "pfd0_392m", "dram_root", + "dram_alt_sel", "pll_dram", "dram_alt_root", "pfd2_270m", + "pfd1_332m", "ahb", "axi"; + interrupts = <0 112 0x04>, <0 113 0x04>; + interrupt-names = "irq_busfreq_0", "irq_busfreq_1"; + }; + + ocrams_ddr: sram@900000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x900000 0x1000>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + + ocram: sram@901000 { + compatible = "mmio-sram"; + reg = <0x901000 0x1f000>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + + ocrams: sram@180000 { + compatible = "fsl,lpm-sram"; + reg = <0x180000 0x8000>; + clocks = <&clks IMX7D_OCRAM_S_CLK>; + status = "disabled"; + }; + + ocram_optee { + compatible = "fsl,optee-lpm-sram"; + reg = <0x180000 0x8000>; + overw_reg = <&ocrams_ddr 0x904000 0x1000>, + <&ocram 0x905000 0x1b000>, + <&ocrams 0x900000 0x4000>; + overw_clock = <&ocrams &clks IMX7D_OCRAM_CLK>; + }; + + ocrams_mf: sram-mf@900000 { + compatible = "fsl,mega-fast-sram"; + reg = <0x900000 0x20000>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + etm@3007d000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0x3007d000 0x1000>; @@ -106,15 +155,157 @@ }; }; +/delete-node/&csi; +/delete-node/&video_mux; + &aips2 { pcie_phy: pcie-phy@306d0000 { compatible = "fsl,imx7d-pcie-phy"; reg = <0x306d0000 0x10000>; status = "disabled"; }; + + system_counter_rd: system-counter-rd@306a0000 { + compatible = "fsl,imx7d-system-counter-rd"; + reg = <0x306a0000 0x10000>; + status = "disabled"; + }; + + system_counter_cmp: system-counter-cmp@306b0000 { + compatible = "fsl,imx7d-system-counter-cmp"; + reg = <0x306b0000 0x10000>; + status = "disabled"; + }; + + system_counter_ctrl: system-counter-ctrl@306c0000 { + compatible = "fsl,imx7d-system-counter-ctrl"; + reg = <0x306c0000 0x10000>; + interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + epdc: epdc@306f0000 { + compatible = "fsl,imx7d-epdc"; + interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x306f0000 0x10000>; + clocks = <&clks IMX7D_CLK_DUMMY>, <&clks IMX7D_EPDC_PIXEL_ROOT_CLK>; + clock-names = "epdc_axi", "epdc_pix"; + epdc-ram = <&gpr 0x4 30>; + qos = <&qosc>; + status = "disabled"; + }; + + epxp: epxp@30700000 { + compatible = "fsl,imx7d-pxp-dma"; + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x30700000 0x10000>; + clocks = <&clks IMX7D_PXP_IPG_CLK>, <&clks IMX7D_PXP_AXI_CLK>; + clock-names = "pxp_ipg", "pxp_axi"; + status = "disabled"; + }; + + csi1: csi1@30710000 { + compatible = "fsl,imx7d-csi", "fsl,imx6s-csi"; + reg = <0x30710000 0x10000>; + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_CLK_DUMMY>, + <&clks IMX7D_CSI_MCLK_ROOT_CLK>, + <&clks IMX7D_CLK_DUMMY>; + clock-names = "disp-axi", "csi_mclk", "disp_dcic"; + status = "disabled"; + }; + + mipi_csi: mipi-csi@30750000 { + compatible = "fsl,imx7d-mipi-csi"; + reg = <0x30750000 0x10000>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_MIPI_CSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "mipi_clk", "phy_clk"; + mipi-phy-supply = <®_1p0d>; + csis-phy-reset = <&src 0x28 2>; + bus-width = <4>; + status = "disabled"; + /delete-node/ port@0; + /delete-node/ port@1; + }; + + mipi_dsi: mipi-dsi@30760000 { + compatible = "fsl,imx7d-mipi-dsi"; + reg = <0x30760000 0x10000>; + interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_MIPI_DSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "mipi_cfg_clk", "mipi_pllref_clk"; + power-domains = <&pgc_mipi_phy>; + status = "disabled"; + }; + + qosc: qosc@307f0000 { + compatible = "fsl,imx7d-qosc", "syscon"; + reg = <0x307f0000 0x4000>; + }; }; &aips3 { + mu: mu@30aa0000 { + compatible = "fsl,imx7d-mu", "fsl,imx6sx-mu"; + reg = <0x30aa0000 0x10000>; + interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_MU_ROOT_CLK>; + clock-names = "mu"; + #mbox-cells = <2>; + }; + + mu_lp: mu_lp@30aa0000 { + compatible = "fsl,imx7d-mu-lp", "fsl,imx6sx-mu-lp"; + reg = <0x30aa0000 0x10000>; + interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_MU_ROOT_CLK>; + clock-names = "mu"; + status = "okay"; + }; + + sema4: sema4@30ac0000 { + compatible = "fsl,imx7d-sema4"; + reg = <0x30ac0000 0x10000>; + interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_SEMA4_HS_ROOT_CLK>; + clock-names = "sema4"; + status = "okay"; + }; + + sim1: sim@30b90000 { + compatible = "fsl,imx7d-sim"; + reg = <0x30b90000 0x10000>; + interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_SIM1_ROOT_CLK>; + clock-names = "sim"; + status = "disabled"; + }; + + qspi1: spi@30bb0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx7d-qspi"; + reg = <0x30bb0000 0x10000>, <0x60000000 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_QSPI_ROOT_CLK>, + <&clks IMX7D_QSPI_ROOT_CLK>; + clock-names = "qspi_en", "qspi"; + status = "disabled"; + }; + + sim2: sim@30ba0000 { + compatible = "fsl,imx7d-sim"; + reg = <0x30ba0000 0x10000>; + interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + usbotg2: usb@30b20000 { compatible = "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x30b20000 0x200>; @@ -144,7 +335,7 @@ <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET2_TIME_ROOT_CLK>, <&clks IMX7D_PLL_ENET_MAIN_125M_CLK>, - <&clks IMX7D_ENET_PHY_REF_ROOT_CLK>; + <&clks IMX7D_ENET_PHY_REF_ROOT_DIV>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; fsl,num-tx-queues = <3>; @@ -195,6 +386,46 @@ fsl,imx7d-pcie-phy = <&pcie_phy>; status = "disabled"; }; + + pcie_ep: pcie_ep@33800000 { + compatible = "fsl,imx7d-pcie-ep"; + reg = <0x33800000 0x4000>, <0x40000000 0x10000000>; + reg-names = "regs", "addr_space"; + num-lanes = <1>; + clocks = <&clks IMX7D_PCIE_CTRL_ROOT_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>, + <&clks IMX7D_PCIE_PHY_ROOT_CLK>; + clock-names = "pcie", "pcie_bus", "pcie_phy"; + assigned-clocks = <&clks IMX7D_PCIE_CTRL_ROOT_SRC>, + <&clks IMX7D_PCIE_PHY_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_250M_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + + fsl,max-link-speed = <2>; + power-domains = <&pgc_pcie_phy>; + resets = <&src IMX7_RESET_PCIEPHY>, + <&src IMX7_RESET_PCIE_CTRL_APPS_EN>, + <&src IMX7_RESET_PCIE_CTRL_APPS_TURNOFF>; + reset-names = "pciephy", "apps", "turnoff"; + fsl,imx7d-pcie-phy = <&pcie_phy>; + num-ib-windows = <4>; + num-ob-windows = <4>; + status = "disabled"; + }; + + rpmsg: rpmsg{ + compatible = "fsl,imx7d-rpmsg"; + /* up to now, the following channels are used in imx rpmsg + * - tx1/rx1: messages channel. + * - general interrupt1: remote proc finish re-init rpmsg stack + * when A core is partition reset. + */ + mbox-names = "tx", "rx", "rxdb"; + mboxes = <&mu 0 1 + &mu 1 1 + &mu 3 1>; + status = "disabled"; + }; }; &ca_funnel_in_ports { diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi index e2e604d6ba0b..8903c9b04ffe 100644 --- a/arch/arm/boot/dts/imx7s.dtsi +++ b/arch/arm/boot/dts/imx7s.dtsi @@ -53,19 +53,6 @@ #address-cells = <1>; #size-cells = <0>; - idle-states { - entry-method = "psci"; - - cpu_sleep_wait: cpu-sleep-wait { - compatible = "arm,idle-state"; - arm,psci-suspend-param = <0x0010000>; - local-timer-stop; - entry-latency-us = <100>; - exit-latency-us = <50>; - min-residency-us = <1000>; - }; - }; - cpu0: cpu@0 { compatible = "arm,cortex-a7"; device_type = "cpu"; @@ -73,7 +60,6 @@ clock-frequency = <792000000>; clock-latency = <61036>; /* two CLK32 periods */ clocks = <&clks IMX7D_CLK_ARM>; - cpu-idle-states = <&cpu_sleep_wait>; }; }; @@ -158,15 +144,6 @@ clocks = <&clks IMX7D_PLL_SYS_MAIN_CLK>; }; - timer { - compatible = "arm,armv7-timer"; - interrupt-parent = <&intc>; - interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, - <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, - <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, - <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>; - }; - soc { #address-cells = <1>; #size-cells = <1>; @@ -216,6 +193,11 @@ }; }; + caam_sm: caam-sm@100000 { + compatible = "fsl,imx7d-caam-sm", "fsl,imx6q-caam-sm"; + reg = <0x100000 0x8000>; + }; + funnel@30083000 { compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0x30083000 0x1000>; @@ -316,6 +298,17 @@ <0x31006000 0x2000>; }; + timer { + compatible = "arm,armv7-timer"; + arm,cpu-registers-not-fw-configured; + interrupt-parent = <&intc>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + clock-frequency = <8000000>; + }; + aips1: aips-bus@30000000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -449,8 +442,9 @@ reg = <0x302d0000 0x10000>; interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX7D_GPT1_ROOT_CLK>, - <&clks IMX7D_GPT1_ROOT_CLK>; - clock-names = "ipg", "per"; + <&clks IMX7D_GPT1_ROOT_CLK>, + <&clks IMX7D_GPT_3M_CLK>; + clock-names = "ipg", "per", "osc_per"; }; gpt2: gpt@302e0000 { @@ -593,6 +587,20 @@ }; }; + irq_sec_vio: caam_secvio { + compatible = "fsl,imx6q-caam-secvio"; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + jtag-tamper = "disabled"; + watchdog-tamper = "enabled"; + internal-boot-tamper = "enabled"; + external-pin-tamper = "disabled"; + }; + + caam_snvs: caam-snvs@30370000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x30370000 0x10000>; + }; + snvs: snvs@30370000 { compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; reg = <0x30370000 0x10000>; @@ -607,10 +615,21 @@ clock-names = "snvs-rtc"; }; + snvs_poweroff: snvs-poweroff { + compatible = "syscon-poweroff"; + regmap = <&snvs>; + offset = <0x38>; + value = <0x60>; + mask = <0x60>; + status = "disabled"; + }; + snvs_pwrkey: snvs-powerkey { compatible = "fsl,sec-v4.0-pwrkey"; regmap = <&snvs>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_SNVS_CLK>; + clock-names = "snvs"; linux,keycode = <KEY_POWER>; wakeup-source; status = "disabled"; @@ -628,7 +647,7 @@ }; src: src@30390000 { - compatible = "fsl,imx7d-src", "syscon"; + compatible = "fsl,imx7d-src", "fsl,imx51-src", "syscon"; reg = <0x30390000 0x10000>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; #reset-cells = <1>; @@ -641,6 +660,7 @@ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <3>; interrupt-parent = <&intc>; + fsl,mf-mix-wakeup-irq = <0x54010000 0xc00 0x0 0x1040640>; #power-domain-cells = <1>; pgc { @@ -658,6 +678,12 @@ reg = <1>; power-supply = <®_1p0d>; }; + + pgc_hsic_phy: power-domain@2 { + #power-domain-cells = <0>; + reg = <2>; + power-supply = <®_1p2>; + }; }; }; }; @@ -698,6 +724,8 @@ clocks = <&clks IMX7D_ECSPI4_ROOT_CLK>, <&clks IMX7D_ECSPI4_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 6 7 1>, <&sdma 7 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -767,8 +795,9 @@ reg = <0x30730000 0x10000>; interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>, - <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>; - clock-names = "pix", "axi"; + <&clks IMX7D_CLK_DUMMY>, + <&clks IMX7D_CLK_DUMMY>; + clock-names = "pix", "axi", "disp_axi"; status = "disabled"; }; @@ -800,6 +829,11 @@ }; }; }; + + ddrc: ddrc@307a0000 { + compatible = "fsl,imx7-ddrc"; + reg = <0x307a0000 0x10000>; + }; }; aips3: aips-bus@30800000 { @@ -825,6 +859,8 @@ clocks = <&clks IMX7D_ECSPI1_ROOT_CLK>, <&clks IMX7D_ECSPI1_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 0 7 1>, <&sdma 1 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -837,6 +873,8 @@ clocks = <&clks IMX7D_ECSPI2_ROOT_CLK>, <&clks IMX7D_ECSPI2_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 2 7 1>, <&sdma 3 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -849,6 +887,8 @@ clocks = <&clks IMX7D_ECSPI3_ROOT_CLK>, <&clks IMX7D_ECSPI3_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 4 7 1>, <&sdma 5 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -871,6 +911,8 @@ clocks = <&clks IMX7D_UART2_ROOT_CLK>, <&clks IMX7D_UART2_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 24 4 0>, <&sdma 25 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -882,6 +924,8 @@ clocks = <&clks IMX7D_UART3_ROOT_CLK>, <&clks IMX7D_UART3_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 26 4 0>, <&sdma 27 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1031,6 +1075,8 @@ clocks = <&clks IMX7D_UART4_ROOT_CLK>, <&clks IMX7D_UART4_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 28 4 0>, <&sdma 29 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1042,6 +1088,8 @@ clocks = <&clks IMX7D_UART5_ROOT_CLK>, <&clks IMX7D_UART5_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 30 4 0>, <&sdma 31 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1053,6 +1101,8 @@ clocks = <&clks IMX7D_UART6_ROOT_CLK>, <&clks IMX7D_UART6_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 32 4 0>, <&sdma 33 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1064,6 +1114,8 @@ clocks = <&clks IMX7D_UART7_ROOT_CLK>, <&clks IMX7D_UART7_ROOT_CLK>; clock-names = "ipg", "per"; + dmas = <&sdma 34 4 0>, <&sdma 35 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1101,6 +1153,7 @@ compatible = "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x30b30000 0x200>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&pgc_hsic_phy>; clocks = <&clks IMX7D_USB_CTRL_CLK>; fsl,usbphy = <&usbphynop3>; fsl,usbmisc = <&usbmisc3 0>; @@ -1131,6 +1184,8 @@ <&clks IMX7D_USDHC1_ROOT_CLK>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-step = <2>; + fsl,tuning-start-tap = <20>; status = "disabled"; }; @@ -1143,6 +1198,8 @@ <&clks IMX7D_USDHC2_ROOT_CLK>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-step = <2>; + fsl,tuning-start-tap = <20>; status = "disabled"; }; @@ -1155,6 +1212,8 @@ <&clks IMX7D_USDHC3_ROOT_CLK>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; + fsl,tuning-step = <2>; + fsl,tuning-start-tap = <20>; status = "disabled"; }; @@ -1181,7 +1240,7 @@ <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET1_TIME_ROOT_CLK>, <&clks IMX7D_PLL_ENET_MAIN_125M_CLK>, - <&clks IMX7D_ENET_PHY_REF_ROOT_CLK>; + <&clks IMX7D_ENET_PHY_REF_ROOT_DIV>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; fsl,num-tx-queues = <3>; diff --git a/arch/arm/boot/dts/imx7ulp-evk-ft5416.dts b/arch/arm/boot/dts/imx7ulp-evk-ft5416.dts new file mode 100644 index 000000000000..b959c6852f9a --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evk-ft5416.dts @@ -0,0 +1,15 @@ +/* + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evk.dts" +&lpi2c7 { + focaltech@38 { + focaltech,panel-type = <FT5416>; + focaltech,swap-xy; + }; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evk-mipi.dts b/arch/arm/boot/dts/imx7ulp-evk-mipi.dts new file mode 100644 index 000000000000..a467fad79846 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evk-mipi.dts @@ -0,0 +1,10 @@ +/* + * Copyright 2017-2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evk.dts" +#include "imx7ulp-evk-mipi.dtsi" diff --git a/arch/arm/boot/dts/imx7ulp-evk-mipi.dtsi b/arch/arm/boot/dts/imx7ulp-evk-mipi.dtsi new file mode 100644 index 000000000000..4caeefbf3b68 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evk-mipi.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright 2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +&adv7535 { + status = "disabled"; + + /delete-node/ port; +}; + +&mipi_dsi { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_mipi_dsi_reset>; + pinctrl-1 = <&pinctrl_mipi_dsi_reset>; + lcd_panel = "TRULY-WVGA-TFT3P5581E"; + resets = <&mipi_dsi_reset>; + + /delete-node/ port; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evk.dts b/arch/arm/boot/dts/imx7ulp-evk.dts index 4245b33bb451..927c281f2c01 100644 --- a/arch/arm/boot/dts/imx7ulp-evk.dts +++ b/arch/arm/boot/dts/imx7ulp-evk.dts @@ -8,11 +8,17 @@ /dts-v1/; #include "imx7ulp.dtsi" +#include <dt-bindings/input/input.h> / { model = "NXP i.MX7ULP EVK"; compatible = "fsl,imx7ulp-evk", "fsl,imx7ulp"; + aliases { + gpio4 = &rpmsg_gpio0; + gpio5 = &rpmsg_gpio1; + }; + chosen { stdout-path = &lpuart4; }; @@ -22,6 +28,33 @@ reg = <0x60000000 0x40000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + vdev0vring0: vdev0vring0@9ff00000 { + reg = <0x9ff00000 0x8000>; + no-map; + }; + vdev0vring1: vdev0vring1@9ff08000 { + reg = <0x9ff08000 0x8000>; + no-map; + }; + vdev1vring0: vdev1vring0@9ff10000 { + reg = <0x9ff10000 0x8000>; + no-map; + }; + vdev1vring1: vdev1vring1@9ff18000 { + reg = <0x9ff18000 0x8000>; + no-map; + }; + vdev1vring3 { + reg = <0x9ff20000 0xe0000>; + no-map; + }; + }; + backlight { compatible = "pwm-backlight"; pwms = <&tpm4 1 50000 0>; @@ -30,35 +63,367 @@ status = "okay"; }; - reg_usb_otg1_vbus: regulator-usb-otg1-vbus { - compatible = "regulator-fixed"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg1_vbus>; - regulator-name = "usb_otg1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio_ptc 0 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; - - reg_vsd_3v3: regulator-vsd-3v3 { - compatible = "regulator-fixed"; - regulator-name = "VSD_3V3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; + mipi_dsi_reset: mipi-dsi-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio_ptc 19 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + modem_reset: modem-reset { + compatible = "gpio-reset"; + reset-gpios = <&rpmsg_gpio0 15 GPIO_ACTIVE_LOW>; + reset-delay-us = <1000>; + #reset-cells = <0>; + }; + + pf1550-rpmsg { + compatible = "fsl,pf1550-rpmsg"; + sw1_reg: SW1 { + regulator-name = "SW1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1387500>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: SW2 { + regulator-name = "SW2"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1387500>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: SW3 { + regulator-name = "SW3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: VREFDDR { + regulator-name = "VREFDDR"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + + vldo1_reg: LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vldo2_reg: LDO2 { + regulator-name = "LDO2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vldo3_reg: LDO3 { + regulator-name = "LDO3"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cell = <1>; + #size-cells = <0>; + + reg_usb_otg1_vbus: regulator-usb-otg1-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_usbotg1_vbus>; + pinctrl-1 = <&pinctrl_usbotg1_vbus>; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio_ptc 0 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_vsd_3v3: regulator-vsd-3v3 { + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc0_rst>; + gpio = <&gpio_ptd 0 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; + enable-active-high; + }; + + reg_sd1_vmmc: sd1_regulator { + compatible = "regulator-fixed"; + regulator-name = "WLAN_EN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&rpmsg_gpio0 14 GPIO_ACTIVE_HIGH>; + startup-delay-us = <100>; + off-on-delay-us = <20000>; + enable-active-high; + }; + }; + + rpmsg_gpio0: rpmsg-gpio0 { + compatible = "fsl,imx-rpmsg-gpio"; + port_idx = <0>; + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&rpmsg_gpio0>; + status = "okay"; + }; + + rpmsg_gpio1: rpmsg-gpio1 { + compatible = "fsl,imx-rpmsg-gpio"; + port_idx = <1>; + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&rpmsg_gpio1>; + status = "okay"; + }; + + rpmsg_keys: rpmsg-keys { + compatible = "fsl,rpmsg-keys"; + + volume-up { + label = "Volume Up"; + linux,code = <KEY_VOLUMEUP>; + }; + + volume-down { + label = "Volume Down"; + linux,code = <KEY_VOLUMEDOWN>; + }; + + power-on { + label = "PowerOn"; + linux,code = <KEY_POWER>; + rpmsg-key,wakeup; + }; + }; + + rpmsg_sensor: rpmsg-sensor { + compatible = "fsl,rpmsg-input"; + }; + + rpmsg_i2s: rpmsg-i2s { + compatible = "fsl,imx7ulp-rpmsg-i2s"; + /* the audio device index in m4 domain */ + fsl,audioindex = <0> ; + status = "okay"; + }; + + sound-rpmsg { + compatible = "fsl,imx-audio-rpmsg"; + model = "wm8960-audio"; + cpu-dai = <&rpmsg_i2s>; + rpmsg-out; + rpmsg-in; + audio-routing = + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "LINPUT2", "Mic Jack", + "LINPUT3", "Mic Jack", + "RINPUT1", "Main MIC", + "RINPUT2", "Main MIC", + "Mic Jack", "MICB", + "Main MIC", "MICB", + "Playback", "CPU-Playback", + "CPU-Capture", "Capture"; + }; + + imx7ulp-cm4 { + compatible = "fsl,imx7ulp-cm4"; + ipc-only; + rsc-da=<0x1fff8000>; + mbox-names = "tx", "rx", "rxdb"; + mboxes = <&mu 0 1 + &mu 1 1 + &mu 3 1>; + memory-region = <&vdev0vring0>, <&vdev0vring1>, + <&vdev1vring0>, <&vdev1vring1>; + }; +}; + +&cpu0 { + arm-supply= <&sw1_reg>; +}; + +&lpspi3 { + fsl,spi-num-chipselects = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpspi3>; + pinctrl-1 = <&pinctrl_lpspi3>; + status = "okay"; + + spidev0: spi@0 { + reg = <0>; + compatible = "rohm,dh2228fv"; + spi-max-frequency = <1000000>; + }; +}; + +&lpi2c5 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpi2c5>; + pinctrl-1 = <&pinctrl_lpi2c5>; + status = "okay"; + + adv7535: adv7535@3d { + compatible = "adi,adv7535"; + reg = <0x3d>; /* PD pin is low */ pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc0_rst>; - gpio = <&gpio_ptd 0 GPIO_ACTIVE_HIGH>; - enable-active-high; + pinctrl-0 = <&pinctrl_dsi_hdmi>; + interrupt-parent = <&gpio_ptc>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + video-mode = <1>; /* + * Only support CEA modes. + * Reference mxc_edid.c + */ + dsi-traffic-mode = <0>; + bpp = <24>; + status = "disabled"; + }; +}; + +&lcdif { + status = "okay"; + disp-dev = "mipi_dsi_northwest"; + display = <&display0>; + + display0: display@0 { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; }; }; &lpuart4 { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&pinctrl_lpuart4>; + pinctrl-1 = <&pinctrl_lpuart4>; + status = "okay"; +}; + +&lpuart6 { /* BT */ + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpuart6>; + pinctrl-1 = <&pinctrl_lpuart6>; + resets = <&modem_reset>; status = "okay"; }; +&lpuart7 { /* Uart test */ + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpuart7>; + pinctrl-1 = <&pinctrl_lpuart7>; + status = "disabled"; +}; + +&lpi2c7 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpi2c7 &pinctrl_touch_io>; + pinctrl-1 = <&pinctrl_lpi2c7 &pinctrl_touch_io>; + status = "okay"; + + focaltech@38 { + compatible = "focaltech,fts"; + reg = <0x38>; + interrupt-parent = <&gpio_ptf>; + interrupts = <0 0x2>; + focaltech,panel-type = <FT5426>; + focaltech,reset-gpio = <&gpio_ptf 1 0x1>; + focaltech,irq-gpio = <&gpio_ptf 0 0x2>; + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 480 854>; + + focaltech,have-key; + focaltech,key-number = <3>; + focaltech,keys = <139 102 158>; + focaltech,key-y-coord = <2000>; + focaltech,key-x-coords = <200 600 800>; + }; +}; + +&adv7535 { + status = "okay"; + + port { + dsi_to_hdmi: endpoint { + remote-endpoint = <&mipi_dsi_ep>; + }; + }; +}; + +&mipi_dsi { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_mipi_dsi_reset>; + pinctrl-1 = <&pinctrl_mipi_dsi_reset>; + lcd_panel = "TRULY-WVGA-TFT3P5581E"; + resets = <&mipi_dsi_reset>; + status = "okay"; + + port { + mipi_dsi_ep: endpoint { + remote-endpoint = <&dsi_to_hdmi>; + }; + }; +}; + +&rpmsg{ + /* + * 64K for one rpmsg instance, default using 2 rpmsg instances: + * --0x9FF00000~0x9FF0FFFF: pmic,pm,audio,keys,gpio,sensor + * --0x9FF10000~0x9FF1FFFF: pingpong,virtual tty + */ + vdev-nums = <2>; + reg = <0x9FF00000 0x20000>; + status = "disabled"; +}; + &tpm4 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm0>; @@ -67,24 +432,60 @@ &usbotg1 { vbus-supply = <®_usb_otg1_vbus>; - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&pinctrl_usbotg1_id>; + pinctrl-1 = <&pinctrl_usbotg1_id>; srp-disable; hnp-disable; adp-disable; - over-current-active-low; + disable-over-current; status = "okay"; }; +&usbphy1 { + fsl,tx-d-cal = <106>; +}; + &usdhc0 { - pinctrl-names = "default"; + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; pinctrl-0 = <&pinctrl_usdhc0>; + pinctrl-1 = <&pinctrl_usdhc0>; + pinctrl-2 = <&pinctrl_usdhc0>; + pinctrl-3 = <&pinctrl_usdhc0>; + fsl,delay-line = <15>; cd-gpios = <&gpio_ptc 10 GPIO_ACTIVE_LOW>; vmmc-supply = <®_vsd_3v3>; + vqmmc-supply = <&vldo2_reg>; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1>; + bus-width = <4>; + no-1-8-v; + vmmc-supply = <®_sd1_vmmc>; + pm-ignore-notify; + keep-power-in-suspend; + non-removable; status = "okay"; }; &iomuxc1 { + pinctrl_lpi2c5: lpi2c5grp { + fsl,pins = < + IMX7ULP_PAD_PTC4__LPI2C5_SCL 0x27 + IMX7ULP_PAD_PTC5__LPI2C5_SDA 0x27 + >; + }; + + pinctrl_mipi_dsi_reset: mipi_dsi_reset_grp { + fsl,pins = < + IMX7ULP_PAD_PTC19__PTC19 0x20003 + >; + }; + pinctrl_lpuart4: lpuart4grp { fsl,pins = < IMX7ULP_PAD_PTC3__LPUART4_RX 0x3 @@ -93,12 +494,54 @@ bias-pull-up; }; + pinctrl_lpuart6: lpuart6grp { + fsl,pins = < + IMX7ULP_PAD_PTE10__LPUART6_TX 0x3 + IMX7ULP_PAD_PTE11__LPUART6_RX 0x3 + IMX7ULP_PAD_PTE9__LPUART6_RTS_B 0x3 + IMX7ULP_PAD_PTE8__LPUART6_CTS_B 0x3 + IMX7ULP_PAD_PTE7__PTE7 0x20000 /* BT_REG_ON */ + >; + }; + + pinctrl_lpuart7: lpuart7grp { + fsl,pins = < + IMX7ULP_PAD_PTF14__LPUART7_TX 0x3 + IMX7ULP_PAD_PTF15__LPUART7_RX 0x3 + IMX7ULP_PAD_PTF13__LPUART7_RTS_B 0x3 + IMX7ULP_PAD_PTF12__LPUART7_CTS_B 0x3 + >; + }; + + pinctrl_lpi2c7: lpi2c7grp { + fsl,pins = < + IMX7ULP_PAD_PTF12__LPI2C7_SCL 0x27 + IMX7ULP_PAD_PTF13__LPI2C7_SDA 0x27 + >; + }; + + pinctrl_touch_io: touchiogrp { + fsl,pins = < + IMX7ULP_PAD_PTF0__PTF0 0x10043 + IMX7ULP_PAD_PTF1__PTF1 0x20043 + >; + }; + pinctrl_pwm0: pwm0grp { fsl,pins = < IMX7ULP_PAD_PTF2__TPM4_CH1 0x2 >; }; + pinctrl_lpspi3: lpspi3grp { + fsl,pins = < + IMX7ULP_PAD_PTF16__LPSPI3_SIN 0x0 + IMX7ULP_PAD_PTF17__LPSPI3_SOUT 0x0 + IMX7ULP_PAD_PTF18__LPSPI3_SCK 0x0 + IMX7ULP_PAD_PTF19__LPSPI3_PCS0 0x0 + >; + }; + pinctrl_usbotg1_vbus: otg1vbusgrp { fsl,pins = < IMX7ULP_PAD_PTC0__PTC0 0x20000 @@ -108,7 +551,6 @@ pinctrl_usbotg1_id: otg1idgrp { fsl,pins = < IMX7ULP_PAD_PTC13__USB0_ID 0x10003 - IMX7ULP_PAD_PTC16__USB1_OC2 0x10003 >; }; @@ -124,9 +566,51 @@ >; }; + pinctrl_usdhc0_8bit: usdhc0grp_8bit { + fsl,pins = < + IMX7ULP_PAD_PTD1__SDHC0_CMD 0x43 + IMX7ULP_PAD_PTD2__SDHC0_CLK 0x10042 + IMX7ULP_PAD_PTD3__SDHC0_D7 0x43 + IMX7ULP_PAD_PTD4__SDHC0_D6 0x43 + IMX7ULP_PAD_PTD5__SDHC0_D5 0x43 + IMX7ULP_PAD_PTD6__SDHC0_D4 0x43 + IMX7ULP_PAD_PTD7__SDHC0_D3 0x43 + IMX7ULP_PAD_PTD8__SDHC0_D2 0x43 + IMX7ULP_PAD_PTD9__SDHC0_D1 0x43 + IMX7ULP_PAD_PTD10__SDHC0_D0 0x43 + IMX7ULP_PAD_PTD11__SDHC0_DQS 0x42 + >; + }; + pinctrl_usdhc0_rst: usdhc0-gpio-rst-grp { fsl,pins = < IMX7ULP_PAD_PTD0__PTD0 0x3 >; }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + IMX7ULP_PAD_PTE3__SDHC1_CMD 0x43 + IMX7ULP_PAD_PTE2__SDHC1_CLK 0x10042 + IMX7ULP_PAD_PTE1__SDHC1_D0 0x43 + IMX7ULP_PAD_PTE0__SDHC1_D1 0x43 + IMX7ULP_PAD_PTE5__SDHC1_D2 0x43 + IMX7ULP_PAD_PTE4__SDHC1_D3 0x43 + >; + }; + + pinctrl_usdhc1_rst: usdhc1grp_rst { + fsl,pins = < + IMX7ULP_PAD_PTE11__PTE11 0x20000 /* USDHC1 RST */ + IMX7ULP_PAD_PTE13__PTE13 0x10003 /* USDHC1 CD */ + IMX7ULP_PAD_PTE12__PTE12 0x10003 /* USDHC1 WP */ + IMX7ULP_PAD_PTE14__SDHC1_VS 0x43 /* USDHC1 VSEL */ + >; + }; + + pinctrl_dsi_hdmi: dsi_hdmi_grp { + fsl,pins = < + IMX7ULP_PAD_PTC18__PTC18 0x10003 /* DSI_HDMI_INT */ + >; + }; }; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-emmc.dts b/arch/arm/boot/dts/imx7ulp-evkb-emmc.dts new file mode 100644 index 000000000000..ca6acd44de19 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-emmc.dts @@ -0,0 +1,26 @@ +/* + * Copyright 2019 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb.dts" + +/* To support eMMC HS200/HS400, need to do the following reowrk: + * 1,remove TF sd slot, replace eMMC chip + * 2,fix eMMC I/O voltage to 1.8v, remove R183, short TP3 and TP89 + * 3,add R107, make eMMC boot work + */ +&usdhc0 { + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; + pinctrl-0 = <&pinctrl_usdhc0_8bit>; + pinctrl-1 = <&pinctrl_usdhc0_8bit>; + pinctrl-2 = <&pinctrl_usdhc0_8bit>; + pinctrl-3 = <&pinctrl_usdhc0_8bit>; + non-removable; + bus-width = <8>; + status = "okay"; +}; + diff --git a/arch/arm/boot/dts/imx7ulp-evkb-lpuart.dts b/arch/arm/boot/dts/imx7ulp-evkb-lpuart.dts new file mode 100644 index 000000000000..1a5da007edf6 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-lpuart.dts @@ -0,0 +1,17 @@ +/* + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb.dts" + +&lpi2c7 { + status = "disabled"; +}; + +&lpuart7 { /* Uart test */ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-mipi.dts b/arch/arm/boot/dts/imx7ulp-evkb-mipi.dts new file mode 100644 index 000000000000..0ebf73f2618a --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-mipi.dts @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb.dts" +#include "imx7ulp-evk-mipi.dtsi" + +&lpi2c7 { + focaltech@38 { + status = "disabled"; + }; + + goodix@14 { + compatible = "goodix,gt911"; + reg = <0x14>; + interrupt-parent = <&gpio_ptf>; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + irq-gpios = <&gpio_ptf 0 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio_ptf 1 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-rm68191-qhd.dts b/arch/arm/boot/dts/imx7ulp-evkb-rm68191-qhd.dts new file mode 100644 index 000000000000..c482087c08e0 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-rm68191-qhd.dts @@ -0,0 +1,13 @@ +/* + * Copyright 2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb-mipi.dts" + +&mipi_dsi { + lcd_panel = "ROCKTECH-QHD-RK055IQH042"; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-rm68200-wxga.dts b/arch/arm/boot/dts/imx7ulp-evkb-rm68200-wxga.dts new file mode 100644 index 000000000000..28b83c388101 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-rm68200-wxga.dts @@ -0,0 +1,13 @@ +/* + * Copyright 2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb-mipi.dts" + +&mipi_dsi { + lcd_panel = "ROCKTECH-WXGA-RK055AHD042"; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-sd1.dts b/arch/arm/boot/dts/imx7ulp-evkb-sd1.dts new file mode 100644 index 000000000000..8984a6ace291 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-sd1.dts @@ -0,0 +1,45 @@ +/* + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb.dts" + +/ { + regulators { + reg_vsd_3v3b: regulator@2 { + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3B"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio_pte 11 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; + enable-active-high; + }; + }; +}; + +&lpuart6 { + status = "disabled"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; + pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_usdhc1_rst>; + pinctrl-1 = <&pinctrl_usdhc1 &pinctrl_usdhc1_rst>; + pinctrl-2 = <&pinctrl_usdhc1 &pinctrl_usdhc1_rst>; + pinctrl-3 = <&pinctrl_usdhc1 &pinctrl_usdhc1_rst>; + cd-gpios = <&gpio_pte 13 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio_pte 12 GPIO_ACTIVE_HIGH>; + fsl,delay-line = <15>; + vmmc-supply = <®_vsd_3v3b>; + /delete-property/non-removable; + /delete-property/pm-ignore-notify; + /delete-property/keep-power-in-suspend; + /delete-property/non-removable; + /delete-property/no-1-8-v; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-sensors-to-i2c5.dts b/arch/arm/boot/dts/imx7ulp-evkb-sensors-to-i2c5.dts new file mode 100644 index 000000000000..83a712b9b4f3 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-sensors-to-i2c5.dts @@ -0,0 +1,21 @@ + +#include "imx7ulp-evkb.dts" + +&lpi2c5 { + + fxas2100x@20 { + compatible = "fsl,fxas2100x"; + reg = <0x20>; + }; + + fxos8700@1e { + compatible = "fsl,fxos8700"; + reg = <0x1e>; + }; + + mpl3115@60 { + compatible = "fsl,mpl3115"; + reg = <0x60>; + }; + +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb-spi-slave.dts b/arch/arm/boot/dts/imx7ulp-evkb-spi-slave.dts new file mode 100644 index 000000000000..83cb121ff50a --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb-spi-slave.dts @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evkb.dts" + +/delete-node/&spidev0; + +&pinctrl_lpspi3 { + fsl,pins = < + IMX7ULP_PAD_PTF16__LPSPI3_SIN 0x0 + IMX7ULP_PAD_PTF17__LPSPI3_SOUT 0x0 + IMX7ULP_PAD_PTF18__LPSPI3_SCK 0x0 + IMX7ULP_PAD_PTF19__LPSPI3_PCS0 0x0 + >; +}; + +&lpspi3 { + #address-cells = <0>; + pinctrl-0 = <&pinctrl_lpspi3>; + pinctrl-1 = <&pinctrl_lpspi3>; + /delete-property/ cs-gpios; + + spi-slave; +}; diff --git a/arch/arm/boot/dts/imx7ulp-evkb.dts b/arch/arm/boot/dts/imx7ulp-evkb.dts new file mode 100644 index 000000000000..37df89558349 --- /dev/null +++ b/arch/arm/boot/dts/imx7ulp-evkb.dts @@ -0,0 +1,39 @@ +/* + * Copyright 2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7ulp-evk.dts" + +/ { + model = "NXP i.MX7ULP EVKB"; + compatible = "fsl,imx7ulp-evkb", "fsl,imx7ulp", "Generic DT based system"; + + regulators { + reg_sd1_vmmc: sd1_regulator { + status = "disabled"; + }; + }; + + usdhc1_pwrseq: usdhc1_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&rpmsg_gpio0 14 GPIO_ACTIVE_LOW>; + post-power-on-delay-ms = <80>; + }; +}; + +&usdhc1 { + #address-cells = <1>; + #size-cells = <0>; + /delete-property/ vmmc-supply; + mmc-pwrseq = <&usdhc1_pwrseq>; + cap-power-off-card; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi index 0108b63df77d..471cd61cb6de 100644 --- a/arch/arm/boot/dts/imx7ulp.dtsi +++ b/arch/arm/boot/dts/imx7ulp.dtsi @@ -41,9 +41,41 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0xf00>; + operating-points = < + /* KHz uV */ + 720000 1125000 + 500210 1025000 + >; + clocks = <&smc1 IMX7ULP_CLK_ARM>, + <&scg1 IMX7ULP_CLK_CORE_DIV>, + <&scg1 IMX7ULP_CLK_SYS_SEL>, + <&scg1 IMX7ULP_CLK_HSRUN_SYS_SEL>, + <&scg1 IMX7ULP_CLK_HSRUN_CORE_DIV>, + <&scg1 IMX7ULP_CLK_SPLL_PFD0>, + <&scg1 IMX7ULP_CLK_SPLL_SEL>, + <&scg1 IMX7ULP_CLK_FIRC>, + <&scg1 IMX7ULP_CLK_SPLL>; + clock-names = "arm", "core_div", "sys_sel", "hsrun_sys_sel", + "hsrun_core", "spll_pfd0", "spll_sel", "firc", + "spll"; }; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0xC000000>; + alignment = <0x2000>; + linux,cma-default; + }; + }; + intc: interrupt-controller@40021000 { compatible = "arm,cortex-a7-gic"; #interrupt-cells = <3>; @@ -87,11 +119,14 @@ #clock-cells = <0>; }; - mpll: clock-mpll { - compatible = "fixed-clock"; - clock-frequency = <480000000>; - clock-output-names = "mpll"; - #clock-cells = <0>; + sram: sram@20000000 { + compatible = "fsl,lpm-sram"; + reg = <0x1fffc000 0x4000>; + }; + + caam_sm: caam-sm@26000000 { + compatible = "fsl,imx6q-caam-sm"; + reg = <0x26000000 0x8000>; }; ahbbridge0: bus@40000000 { @@ -129,6 +164,62 @@ <&pcc2 IMX7ULP_CLK_DMA_MUX1>; }; + mu: mu@40220000 { + compatible = "fsl,imx7ulp-mu"; + reg = <0x40220000 0x1000>; + interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + }; + + nmi: nmi@40220000 { + compatible = "fsl,imx7ulp-nmi"; + reg = <0x40220000 0x1000>; + interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + }; + + mu_lp: mu_lp@40220000 { + compatible = "fsl,imx7ulp-mu-lp", "fsl,imx6sx-mu-lp"; + reg = <0x40220000 0x1000>; + interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + }; + + lpspi2: spi@40290000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx7ulp-spi"; + reg = <0x40290000 0x10000>; + interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc2 IMX7ULP_CLK_LPSPI2>, + <&pcc2 IMX7ULP_CLK_DUMMY>; + clock-names = "per", "ipg"; + assigned-clocks = <&pcc2 IMX7ULP_CLK_LPSPI2>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; + assigned-clock-rates = <48000000>; + dmas = <&edma1 0 26>, <&edma1 0 25>; + dma-names = "tx","rx"; + status = "disabled"; + }; + + lpspi3: spi@402A0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx7ulp-spi"; + reg = <0x402A0000 0x10000>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc2 IMX7ULP_CLK_LPSPI3>, + <&pcc2 IMX7ULP_CLK_DUMMY>; + clock-names = "per", "ipg"; + assigned-clocks = <&pcc2 IMX7ULP_CLK_LPSPI3>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; + assigned-clock-rates = <48000000>; + dmas = <&edma1 0 28>, <&edma1 0 27>; + dma-names = "tx","rx"; + status = "disabled"; + }; + crypto: crypto@40240000 { compatible = "fsl,sec-v4.0"; #address-cells = <1>; @@ -152,6 +243,31 @@ }; }; + lpi2c4: lpi2c4@402b0000 { + compatible = "fsl,imx7ulp-lpi2c"; + reg = <0x402b0000 0x10000>; + interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc2 IMX7ULP_CLK_LPI2C4>, + <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>; + clock-names = "per", "ipg"; + assigned-clocks = <&pcc2 IMX7ULP_CLK_LPI2C4>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; + assigned-clock-rates = <48000000>; + status = "disabled"; + }; + + lpi2c5: lpi2c5@402c0000 { + compatible = "fsl,imx7ulp-lpi2c"; + reg = <0x402c0000 0x10000>; + interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc2 IMX7ULP_CLK_LPI2C5>, + <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>; + clock-names = "per", "ipg"; + assigned-clocks = <&pcc2 IMX7ULP_CLK_LPI2C5>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; + assigned-clock-rates = <48000000>; + }; + lpuart4: serial@402d0000 { compatible = "fsl,imx7ulp-lpuart"; reg = <0x402d0000 0x1000>; @@ -171,8 +287,10 @@ clocks = <&pcc2 IMX7ULP_CLK_LPUART5>; clock-names = "ipg"; assigned-clocks = <&pcc2 IMX7ULP_CLK_LPUART5>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; assigned-clock-rates = <48000000>; + dmas = <&edma1 0 20>, <&edma1 0 19>; + dma-names = "tx","rx"; status = "disabled"; }; @@ -220,6 +338,7 @@ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; clocks = <&pcc2 IMX7ULP_CLK_USB_PHY>; #phy-cells = <0>; + nxp,sim = <&sim>; }; usdhc0: mmc@40370000 { @@ -230,8 +349,9 @@ <&scg1 IMX7ULP_CLK_NIC1_DIV>, <&pcc2 IMX7ULP_CLK_USDHC0>; clock-names = "ipg", "ahb", "per"; - assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC0>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>; + assigned-clocks = <&scg1 IMX7ULP_CLK_APLL_PFD1>, <&pcc2 IMX7ULP_CLK_USDHC0>; + assigned-clock-parents = <0>, <&scg1 IMX7ULP_CLK_APLL_PFD1>; + assigned-clock-rates = <0>, <352800000>; bus-width = <4>; fsl,tuning-start-tap = <20>; fsl,tuning-step = <2>; @@ -246,8 +366,9 @@ <&scg1 IMX7ULP_CLK_NIC1_DIV>, <&pcc2 IMX7ULP_CLK_USDHC1>; clock-names = "ipg", "ahb", "per"; - assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC1>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>; + assigned-clocks = <&scg1 IMX7ULP_CLK_APLL_PFD1>, <&pcc2 IMX7ULP_CLK_USDHC1>; + assigned-clock-parents = <0>, <&scg1 IMX7ULP_CLK_APLL_PFD1>; + assigned-clock-rates = <0>, <352800000>; bus-width = <4>; fsl,tuning-start-tap = <20>; fsl,tuning-step = <2>; @@ -258,12 +379,37 @@ compatible = "fsl,imx7ulp-scg1"; reg = <0x403e0000 0x10000>; clocks = <&rosc>, <&sosc>, <&sirc>, - <&firc>, <&upll>, <&mpll>; + <&firc>, <&upll>; clock-names = "rosc", "sosc", "sirc", - "firc", "upll", "mpll"; + "firc", "upll"; #clock-cells = <1>; }; + wdog1: wdog@403D0000 { + compatible = "fsl,imx7ulp-wdt"; + reg = <0x403D0000 0x10000>; + interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc2 IMX7ULP_CLK_WDG1>; + assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG1>; + assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; + /* + * As the 1KHz LPO clock rate is not trimed,the actually clock + * is about 667Hz, so the init timeout 60s should set 40*1000 + * in the TOVAL register. + */ + timeout-sec = <40>; + }; + + wdog2: wdog@40430000 { + compatible = "fsl,imx7ulp-wdt"; + reg = <0x40430000 0x10000>; + interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc2 IMX7ULP_CLK_WDG2>; + assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG2>; + assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; + timeout-sec = <40>; + }; + pcc2: clock-controller@403f0000 { compatible = "fsl,imx7ulp-pcc2"; reg = <0x403f0000 0x10000>; @@ -276,18 +422,22 @@ <&scg1 IMX7ULP_CLK_APLL_PFD0>, <&scg1 IMX7ULP_CLK_UPLL>, <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>, - <&scg1 IMX7ULP_CLK_MIPI_PLL>, <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>, <&scg1 IMX7ULP_CLK_ROSC>, <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>; clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", - "upll", "sosc_bus_clk", "mpll", + "upll", "sosc_bus_clk", "firc_bus_clk", "rosc", "spll_bus_clk"; assigned-clocks = <&pcc2 IMX7ULP_CLK_LPTPM5>; assigned-clock-parents = <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>; }; + pmc1: pmc1@40400000 { + compatible = "fsl,imx7ulp-pmc1"; + reg = <0x40400000 0x1000>; + }; + smc1: clock-controller@40410000 { compatible = "fsl,imx7ulp-smc1"; reg = <0x40410000 0x1000>; @@ -309,13 +459,12 @@ <&scg1 IMX7ULP_CLK_APLL_PFD0>, <&scg1 IMX7ULP_CLK_UPLL>, <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>, - <&scg1 IMX7ULP_CLK_MIPI_PLL>, <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>, <&scg1 IMX7ULP_CLK_ROSC>, <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>; clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", - "upll", "sosc_bus_clk", "mpll", + "upll", "sosc_bus_clk", "firc_bus_clk", "rosc", "spll_bus_clk"; }; }; @@ -331,10 +480,11 @@ compatible = "fsl,imx7ulp-lpi2c"; reg = <0x40a40000 0x10000>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>; - clock-names = "ipg"; + clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>, + <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>; + clock-names = "per", "ipg"; assigned-clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; assigned-clock-rates = <48000000>; status = "disabled"; }; @@ -343,10 +493,11 @@ compatible = "fsl,imx7ulp-lpi2c"; reg = <0x40a50000 0x10000>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>; - clock-names = "ipg"; + clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>, + <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>; + clock-names = "per", "ipg"; assigned-clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; assigned-clock-rates = <48000000>; status = "disabled"; }; @@ -358,8 +509,10 @@ clocks = <&pcc3 IMX7ULP_CLK_LPUART6>; clock-names = "ipg"; assigned-clocks = <&pcc3 IMX7ULP_CLK_LPUART6>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; assigned-clock-rates = <48000000>; + dmas = <&edma1 0 22>, <&edma1 0 21>; + dma-names = "tx","rx"; status = "disabled"; }; @@ -370,8 +523,34 @@ clocks = <&pcc3 IMX7ULP_CLK_LPUART7>; clock-names = "ipg"; assigned-clocks = <&pcc3 IMX7ULP_CLK_LPUART7>; - assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>; + assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>; assigned-clock-rates = <48000000>; + dmas = <&edma1 0 24>, <&edma1 0 23>; + dma-names = "tx","rx"; + status = "disabled"; + }; + + mipi_dsi: mipi_dsi@40a90000 { + compatible = "fsl,imx7ulp-mipi-dsi"; + reg = <0x40a90000 0x1000>; + interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pcc3 IMX7ULP_CLK_DSI>; + clock-names = "mipi_dsi_clk"; + data-lanes-num = <2>; + phy-ref-clkfreq = <24000000>; + max-data-rate = <800000000>; + sim = <&sim>; + status = "disabled"; + }; + + lcdif: lcdif@40aa0000 { + compatible = "fsl,imx7ulp-lcdif"; + reg = <0x40aa0000 0x1000>; + interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&scg1 IMX7ULP_CLK_DUMMY>, + <&pcc3 IMX7ULP_CLK_LCDIF>, + <&scg1 IMX7ULP_CLK_DUMMY>; + clock-names = "axi", "pix", "disp_axi"; status = "disabled"; }; @@ -441,6 +620,28 @@ clock-names = "gpio", "port"; gpio-ranges = <&iomuxc1 0 96 20>; }; + + gpu: gpu@41800000 { + compatible = "fsl,imx7ulp-gpu", "fsl,imx6q-gpu"; + reg = <0x41800000 0x80000>, <0x41880000 0x80000>, + <0x60000000 0x40000000>, <0x0 0x4000000>; + reg-names = "iobase_3d", "iobase_2d", + "phys_baseaddr", "contiguous_mem"; + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "irq_3d", "irq_2d"; + clocks = <&pcc3 IMX7ULP_CLK_GPU3D>, + <&scg1 IMX7ULP_CLK_DUMMY>, + <&scg1 IMX7ULP_CLK_GPU_DIV>, + <&pcc3 IMX7ULP_CLK_GPU2D>, + <&scg1 IMX7ULP_CLK_NIC1_DIV>; + clock-names = "gpu3d_clk", "gpu3d_shader_clk", + "gpu3d_axi_clk", "gpu2d_clk", + "gpu2d_axi_clk"; + assigned-clocks = <&scg1 IMX7ULP_CLK_APLL_PFD2>, <&pcc3 IMX7ULP_CLK_GPU3D>, <&pcc3 IMX7ULP_CLK_GPU2D>; + assigned-clock-parents = <0>, <&scg1 IMX7ULP_CLK_APLL_PFD2>, <&scg1 IMX7ULP_CLK_APLL_PFD2>; + assigned-clock-rates = <400000000>, <400000000>, <400000000>; + }; }; m4aips1: bus@41080000 { @@ -450,6 +651,11 @@ reg = <0x41080000 0x80000>; ranges; + pmc0: pmc0@410a1000 { + compatible = "fsl,imx7ulp-pmc0"; + reg = <0x410a1000 0x1000>; + }; + sim: sim@410a3000 { compatible = "fsl,imx7ulp-sim", "syscon"; reg = <0x410a3000 0x1000>; @@ -461,4 +667,27 @@ clocks = <&scg1 IMX7ULP_CLK_DUMMY>; }; }; + + rpmsg: rpmsg{ + compatible = "fsl,imx7ulp-rpmsg"; + /* up to now, the following channels are used in imx rpmsg + * - tx1/rx1: messages channel. + * - general interrupt1: remote proc finish re-init rpmsg stack + * when A core is partition reset. + */ + mbox-names = "tx", "rx", "rxdb"; + mboxes = <&mu 0 1 + &mu 1 1 + &mu 3 1>; + status = "disabled"; + }; + + heartbeat-rpmsg { + compatible = "fsl,heartbeat-rpmsg"; + }; + + rtc-rpmsg { + compatible = "fsl,imx-rpmsg-rtc"; + }; + }; diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts index 74a67604876c..ee718b5b7b0e 100644 --- a/arch/arm/boot/dts/ls1021a-qds.dts +++ b/arch/arm/boot/dts/ls1021a-qds.dts @@ -126,6 +126,21 @@ }; }; +&qspi { + num-cs = <2>; + status = "okay"; + + qflash0: s25fl128s@0 { + compatible = "spansion,m25p80"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <20000000>; + reg = <0>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; + }; +}; + &enet0 { tbi-handle = <&tbi0>; phy-handle = <&sgmii_phy1c>; @@ -150,6 +165,10 @@ status = "okay"; }; +&esdhc { + status = "okay"; +}; + &i2c0 { status = "okay"; diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts index 9b1fe99d55b1..0ca4ebfc0304 100644 --- a/arch/arm/boot/dts/ls1021a-twr.dts +++ b/arch/arm/boot/dts/ls1021a-twr.dts @@ -144,6 +144,21 @@ }; }; +&qspi { + num-cs = <2>; + status = "okay"; + + qflash0: n25q128a13@0 { + compatible = "n25q128a13", "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <20000000>; + reg = <0>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; + }; +}; + &enet0 { tbi-handle = <&tbi0>; phy-handle = <&sgmii_phy2>; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index c62fcca7b426..8a9f132a32c1 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -66,6 +66,7 @@ serial4 = &lpuart4; serial5 = &lpuart5; sysclk = &sysclk; + rtc1 = &ftm_alarm0; }; cpus { @@ -167,12 +168,13 @@ ifc: ifc@1530000 { compatible = "fsl,ifc", "simple-bus"; reg = <0x0 0x1530000 0x0 0x10000>; + big-endian; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; }; dcfg: dcfg@1ee0000 { compatible = "fsl,ls1021a-dcfg", "syscon"; - reg = <0x0 0x1ee0000 0x0 0x10000>; + reg = <0x0 0x1ee0000 0x0 0x1000>; big-endian; }; @@ -371,7 +373,7 @@ }; i2c0: i2c@2180000 { - compatible = "fsl,vf610-i2c"; + compatible = "fsl,vf610-i2c", "fsl,ls1021a-vf610-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x0 0x2180000 0x0 0x10000>; @@ -380,11 +382,12 @@ clocks = <&clockgen 4 1>; dma-names = "tx", "rx"; dmas = <&edma0 1 39>, <&edma0 1 38>; + fsl-scl-gpio = <&gpio3 23 0>; status = "disabled"; }; i2c1: i2c@2190000 { - compatible = "fsl,vf610-i2c"; + compatible = "fsl,vf610-i2c", "fsl,ls1021a-vf610-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x0 0x2190000 0x0 0x10000>; @@ -393,6 +396,7 @@ clocks = <&clockgen 4 1>; dma-names = "tx", "rx"; dmas = <&edma0 1 37>, <&edma0 1 36>; + fsl-scl-gpio = <&gpio3 23 0>; status = "disabled"; }; @@ -678,8 +682,9 @@ reg = <0x0 0x2b50000 0x0 0x10000>; interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clockgen 4 1>, <&clockgen 4 1>, - <&clockgen 4 1>, <&clockgen 4 1>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; + <&clockgen 4 1>, <&clockgen 4 1>, + <&clockgen 4 1>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; dma-names = "tx", "rx"; dmas = <&edma0 1 47>, <&edma0 1 46>; @@ -692,8 +697,9 @@ reg = <0x0 0x2b60000 0x0 0x10000>; interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clockgen 4 1>, <&clockgen 4 1>, - <&clockgen 4 1>, <&clockgen 4 1>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; + <&clockgen 4 1>, <&clockgen 4 1>, + <&clockgen 4 1>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; dma-names = "tx", "rx"; dmas = <&edma0 1 45>, <&edma0 1 44>; @@ -861,7 +867,10 @@ dr_mode = "host"; snps,quirk-frame-length-adjustment = <0x20>; snps,dis_rxdet_inp3_quirk; + usb3-lpm-capable; + snps,dis-u1u2-when-u3-quirk; snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; + snps,host-vbus-glitches; }; pcie@3400000 { @@ -869,7 +878,9 @@ reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; - interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */ + interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ + interrupt-names = "pme", "aer"; fsl,pcie-scfg = <&scfg 0>; #address-cells = <3>; #size-cells = <2>; @@ -893,7 +904,9 @@ reg = <0x00 0x03500000 0x0 0x00010000 /* controller registers */ 0x48 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; - interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ + interrupt-names = "pme", "aer"; fsl,pcie-scfg = <&scfg 1>; #address-cells = <3>; #size-cells = <2>; @@ -983,5 +996,24 @@ big-endian; }; + rcpm: rcpm@1ee2140 { + compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+"; + reg = <0x0 0x1ee2140 0x0 0x8>; + #fsl,rcpm-wakeup-cells = <2>; + + /* + * The second and third entry compose an alt offset + * address for IPPDEXPCR1(SCFG_SPARECR8) + */ + fsl,ippdexpcr1-alt-addr = <&scfg 0x0 0x51c>; + }; + + ftm_alarm0: timer0@29d0000 { + compatible = "fsl,ls1021a-ftm-alarm"; + reg = <0x0 0x29d0000 0x0 0x10000>; + fsl,rcpm-wakeup = <&rcpm 0x0 0x20000000>; + interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; + big-endian; + }; }; }; diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index dabb80453249..8233e5a4f615 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -2,7 +2,7 @@ CONFIG_KERNEL_LZO=y CONFIG_SYSVIPC=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PREEMPT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=18 @@ -40,9 +40,6 @@ CONFIG_SOC_IMX6UL=y CONFIG_SOC_IMX7D=y CONFIG_SOC_IMX7ULP=y CONFIG_SOC_VF610=y -CONFIG_PCI=y -CONFIG_PCI_MSI=y -CONFIG_PCI_IMX6=y CONFIG_SMP=y CONFIG_ARM_PSCI=y CONFIG_HIGHMEM=y @@ -58,6 +55,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPUFREQ_DT=y CONFIG_ARM_IMX6Q_CPUFREQ=y CONFIG_ARM_IMX_CPUFREQ_DT=y +CONFIG_ARM_IMX7ULP_CPUFREQ=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_ARM_PSCI_CPUIDLE=y @@ -71,33 +69,47 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set CONFIG_BINFMT_MISC=m +CONFIG_CMA=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_INET=y +CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y -# 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_NETFILTER=y +CONFIG_VLAN_8021Q=m +CONFIG_LLC2=y CONFIG_CAN=y CONFIG_CAN_FLEXCAN=y CONFIG_BT=y -CONFIG_BT_BNEP=m +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIBTUSB=y CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_3WIRE=y +CONFIG_BT_HCIUART_MRVL=y +CONFIG_BT_HCIVHCI=y +CONFIG_BT_MRVL=y +CONFIG_BT_MRVL_SDIO=y CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=y -CONFIG_RFKILL=y -CONFIG_RFKILL_INPUT=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_IMX6=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y -CONFIG_CMA_SIZE_MBYTES=64 CONFIG_IMX_WEIM=y CONFIG_CONNECTOR=y CONFIG_MTD=y @@ -108,16 +120,14 @@ CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_DATAFLASH=y -CONFIG_MTD_M25P80=y CONFIG_MTD_SST25L=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPMI_NAND=y CONFIG_MTD_NAND_VF610_NFC=y CONFIG_MTD_NAND_MXC=y CONFIG_MTD_SPI_NOR=y -CONFIG_SPI_FSL_QUADSPI=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set CONFIG_MTD_UBI=y CONFIG_MTD_UBI_FASTMAP=y CONFIG_MTD_UBI_BLOCK=y @@ -163,9 +173,7 @@ CONFIG_USB_NET_CDC_EEM=m CONFIG_USB_NET_SMSC95XX=y CONFIG_USB_NET_MCS7830=y CONFIG_BRCMFMAC=m -CONFIG_MWIFIEX=m -CONFIG_MWIFIEX_SDIO=m -CONFIG_MWIFIEX_PCIE=m +CONFIG_HOSTAP=y CONFIG_WL12XX=m CONFIG_WL18XX=m CONFIG_WLCORE_SDIO=m @@ -173,6 +181,7 @@ CONFIG_WLCORE_SDIO=m CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_RPMSG=y CONFIG_KEYBOARD_SNVS_PWRKEY=y CONFIG_KEYBOARD_IMX=y CONFIG_MOUSE_PS2=m @@ -181,6 +190,8 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=y CONFIG_TOUCHSCREEN_EGALAX=y CONFIG_TOUCHSCREEN_GOODIX=y +CONFIG_TOUCHSCREEN_ELAN_TS=y +CONFIG_TOUCHSCREEN_FTS=y CONFIG_TOUCHSCREEN_MAX11801=y CONFIG_TOUCHSCREEN_IMX6UL_TSC=y CONFIG_TOUCHSCREEN_EDT_FT5X06=y @@ -192,6 +203,8 @@ CONFIG_TOUCHSCREEN_SX8654=y CONFIG_TOUCHSCREEN_COLIBRI_VF50=y CONFIG_INPUT_MISC=y CONFIG_INPUT_MMA8450=y +CONFIG_INPUT_MPL3115=y +CONFIG_INPUT_ISL29023=y CONFIG_SERIO_SERPORT=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_IMX=y @@ -208,11 +221,19 @@ CONFIG_I2C_ALGOPCF=m CONFIG_I2C_ALGOPCA=m CONFIG_I2C_GPIO=y CONFIG_I2C_IMX=y +CONFIG_I2C_IMX_LPI2C=y CONFIG_SPI=y +CONFIG_SPI_FSL_QUADSPI=y +CONFIG_SPI_FSL_LPSPI=y CONFIG_SPI_GPIO=y CONFIG_SPI_IMX=y +CONFIG_SPI_SPIDEV=y CONFIG_SPI_FSL_DSPI=y +CONFIG_SPI_SLAVE=y +CONFIG_SPI_SLAVE_TIME=y +CONFIG_SPI_SLAVE_SYSTEM_CONTROL=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_IMX_RPMSG=y CONFIG_GPIO_SIOX=m CONFIG_GPIO_MAX732X=y CONFIG_GPIO_MC9S08DZ60=y @@ -224,24 +245,35 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_RESET_SYSCON_POWEROFF=y CONFIG_POWER_SUPPLY=y +CONFIG_SABRESD_MAX8903=y +CONFIG_SENSORS_FXOS8700=y +CONFIG_SENSORS_FXAS2100X=y +CONFIG_SENSOR_FXLS8471=y +CONFIG_SENSOR_IMX_RPMSG=y CONFIG_SENSORS_MC13783_ADC=y CONFIG_SENSORS_GPIO_FAN=y +CONFIG_SENSORS_MAX17135=y CONFIG_SENSORS_IIO_HWMON=y +CONFIG_THERMAL=y CONFIG_THERMAL_STATISTICS=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_CPU_THERMAL=y CONFIG_IMX_THERMAL=y +CONFIG_DEVICE_THERMAL=y CONFIG_WATCHDOG=y -CONFIG_DA9062_WATCHDOG=y CONFIG_DA9063_WATCHDOG=m +CONFIG_DA9062_WATCHDOG=y CONFIG_RN5T618_WATCHDOG=y CONFIG_IMX2_WDT=y +CONFIG_IMX7ULP_WDT=y CONFIG_MFD_DA9052_I2C=y CONFIG_MFD_DA9062=y CONFIG_MFD_DA9063=y CONFIG_MFD_MC13XXX_SPI=y CONFIG_MFD_MC13XXX_I2C=y +CONFIG_MFD_MAX17135=y CONFIG_MFD_RN5T618=y +CONFIG_MFD_SI476X_CORE=y CONFIG_MFD_STMPE=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -250,8 +282,10 @@ CONFIG_REGULATOR_DA9052=y CONFIG_REGULATOR_DA9062=y CONFIG_REGULATOR_DA9063=y CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MAX17135=y CONFIG_REGULATOR_MC13783=y CONFIG_REGULATOR_MC13892=y +CONFIG_REGULATOR_PF1550_RPMSG=y CONFIG_REGULATOR_PFUZE100=y CONFIG_REGULATOR_RN5T618=y CONFIG_RC_CORE=y @@ -259,37 +293,54 @@ CONFIG_RC_DEVICES=y CONFIG_IR_GPIO_CIR=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_MUX=y -CONFIG_SOC_CAMERA=y +CONFIG_VIDEO_MXC_OUTPUT=y +CONFIG_VIDEO_MXC_CAPTURE=m +CONFIG_VIDEO_MXC_CSI_CAMERA=m +CONFIG_MXC_VADC=m +CONFIG_MXC_MIPI_CSI=m +CONFIG_MXC_CAMERA_OV5640=m +CONFIG_MXC_CAMERA_OV5640_V2=m +CONFIG_MXC_CAMERA_OV5640_MIPI=m +CONFIG_MXC_CAMERA_OV5640_MIPI_V2=m +CONFIG_MXC_TVIN_ADV7180=m +CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m +CONFIG_VIDEO_MXC_IPU_OUTPUT=y +CONFIG_VIDEO_MXC_PXP_V4L2=y CONFIG_V4L_MEM2MEM_DRIVERS=y CONFIG_VIDEO_CODA=m CONFIG_VIDEO_IMX_PXP=y -# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7180=m CONFIG_VIDEO_OV2680=m -CONFIG_VIDEO_OV5640=m CONFIG_VIDEO_OV5645=m -CONFIG_IMX_IPUV3_CORE=y +CONFIG_RADIO_SI476X=y CONFIG_DRM=y CONFIG_DRM_MSM=y CONFIG_DRM_PANEL_LVDS=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SEIKO_43WVF1G=y -CONFIG_DRM_DW_HDMI_AHB_AUDIO=m -CONFIG_DRM_DW_HDMI_CEC=y -CONFIG_DRM_IMX=y -CONFIG_DRM_IMX_PARALLEL_DISPLAY=y -CONFIG_DRM_IMX_TVE=y -CONFIG_DRM_IMX_LDB=y -CONFIG_DRM_IMX_HDMI=y -CONFIG_DRM_ETNAVIV=y -CONFIG_DRM_MXSFB=y -CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_MXS=y +CONFIG_FB_MXC_EINK_PANEL=y +CONFIG_FB_MXC_EINK_V2_PANEL=y +CONFIG_FB_MXC_MIPI_DSI=y +CONFIG_FB_MXC_MIPI_DSI_NORTHWEST=y +CONFIG_FB_MXC_MIPI_DSI_SAMSUNG=y +CONFIG_FB_MXC_ADV7535=y +CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y +CONFIG_FB_MXC_TRULY_PANEL_TFT3P5581E=y +CONFIG_FB_MXC_RK_PANEL_RK055AHD042=y +CONFIG_FB_MXC_RK_PANEL_RK055IQH042=y +CONFIG_FB_MXC_SYNC_PANEL=y +CONFIG_FB_MXC_LDB=y +CONFIG_FB_MXC_HDMI=y +CONFIG_FB_MXS_SII902X=y +CONFIG_FB_MXC_DCIC=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_L4F00242T03=y CONFIG_LCD_PLATFORM=y @@ -301,26 +352,31 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_USB_AUDIO=m CONFIG_SND_SOC=y -CONFIG_SND_SOC_FSL_ASRC=y CONFIG_SND_IMX_SOC=y CONFIG_SND_SOC_PHYCORE_AC97=y CONFIG_SND_SOC_EUKREA_TLV320=y +CONFIG_SND_SOC_IMX_WM8960=y +CONFIG_SND_SOC_IMX_SII902X=y +CONFIG_SND_SOC_IMX_WM8958=y +CONFIG_SND_SOC_IMX_CS42888=y +CONFIG_SND_SOC_IMX_WM8962=y +CONFIG_SND_SOC_IMX_RPMSG=y CONFIG_SND_SOC_IMX_ES8328=y CONFIG_SND_SOC_IMX_SGTL5000=y +CONFIG_SND_SOC_IMX_MQS=y CONFIG_SND_SOC_IMX_SPDIF=y CONFIG_SND_SOC_IMX_MC13783=y -CONFIG_SND_SOC_FSL_ASOC_CARD=y +CONFIG_SND_SOC_IMX_SI476X=y +CONFIG_SND_SOC_IMX_HDMI=y CONFIG_SND_SOC_AC97_CODEC=y -CONFIG_SND_SOC_CS42XX8_I2C=y CONFIG_SND_SOC_TLV320AIC3X=y -CONFIG_SND_SOC_WM8960=y -CONFIG_SND_SOC_WM8962=y CONFIG_SND_SIMPLE_CARD=y CONFIG_HID_MULTITOUCH=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y +CONFIG_USB_ACM=m CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y @@ -335,7 +391,7 @@ 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=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_ACM=y CONFIG_USB_CONFIGFS_OBEX=y @@ -365,6 +421,8 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y +CONFIG_MXC_SIM=y +CONFIG_MXC_SIMv2=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y @@ -388,26 +446,29 @@ CONFIG_RTC_DRV_MC13XXX=y CONFIG_RTC_DRV_MXC=y CONFIG_RTC_DRV_MXC_V2=y CONFIG_RTC_DRV_SNVS=y +CONFIG_RTC_DRV_IMX_RPMSG=y CONFIG_DMADEVICES=y CONFIG_FSL_EDMA=y CONFIG_IMX_SDMA=y CONFIG_MXS_DMA=y +CONFIG_MXC_PXP_V2=y +CONFIG_MXC_PXP_V3=y CONFIG_DMATEST=m CONFIG_STAGING=y CONFIG_STAGING_MEDIA=y -CONFIG_VIDEO_IMX_MEDIA=y CONFIG_COMMON_CLK_PWM=y CONFIG_IIO=y -CONFIG_MMA8452=y CONFIG_IMX7D_ADC=y CONFIG_VF610_ADC=y -CONFIG_SENSORS_ISL29018=y -CONFIG_MAG3110=y -CONFIG_MPL3115=y +CONFIG_SENSORS_MAG3110=y CONFIG_PWM=y CONFIG_PWM_FSL_FTM=y CONFIG_PWM_IMX27=y CONFIG_PWM_IMX_TPM=y +CONFIG_PHY_MIXEL_LVDS=y +CONFIG_PHY_MIXEL_LVDS_COMBO=y +CONFIG_MAILBOX=y +CONFIG_IMX_MBOX=y CONFIG_NVMEM_IMX_OCOTP=y CONFIG_NVMEM_VF610_OCOTP=y CONFIG_NVMEM_SNVS_LPGPR=y @@ -416,6 +477,11 @@ CONFIG_OPTEE=y CONFIG_MUX_MMIO=y CONFIG_SIOX=m CONFIG_SIOX_BUS_GPIO=m +CONFIG_MXC_IPU=y +CONFIG_MXC_IPU_V3_PRE=y +CONFIG_MXC_MLB150=y +CONFIG_MXC_MIPI_CSI2=y +CONFIG_MXC_HDMI_CEC=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y @@ -434,6 +500,7 @@ CONFIG_ZISOFS=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y +CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y @@ -448,13 +515,40 @@ CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=m CONFIG_NLS_UTF8=y CONFIG_SECURITYFS=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_ECHAINIV=m +CONFIG_CRYPTO_TLS=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_SHA3=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=m +CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y CONFIG_CRYPTO_DEV_SAHARA=y CONFIG_CRYPTO_DEV_MXS_DCP=y CONFIG_CRC_CCITT=m CONFIG_CRC_T10DIF=y CONFIG_CRC7=m CONFIG_LIBCRC32C=m +CONFIG_DMA_CMA=y CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig new file mode 100644 index 000000000000..2d1c0fba291e --- /dev/null +++ b/arch/arm/configs/imx_v7_defconfig @@ -0,0 +1,588 @@ +CONFIG_KERNEL_LZO=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_ARCH_MXC=y +CONFIG_SOC_IMX50=y +CONFIG_SOC_IMX51=y +CONFIG_SOC_IMX53=y +CONFIG_SOC_IMX6Q=y +CONFIG_SOC_IMX6SL=y +CONFIG_SOC_IMX6SLL=y +CONFIG_SOC_IMX6SX=y +CONFIG_SOC_IMX6UL=y +CONFIG_SOC_IMX7D=y +CONFIG_SOC_IMX7ULP=y +CONFIG_SOC_VF610=y +CONFIG_SMP=y +CONFIG_VMSPLIT_2G=y +CONFIG_ARM_PSCI=y +CONFIG_HIGHMEM=y +CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" +CONFIG_KEXEC=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPUFREQ_DT=y +CONFIG_ARM_IMX6Q_CPUFREQ=y +CONFIG_ARM_IMX_CPUFREQ_DT=y +CONFIG_ARM_IMX7ULP_CPUFREQ=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_PM_DEBUG=y +CONFIG_PM_TEST_SUSPEND=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BINFMT_MISC=m +CONFIG_CMA=y +CONFIG_SECCOMP=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NETFILTER=y +CONFIG_VLAN_8021Q=m +CONFIG_LLC2=y +CONFIG_CAN=y +CONFIG_CAN_FLEXCAN=y +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIBTUSB=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_3WIRE=y +CONFIG_BT_HCIUART_MRVL=y +CONFIG_BT_HCIVHCI=y +CONFIG_BT_MRVL=y +CONFIG_BT_MRVL_SDIO=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_IMX6_HOST=y +CONFIG_PCI_IMX6_EP=y +CONFIG_PCI_ENDPOINT=y +CONFIG_PCI_ENDPOINT_CONFIGFS=y +CONFIG_PCI_EPF_TEST=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_IMX_WEIM=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_SST25L=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_GPMI_NAND=y +CONFIG_MTD_NAND_VF610_NFC=y +CONFIG_MTD_NAND_MXC=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_FASTMAP=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_OF_OVERLAY=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_SENSORS_FXOS8700=y +CONFIG_SENSORS_FXAS2100X=y +CONFIG_PCI_ENDPOINT_TEST=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_IMX=y +CONFIG_PATA_IMX=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +CONFIG_CS89x0=y +CONFIG_CS89x0_PLATFORM=y +# CONFIG_NET_VENDOR_FARADAY is not set +CONFIG_E1000E=y +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_AT803X_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_SMSC_PHY=y +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_NET_MCS7830=y +CONFIG_BRCMFMAC=m +CONFIG_HOSTAP=y +CONFIG_MXMWIFIEX=m +CONFIG_WL12XX=m +CONFIG_WL18XX=m +CONFIG_WLCORE_SDIO=m +# CONFIG_WILINK_PLATFORM_DATA is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_RPMSG=y +CONFIG_KEYBOARD_IMX=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +CONFIG_TOUCHSCREEN_EGALAX=y +CONFIG_TOUCHSCREEN_ELAN_TS=y +CONFIG_TOUCHSCREEN_GOODIX=y +CONFIG_TOUCHSCREEN_MAX11801=y +CONFIG_TOUCHSCREEN_IMX6UL_TSC=y +CONFIG_TOUCHSCREEN_EDT_FT5X06=y +CONFIG_TOUCHSCREEN_MC13783=y +CONFIG_TOUCHSCREEN_TSC2004=y +CONFIG_TOUCHSCREEN_TSC2007=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TOUCHSCREEN_SX8654=y +CONFIG_TOUCHSCREEN_COLIBRI_VF50=y +CONFIG_TOUCHSCREEN_FTS=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MMA8450=y +CONFIG_INPUT_MPL3115=y +CONFIG_SENSOR_FXLS8471=y +CONFIG_SENSOR_IMX_RPMSG=y +CONFIG_INPUT_ISL29023=y +CONFIG_SERIO_SERPORT=m +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_GPIO=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_GPIO=y +CONFIG_I2C_IMX=y +CONFIG_I2C_IMX_LPI2C=y +CONFIG_SPI=y +CONFIG_SPI_FSL_LPSPI=y +CONFIG_SPI_FSL_QUADSPI=y +CONFIG_SPI_GPIO=y +CONFIG_SPI_IMX=y +CONFIG_SPI_FSL_DSPI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI_SLAVE=y +CONFIG_SPI_SLAVE_TIME=y +CONFIG_SPI_SLAVE_SYSTEM_CONTROL=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_SIOX=m +CONFIG_GPIO_IMX_RPMSG=y +CONFIG_GPIO_MAX732X=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCF857X=y +CONFIG_GPIO_STMPE=y +CONFIG_GPIO_74X164=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_POWER_SUPPLY=y +CONFIG_SABRESD_MAX8903=y +CONFIG_SENSORS_MC13783_ADC=y +CONFIG_SENSORS_GPIO_FAN=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_MAX17135=y +CONFIG_SENSORS_MAG3110=y +CONFIG_THERMAL=y +CONFIG_THERMAL_STATISTICS=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_CPU_THERMAL=y +CONFIG_IMX_THERMAL=y +CONFIG_DEVICE_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_DA9063_WATCHDOG=m +CONFIG_DA9062_WATCHDOG=y +CONFIG_RN5T618_WATCHDOG=y +CONFIG_IMX2_WDT=y +CONFIG_IMX7ULP_WDT=y +CONFIG_MFD_DA9052_I2C=y +CONFIG_MFD_DA9062=y +CONFIG_MFD_DA9063=y +CONFIG_MFD_MC13XXX_SPI=y +CONFIG_MFD_MC13XXX_I2C=y +CONFIG_MFD_MAX17135=y +CONFIG_MFD_RN5T618=y +CONFIG_MFD_SI476X_CORE=y +CONFIG_MFD_STMPE=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_ANATOP=y +CONFIG_REGULATOR_DA9052=y +CONFIG_REGULATOR_DA9062=y +CONFIG_REGULATOR_DA9063=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MAX17135=y +CONFIG_REGULATOR_MC13783=y +CONFIG_REGULATOR_MC13892=y +CONFIG_REGULATOR_PF1550_RPMSG=y +CONFIG_REGULATOR_PFUZE100=y +CONFIG_REGULATOR_RN5T618=y +CONFIG_RC_CORE=y +CONFIG_RC_DEVICES=y +CONFIG_IR_GPIO_CIR=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_MUX=y +CONFIG_VIDEO_MXC_CAPTURE=m +CONFIG_VIDEO_MXC_OUTPUT=y +CONFIG_VIDEO_MXC_CSI_CAMERA=m +CONFIG_MXC_VADC=m +CONFIG_MXC_MIPI_CSI=m +CONFIG_MXC_CAMERA_OV5640=m +CONFIG_MXC_CAMERA_OV5640_V2=m +CONFIG_MXC_CAMERA_OV5640_MIPI=m +CONFIG_MXC_CAMERA_OV5640_MIPI_V2=m +CONFIG_MXC_TVIN_ADV7180=m +CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m +CONFIG_VIDEO_MXC_IPU_OUTPUT=y +CONFIG_VIDEO_MXC_PXP_V4L2=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CODA=m +CONFIG_VIDEO_IMX_PXP=y +CONFIG_RADIO_SI476X=y +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_OV2680=m +CONFIG_VIDEO_OV5645=m +CONFIG_DRM=y +CONFIG_DRM_MSM=y +CONFIG_DRM_PANEL_LVDS=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_PANEL_SEIKO_43WVF1G=y +CONFIG_FB_MXS=y +CONFIG_FB_MXC_SYNC_PANEL=y +CONFIG_FB_MXC_OVERLAY=y +CONFIG_FB_MXC_MIPI_DSI_NORTHWEST=y +CONFIG_FB_MXC_ADV7535=y +CONFIG_FB_MXC_TRULY_PANEL_TFT3P5581E=y +CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y +CONFIG_FB_MXC_RK_PANEL_RK055AHD042=y +CONFIG_FB_MXC_RK_PANEL_RK055IQH042=y +CONFIG_FB_MXC_MIPI_DSI_SAMSUNG=y +CONFIG_FB_MXC_MIPI_DSI=y +CONFIG_FB_MXC_LDB=y +CONFIG_FB_MXC_EINK_PANEL=y +CONFIG_FB_MXC_EINK_V2_PANEL=y +CONFIG_FB_MXC_HDMI=y +CONFIG_FB_MXS_SII902X=y +CONFIG_FB_MXC_DCIC=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_L4F00242T03=y +CONFIG_LCD_PLATFORM=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_GPIO=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_SOC=y +CONFIG_SND_IMX_SOC=y +CONFIG_SND_SOC_EUKREA_TLV320=y +CONFIG_SND_SOC_IMX_WM8960=y +CONFIG_SND_SOC_IMX_SII902X=y +CONFIG_SND_SOC_IMX_WM8958=y +CONFIG_SND_SOC_IMX_CS42888=y +CONFIG_SND_SOC_IMX_WM8962=y +CONFIG_SND_SOC_IMX_RPMSG=y +CONFIG_SND_SOC_IMX_ES8328=y +CONFIG_SND_SOC_IMX_SGTL5000=y +CONFIG_SND_SOC_IMX_MQS=y +CONFIG_SND_SOC_IMX_SPDIF=y +CONFIG_SND_SOC_IMX_MC13783=y +CONFIG_SND_SOC_IMX_SI476X=y +CONFIG_SND_SOC_IMX_HDMI=y +CONFIG_SND_SOC_AC97_CODEC=y +CONFIG_SND_SOC_TLV320AIC3X=y +CONFIG_SND_SIMPLE_CARD=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG_WHITELIST=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MXC=y +CONFIG_USB_HCD_TEST_MODE=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=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_TEST=m +CONFIG_USB_EHSET_TEST_FIXTURE=m +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MXS_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_FSL_USB2=y +CONFIG_USB_CONFIGFS=y +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_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_LB_SS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_PRINTER=y +CONFIG_USB_ZERO=m +CONFIG_USB_AUDIO=m +CONFIG_USB_ETH=m +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +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_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_ISL1208=y +CONFIG_RTC_DRV_PCF8523=y +CONFIG_RTC_DRV_PCF8563=y +CONFIG_RTC_DRV_M41T80=y +CONFIG_RTC_DRV_DA9063=y +CONFIG_RTC_DRV_MC13XXX=y +CONFIG_RTC_DRV_MXC=y +CONFIG_RTC_DRV_MXC_V2=y +CONFIG_RTC_DRV_SNVS=y +CONFIG_RTC_DRV_IMX_RPMSG=y +CONFIG_DMADEVICES=y +CONFIG_FSL_EDMA=y +CONFIG_IMX_SDMA=y +CONFIG_MXS_DMA=y +CONFIG_MXC_PXP_V2=y +CONFIG_MXC_PXP_V3=y +CONFIG_DMATEST=m +CONFIG_STAGING=y +CONFIG_STAGING_MEDIA=y +CONFIG_COMMON_CLK_PWM=y +CONFIG_MAILBOX=y +CONFIG_IMX_MBOX=y +CONFIG_REMOTEPROC=y +CONFIG_IMX_REMOTEPROC=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_IMX7D_ADC=y +CONFIG_VF610_ADC=y +CONFIG_PWM=y +CONFIG_PWM_FSL_FTM=y +CONFIG_PWM_IMX27=y +CONFIG_PWM_IMX_TPM=y +CONFIG_PHY_MIXEL_LVDS=y +CONFIG_PHY_MIXEL_LVDS_COMBO=y +CONFIG_NVMEM_IMX_OCOTP=y +CONFIG_NVMEM_VF610_OCOTP=y +CONFIG_NVMEM_SNVS_LPGPR=y +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_MUX_MMIO=y +CONFIG_SIOX=m +CONFIG_SIOX_BUS_GPIO=m +CONFIG_MXC_SIM=y +CONFIG_MXC_IPU=y +CONFIG_MXC_SIMv2=y +CONFIG_MXC_MLB150=y +CONFIG_MXC_IPU_V3_PRE=y +CONFIG_MXC_HDMI_CEC=y +CONFIG_MXC_MIPI_CSI2=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_JFFS2_FS=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_UTF8=y +CONFIG_SECURITYFS=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_ECHAINIV=m +CONFIG_CRYPTO_TLS=m +CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_OFB=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_SHA3=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=m +CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y +CONFIG_CRYPTO_DEV_SAHARA=y +CONFIG_CRYPTO_DEV_MXS_DCP=y +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_SM3=m +CONFIG_CRYPTO_STREEBOG=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SM4=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_DMA_CMA=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FTRACE is not set diff --git a/arch/arm/configs/lsdk.config b/arch/arm/configs/lsdk.config new file mode 100644 index 000000000000..0a21b724367b --- /dev/null +++ b/arch/arm/configs/lsdk.config @@ -0,0 +1,88 @@ +# general +CONFIG_ARM_MODULE_PLTS=y +CONFIG_CHECKPOINT_RESTORE=y + +# virtualization +CONFIG_KVM=y +CONFIG_KVM_ARM_MAX_VCPUS=8 +CONFIG_VHOST_NET=y +CONFIG_BRIDGE=y +CONFIG_TUN=y + +# containers +CONFIG_UNIX_DIAG=y +CONFIG_PACKET_DIAG=y +CONFIG_NETLINK_DIAG=y +CONFIG_OVERLAY_FS=y + +# network and misc +CONFIG_INET_ESP=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_VETH=y +CONFIG_NETFILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NF_NAT_IPV6=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y +CONFIG_MACVLAN=y +CONFIG_MACVTAP=y +CONFIG_VLAN_8021Q=y + +# namespaces +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y + +# cgroups +CONFIG_CPUSETS=y +CGROUP_DEVICE=y +CGROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_CGROUP_FREEZER=y + +# iptables +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_IP_NF_FILTER=y +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y +CONFIG_IP_VS=y +CONFIG_NETFILTER_XT_MATCH_IPVS=y +CONFIG_POSIX_MQUEUE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_NAT=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y + +# filesystems +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FUSE_FS=y + +# /proc/config.gz +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y + +# disable unneeded options and override default options set by defconfig to deduce the size of modules +# CONFIG_DRM_TEGRA is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_MSM is not set +# CONFIG_DRM_VC4 is not set +# CONFIG_DRM_ROCKCHIP is not set +# CONFIG_DRM_RCAR_DU is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_SND_SOC_ROCKCHIP is not set diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index e4c8def9a0a5..930c662b761a 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -128,8 +128,8 @@ CONFIG_CRYPTO_AES_ARM_CE=m CONFIG_CRYPTO_GHASH_ARM_CE=m CONFIG_CRYPTO_CRC32_ARM_CE=m CONFIG_CRYPTO_CHACHA20_NEON=m -CONFIG_GCC_PLUGINS=y -CONFIG_GCC_PLUGIN_STRUCTLEAK=y +CONFIG_VIRTUALIZATION=y +CONFIG_VHOST_NET=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y @@ -174,7 +174,7 @@ CONFIG_PCI_TEGRA=y CONFIG_PCI_RCAR_GEN2=y CONFIG_PCIE_RCAR=y CONFIG_PCI_DRA7XX_EP=y -CONFIG_PCI_KEYSTONE=y +CONFIG_PCI_LAYERSCAPE=y CONFIG_PCI_ENDPOINT=y CONFIG_PCI_ENDPOINT_CONFIGFS=y CONFIG_PCI_EPF_TEST=m @@ -186,18 +186,24 @@ CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_M25P80=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_SST25L=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_NAND_OMAP2=y CONFIG_MTD_NAND_OMAP_BCH=y CONFIG_MTD_NAND_ATMEL=y CONFIG_MTD_NAND_MARVELL=y -CONFIG_MTD_NAND_GPMI_NAND=y CONFIG_MTD_NAND_BRCMNAND=y +CONFIG_MTD_NAND_GPMI_NAND=y +CONFIG_MTD_NAND_FSL_IFC=y CONFIG_MTD_NAND_VF610_NFC=y CONFIG_MTD_NAND_DAVINCI=y CONFIG_MTD_NAND_STM32_FMC2=y @@ -220,6 +226,7 @@ CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_SATA_AHCI_PLATFORM=y @@ -229,6 +236,8 @@ CONFIG_AHCI_ST=y CONFIG_AHCI_IMX=y CONFIG_AHCI_SUNXI=y CONFIG_AHCI_TEGRA=y +CONFIG_AHCI_QORIQ=y +CONFIG_SATA_SIL24=y CONFIG_SATA_HIGHBANK=y CONFIG_SATA_MV=y CONFIG_SATA_RCAR=y @@ -244,7 +253,9 @@ CONFIG_BGMAC_BCMA=y CONFIG_SYSTEMPORT=m CONFIG_MACB=y CONFIG_NET_CALXEDA_XGMAC=y +CONFIG_FSL_XGMAC_MDIO=y CONFIG_GIANFAR=y +CONFIG_FSL_SDK_DPAA_ETH=y CONFIG_HIX5HD2_GMAC=y CONFIG_E1000E=y CONFIG_IGB=y @@ -260,13 +271,16 @@ CONFIG_STMMAC_ETH=y CONFIG_DWMAC_DWC_QOS_ETH=y CONFIG_TI_CPSW=y CONFIG_XILINX_EMACLITE=y +CONFIG_AQUANTIA_PHY=y CONFIG_AT803X_PHY=y CONFIG_BROADCOM_PHY=y CONFIG_ICPLUS_PHY=y CONFIG_MARVELL_PHY=y CONFIG_MICREL_PHY=y +CONFIG_NATIONAL_PHY=y CONFIG_ROCKCHIP_PHY=y CONFIG_SMSC_PHY=y +CONFIG_VITESSE_PHY=y CONFIG_USB_PEGASUS=y CONFIG_USB_RTL8152=m CONFIG_USB_LAN78XX=m @@ -467,8 +481,8 @@ CONFIG_BATTERY_BQ27XXX=m CONFIG_AXP20X_POWER=m CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17042=m -CONFIG_CHARGER_GPIO=m CONFIG_CHARGER_CPCAP=m +CONFIG_CHARGER_GPIO=m CONFIG_CHARGER_MAX14577=m CONFIG_CHARGER_MAX77693=m CONFIG_CHARGER_MAX8997=m @@ -491,7 +505,6 @@ CONFIG_BCM2835_THERMAL=m CONFIG_BRCMSTB_THERMAL=m CONFIG_ST_THERMAL_MEMMAP=y CONFIG_UNIPHIER_THERMAL=y -CONFIG_WATCHDOG=y CONFIG_DA9063_WATCHDOG=m CONFIG_XILINX_WATCHDOG=y CONFIG_ARM_SP805_WATCHDOG=y @@ -525,10 +538,6 @@ CONFIG_MFD_BCM590XX=y CONFIG_MFD_AC100=y CONFIG_MFD_AXP20X_I2C=y CONFIG_MFD_AXP20X_RSB=y -CONFIG_MFD_CROS_EC=m -CONFIG_CROS_EC_I2C=m -CONFIG_CROS_EC_SPI=m -CONFIG_MFD_CROS_EC_CHARDEV=m CONFIG_MFD_DA9063=m CONFIG_MFD_MAX14577=y CONFIG_MFD_MAX77686=y @@ -628,7 +637,6 @@ CONFIG_V4L_TEST_DRIVERS=y CONFIG_VIDEO_VIVID=m CONFIG_CEC_PLATFORM_DRIVERS=y CONFIG_VIDEO_SAMSUNG_S5P_CEC=m -# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7180=m CONFIG_VIDEO_ML86V7667=m CONFIG_DRM=y @@ -677,16 +685,17 @@ CONFIG_DRM_PL111=m CONFIG_DRM_LIMA=m CONFIG_DRM_PANFROST=m CONFIG_DRM_ASPEED_GFX=m +CONFIG_FB_ARMCLCD=y CONFIG_FB_EFI=y CONFIG_FB_WM8505=y CONFIG_FB_SH_MOBILE_LCDC=y CONFIG_FB_SIMPLE=y -CONFIG_LCD_PLATFORM=m CONFIG_BACKLIGHT_PWM=y CONFIG_BACKLIGHT_AS3711=y CONFIG_BACKLIGHT_GPIO=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y CONFIG_SOUND=m CONFIG_SND=m CONFIG_SND_HDA_TEGRA=m @@ -871,6 +880,7 @@ CONFIG_RTC_DRV_S35390A=m CONFIG_RTC_DRV_RX8581=m CONFIG_RTC_DRV_EM3027=y CONFIG_RTC_DRV_S5M=m +CONFIG_RTC_DRV_DS3232=y CONFIG_RTC_DRV_DA9063=m CONFIG_RTC_DRV_EFI=m CONFIG_RTC_DRV_DIGICOLOR=m @@ -919,6 +929,10 @@ CONFIG_SERIO_NVEC_PS2=y CONFIG_NVEC_POWER=y CONFIG_NVEC_PAZ00=y CONFIG_STAGING_BOARD=y +CONFIG_FSL_SDK_DPA=y +CONFIG_MFD_CROS_EC=m +CONFIG_CROS_EC_I2C=m +CONFIG_CROS_EC_SPI=m CONFIG_COMMON_CLK_MAX77686=y CONFIG_COMMON_CLK_RK808=m CONFIG_COMMON_CLK_S2MPS11=m @@ -978,16 +992,15 @@ CONFIG_BERLIN2_ADC=m CONFIG_CPCAP_ADC=m CONFIG_EXYNOS_ADC=m CONFIG_MESON_SARADC=m +CONFIG_ROCKCHIP_SARADC=m CONFIG_STM32_ADC_CORE=m CONFIG_STM32_ADC=m CONFIG_STM32_DFSDM_ADC=m CONFIG_VF610_ADC=m CONFIG_XILINX_XADC=y -CONFIG_STM32_LPTIMER_CNT=m -CONFIG_STM32_DAC=m -CONFIG_ROCKCHIP_SARADC=m CONFIG_IIO_CROS_EC_SENSORS_CORE=m CONFIG_IIO_CROS_EC_SENSORS=m +CONFIG_STM32_DAC=m CONFIG_MPU3050_I2C=y CONFIG_CM36651=m CONFIG_IIO_CROS_EC_LIGHT_PROX=m @@ -1036,11 +1049,11 @@ CONFIG_PHY_DM816X_USB=m CONFIG_OMAP_USB2=y CONFIG_TI_PIPE3=y CONFIG_TWL4030_USB=m -CONFIG_MESON_MX_EFUSE=m -CONFIG_ROCKCHIP_EFUSE=m CONFIG_NVMEM_IMX_OCOTP=y +CONFIG_ROCKCHIP_EFUSE=m CONFIG_NVMEM_SUNXI_SID=y CONFIG_NVMEM_VF610_OCOTP=y +CONFIG_MESON_MX_EFUSE=m CONFIG_EXT4_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y @@ -1068,6 +1081,7 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m CONFIG_CRYPTO_DEV_MARVELL_CESA=m +CONFIG_CRYPTO_DEV_FSL_CAAM=m CONFIG_CRYPTO_DEV_EXYNOS_RNG=m CONFIG_CRYPTO_DEV_S5P=m CONFIG_CRYPTO_DEV_ATMEL_AES=m diff --git a/arch/arm/configs/multi_v7_lpae.config b/arch/arm/configs/multi_v7_lpae.config new file mode 100644 index 000000000000..cd13d2df5fd5 --- /dev/null +++ b/arch/arm/configs/multi_v7_lpae.config @@ -0,0 +1,2 @@ +# Support for the Large Physical Address Extension +CONFIG_ARM_LPAE=y diff --git a/arch/arm/configs/multi_v8.config b/arch/arm/configs/multi_v8.config new file mode 100644 index 000000000000..2203dabebc44 --- /dev/null +++ b/arch/arm/configs/multi_v8.config @@ -0,0 +1,23 @@ +# ppfe +CONFIG_FSL_PPFE=y +CONFIG_FSL_PPFE_UTIL_DISABLED=y +# DPAA 1 +CONFIG_HAS_FSL_QBMAN=y +# network +CONFIG_BRIDGE=m +CONFIG_MACVLAN=y +CONFIG_FSL_SDK_FMAN=y +CONFIG_FMAN_ARM=y +CONFIG_FSL_SDK_DPAA_ETH=y +# mdio +CONFIG_FSL_XGMAC_MDIO=y +CONFIG_MDIO_BUS_MUX_MMIOREG=y +# phy +CONFIG_AQUANTIA_PHY=y +CONFIG_VITESSE_PHY=y +# NVMe +CONFIG_BLK_DEV_NVME=y +# vfio +CONFIG_VFIO=y +CONFIG_VFIO_PCI=y +CONFIG_VFIO_FSL_MC=y diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h index 4f80b72372b4..f1aebe735321 100644 --- a/arch/arm/include/asm/delay.h +++ b/arch/arm/include/asm/delay.h @@ -85,6 +85,22 @@ extern void __bad_udelay(void); __const_udelay((n) * UDELAY_MULT)) : \ __udelay(n)) +#define spin_event_timeout(condition, timeout, delay) \ +({ \ + typeof(condition) __ret; \ + int i = 0; \ + while (!(__ret = (condition)) && (i++ < timeout)) { \ + if (delay) \ + udelay(delay); \ + else \ + cpu_relax(); \ + udelay(1); \ + } \ + if (!__ret) \ + __ret = (condition); \ + __ret; \ +}) + /* Loop-based definitions for assembly code. */ extern void __loop_delay(unsigned long loops); extern void __loop_udelay(unsigned long usecs); diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 7a0596fcb2e7..b026d499e42d 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -123,6 +123,7 @@ static inline u32 __raw_readl(const volatile void __iomem *addr) #define MT_DEVICE_NONSHARED 1 #define MT_DEVICE_CACHED 2 #define MT_DEVICE_WC 3 +#define MT_MEMORY_RW_NS 4 /* * types 4 onwards can be found in asm/mach/map.h and are undefined * for ioremap @@ -224,6 +225,34 @@ void __iomem *pci_remap_cfgspace(resource_size_t res_cookie, size_t size); #endif #endif +/* access ports */ +#define setbits32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr)) +#define clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr)) + +#define setbits16(_addr, _v) iowrite16be(ioread16be(_addr) | (_v), (_addr)) +#define clrbits16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr)) + +#define setbits8(_addr, _v) iowrite8(ioread8(_addr) | (_v), (_addr)) +#define clrbits8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr)) + +/* Clear and set bits in one shot. These macros can be used to clear and + * set multiple bits in a register using a single read-modify-write. These + * macros can also be used to set a multiple-bit bit pattern using a mask, + * by specifying the mask in the 'clear' parameter and the new bit pattern + * in the 'set' parameter. + */ + +#define clrsetbits_be32(addr, clear, set) \ + iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr)) +#define clrsetbits_le32(addr, clear, set) \ + iowrite32le((ioread32le(addr) & ~(clear)) | (set), (addr)) +#define clrsetbits_be16(addr, clear, set) \ + iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr)) +#define clrsetbits_le16(addr, clear, set) \ + iowrite16le((ioread16le(addr) & ~(clear)) | (set), (addr)) +#define clrsetbits_8(addr, clear, set) \ + iowrite8((ioread8(addr) & ~(clear)) | (set), (addr)) + /* * IO port access primitives * ------------------------- @@ -410,6 +439,8 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size); #define ioremap_wc ioremap_wc #define ioremap_wt ioremap_wc +void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size); + void iounmap(volatile void __iomem *iomem_cookie); #define iounmap iounmap diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 0d84d50bf9ba..d18f3ef33633 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -55,7 +55,8 @@ void stage2_unmap_vm(struct kvm *kvm); int kvm_alloc_stage2_pgd(struct kvm *kvm); void kvm_free_stage2_pgd(struct kvm *kvm); int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, - phys_addr_t pa, unsigned long size, bool writable); + phys_addr_t pa, unsigned long size, bool writable, + pgprot_t prot); int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run); diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index 92282558caf7..05e1af2179f9 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -18,9 +18,9 @@ struct map_desc { unsigned int type; }; -/* types 0-3 are defined in asm/io.h */ +/* types 0-4 are defined in asm/io.h */ enum { - MT_UNCACHED = 4, + MT_UNCACHED = 5, MT_CACHECLEAN, MT_MINICLEAN, MT_LOW_VECTORS, diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 3ae120cd1715..ea5c29c11bc8 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -116,6 +116,13 @@ extern pgprot_t pgprot_s2_device; #define pgprot_noncached(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) +#define pgprot_cached(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED) + +#define pgprot_cached_ns(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED | \ + L_PTE_MT_DEV_NONSHARED) + #define pgprot_writecombine(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE) diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index ed46ca69813d..cc9e5b3cdbcf 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -12,11 +12,14 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/of_irq.h> #include <asm/mach-types.h> #include <asm/mach/map.h> #include <asm/mach/pci.h> +#include "../../../drivers/pci/pcie/portdrv.h" + static int debug_pci; /* @@ -65,6 +68,47 @@ void pcibios_report_status(u_int status_mask, int warn) } /* + * Check device tree if the service interrupts are there + */ +int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) +{ + int ret, count = 0; + struct device_node *np = NULL; + + if (dev->bus->dev.of_node) + np = dev->bus->dev.of_node; + + if (np == NULL) + return 0; + + if (!IS_ENABLED(CONFIG_OF_IRQ)) + return 0; + + /* If root port doesn't support MSI/MSI-X/INTx in RC mode, + * request irq for aer + */ + if (mask & PCIE_PORT_SERVICE_AER) { + ret = of_irq_get_byname(np, "aer"); + if (ret > 0) { + irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret; + count++; + } + } + + if (mask & PCIE_PORT_SERVICE_PME) { + ret = of_irq_get_byname(np, "pme"); + if (ret > 0) { + irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret; + count++; + } + } + + /* TODO: add more service interrupts if there it is in the device tree*/ + + return count; +} + +/* * We don't use this to fix the device, but initialisation of it. * It's not the correct use for this, but it works. * Note that the arbiter/ISA bridge appears to be buggy, specifically in diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index b996b2cf0703..a148421cf482 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -9,6 +9,7 @@ * reading the RTC at bootup, etc... */ #include <linux/clk-provider.h> +#include <linux/clockchips.h> #include <linux/clocksource.h> #include <linux/errno.h> #include <linux/export.h> @@ -107,5 +108,7 @@ void __init time_init(void) of_clk_init(NULL); #endif timer_probe(); + + tick_setup_hrtimer_broadcast(); } } diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 95584ee02b55..42e609b75d31 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -40,9 +40,29 @@ config HAVE_IMX_GPC bool select PM_GENERIC_DOMAINS if PM +config HAVE_IMX_GPCV2 + bool + select PM_GENERIC_DOMAINS if PM + config HAVE_IMX_MMDC bool +config HAVE_IMX_AMP + bool + +config HAVE_IMX_DDRC + bool + select HAVE_IMX_BUSFREQ + +config HAVE_IMX_BUSFREQ + bool + +config HAVE_IMX_MU + bool + +config HAVE_IMX_RPMSG + bool + config HAVE_IMX_SRC def_bool y if SMP select ARCH_HAS_RESET_CONTROLLER @@ -511,7 +531,12 @@ config SOC_IMX6SLL config SOC_IMX6SX bool "i.MX6 SoloX support" select PINCTRL_IMX6SX + select HAVE_IMX_AMP select SOC_IMX6 + select HAVE_IMX_MU + select HAVE_IMX_RPMSG + select IMX_SEMA4 + select KEYBOARD_SNVS_PWRKEY help This enables support for Freescale i.MX6 SoloX processor. @@ -547,6 +572,11 @@ config SOC_IMX7D_CA7 select HAVE_IMX_MMDC select HAVE_IMX_SRC select IMX_GPCV2 + select HAVE_IMX_DDRC + select HAVE_IMX_MU + select HAVE_IMX_RPMSG + select HAVE_IMX_GPCV2 + select KEYBOARD_SNVS_PWRKEY config SOC_IMX7D_CM4 bool diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index e7364e6c8c6b..1a75a019b163 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := cpu.o system.o irq-common.o +obj-y := cpu.o system.o irq-common.o common.o obj-$(CONFIG_SOC_IMX21) += mm-imx21.o @@ -25,11 +25,18 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o -obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o -obj-$(CONFIG_SOC_IMX6SLL) += cpuidle-imx6sx.o -obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o -obj-$(CONFIG_SOC_IMX6UL) += cpuidle-imx6sx.o -obj-$(CONFIG_SOC_IMX7ULP) += cpuidle-imx7ulp.o +AFLAGS_imx6sl_low_power_idle.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o imx6sl_low_power_idle.o +AFLAGS_imx6sll_low_power_idle.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_IMX6SLL) += cpuidle-imx6sll.o imx6sll_low_power_idle.o +obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o imx6sx_low_power_idle.o +AFLAGS_imx6sx_low_power_idle.o :=-Wa,-march=armv7-a +AFLAGS_imx6ul_low_power_idle.o :=-Wa,-march=armv7-a +AFLAGS_imx6ull_low_power_idle.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_IMX6UL) += cpuidle-imx6ul.o imx6ul_low_power_idle.o imx6ull_low_power_idle.o +obj-$(CONFIG_SOC_IMX7ULP) += cpuidle-imx7ulp.o pm-rpmsg.o +AFLAGS_imx7d_low_power_idle.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_IMX7D_CA7) += cpuidle-imx7d.o imx7d_low_power_idle.o endif ifdef CONFIG_SND_SOC_IMX_PCM_FIQ @@ -70,26 +77,46 @@ obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o +obj-$(CONFIG_HAVE_IMX_GPCV2) += gpcv2.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o +obj-$(CONFIG_HAVE_IMX_DDRC) += ddrc.o +obj-$(CONFIG_HAVE_IMX_MU) += mu.o ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) AFLAGS_headsmp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o endif -obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o -obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o -obj-$(CONFIG_SOC_IMX6SLL) += mach-imx6sl.o -obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o +obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o ddr3_freq_imx6.o smp_wfe_imx6.o \ + lpddr2_freq_imx6q.o +obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o lpddr2_freq_imx6.o +obj-$(CONFIG_SOC_IMX6SLL) += mach-imx6sl.o lpddr2_freq_imx6sll.o +obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o ddr3_freq_imx6sx.o smp_wfe_imx6.o lpddr2_freq_imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o -obj-$(CONFIG_SOC_IMX7D_CA7) += mach-imx7d.o +obj-$(CONFIG_SOC_IMX7D_CA7) += mach-imx7d.o pm-imx7.o ddr3_freq_imx7d.o smp_wfe.o \ + lpddr3_freq_imx.o suspend-imx7.o obj-$(CONFIG_SOC_IMX7D_CM4) += mach-imx7d-cm4.o obj-$(CONFIG_SOC_IMX7ULP) += mach-imx7ulp.o pm-imx7ulp.o +obj-y += busfreq-imx.o busfreq_ddr3.o busfreq_lpddr2.o +AFLAGS_smp_wfe.o :=-Wa,-march=armv7-a +AFLAGS_smp_wfe_imx6.o :=-Wa,-march=armv7-a +AFLAGS_ddr3_freq_imx7d.o :=-Wa,-march=armv7-a +AFLAGS_lpddr3_freq_imx.o :=-Wa,-march=armv7-a +AFLAGS_ddr3_freq_imx6.o :=-Wa,-march=armv7-a +AFLAGS_lpddr2_freq_imx6.o :=-Wa,-march=armv7-a +AFLAGS_lpddr2_freq_imx6q.o :=-Wa,-march=armv7-a +AFLAGS_lpddr2_freq_imx6sx.o :=-Wa,-march=armv7-a +AFLAGS_lpddr2_freq_imx6sll.o :=-Wa,-march=armv7-a +AFLAGS_ddr3_freq_imx6sx.o :=-Wa,-march=armv7-a + ifeq ($(CONFIG_SUSPEND),y) AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a +AFLAGS_suspend-imx7.o :=-Wa,-march=armv7-a +AFLAGS_suspend-imx7ulp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o +obj-$(CONFIG_SOC_IMX7ULP) += suspend-imx7ulp.o endif ifeq ($(CONFIG_ARM_CPU_SUSPEND),y) AFLAGS_resume-imx6.o :=-Wa,-march=armv7-a @@ -106,4 +133,9 @@ obj-$(CONFIG_SOC_VF610) += mach-vf610.o obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o +ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_IMX7),) +# Bus frequency by OPTEE OS +obj-$(CONFIG_OPTEE) += busfreq_optee.o +endif + obj-y += devices/ diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index 777d8c255501..a9ec0159b8f0 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -4,6 +4,7 @@ * Copyright 2017-2018 NXP. */ +#include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include <linux/of.h> @@ -16,38 +17,63 @@ #define REG_SET 0x4 #define REG_CLR 0x8 +#define ANADIG_ARM_PLL 0x60 +#define ANADIG_DDR_PLL 0x70 +#define ANADIG_SYS_PLL 0xb0 +#define ANADIG_ENET_PLL 0xe0 +#define ANADIG_AUDIO_PLL 0xf0 +#define ANADIG_VIDEO_PLL 0x130 + #define ANADIG_REG_2P5 0x130 #define ANADIG_REG_CORE 0x140 #define ANADIG_ANA_MISC0 0x150 #define ANADIG_USB1_CHRG_DETECT 0x1b0 #define ANADIG_USB2_CHRG_DETECT 0x210 +#define ANADIG_ANA_MISC2 0x170 #define ANADIG_DIGPROG 0x260 #define ANADIG_DIGPROG_IMX6SL 0x280 #define ANADIG_DIGPROG_IMX7D 0x800 -#define SRC_SBMR2 0x1c - #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 #define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 +#define BM_ANADIG_REG_CORE_REG1 (0x1f << 9) +#define BM_ANADIG_REG_CORE_REG2 (0x1f << 18) +#define BP_ANADIG_REG_CORE_REG2 (18) #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 +#define BM_ANADIG_ANA_MISC0_V2_STOP_MODE_CONFIG 0x800 +#define BM_ANADIG_ANA_MISC0_V3_STOP_MODE_CONFIG 0xc00 +#define BM_ANADIG_ANA_MISC2_REG1_STEP_TIME (0x3 << 26) +#define BP_ANADIG_ANA_MISC2_REG1_STEP_TIME (26) /* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */ #define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 +/* Since i.MX6SX, DISCON_HIGH_SNVS is changed to bit 12 */ +#define BM_ANADIG_ANA_MISC0_V2_DISCON_HIGH_SNVS 0x1000 #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000 #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 +#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ +#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ + static struct regmap *anatop; static void imx_anatop_enable_weak2p5(bool enable) { - u32 reg, val; + u32 reg, val, mask; regmap_read(anatop, ANADIG_ANA_MISC0, &val); + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) + mask = BM_ANADIG_ANA_MISC0_V3_STOP_MODE_CONFIG; + else if (cpu_is_imx6sl()) + mask = BM_ANADIG_ANA_MISC0_V2_STOP_MODE_CONFIG; + else + mask = BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG; + /* can only be enabled when stop_mode_config is clear. */ reg = ANADIG_REG_2P5; - reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ? - REG_SET : REG_CLR; + reg += (enable && (val & mask) == 0) ? REG_SET : REG_CLR; regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG); } @@ -65,35 +91,89 @@ static inline void imx_anatop_enable_2p5_pulldown(bool enable) static inline void imx_anatop_disconnect_high_snvs(bool enable) { - regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), - BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) + regmap_write(anatop, ANADIG_ANA_MISC0 + + (enable ? REG_SET : REG_CLR), + BM_ANADIG_ANA_MISC0_V2_DISCON_HIGH_SNVS); + else + regmap_write(anatop, ANADIG_ANA_MISC0 + + (enable ? REG_SET : REG_CLR), + BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); +} + +static void imx_anatop_disable_pu(bool off) +{ + u32 val, soc, delay; + if (off) { + regmap_read(anatop, ANADIG_REG_CORE, &val); + val &= ~BM_ANADIG_REG_CORE_REG1; + regmap_write(anatop, ANADIG_REG_CORE, val); + } else { + /* track vddpu with vddsoc */ + regmap_read(anatop, ANADIG_REG_CORE, &val); + soc = val & BM_ANADIG_REG_CORE_REG2; + val &= ~BM_ANADIG_REG_CORE_REG1; + val |= soc >> 9; + regmap_write(anatop, ANADIG_REG_CORE, val); + /* wait PU LDO ramp */ + regmap_read(anatop, ANADIG_ANA_MISC2, &val); + val &= BM_ANADIG_ANA_MISC2_REG1_STEP_TIME; + val >>= BP_ANADIG_ANA_MISC2_REG1_STEP_TIME; + delay = (soc >> BP_ANADIG_REG_CORE_REG2) * + (LDO_RAMP_UP_UNIT_IN_CYCLES << val) / + LDO_RAMP_UP_FREQ_IN_MHZ + 1; + udelay(delay); + } } void imx_anatop_pre_suspend(void) { - if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) - imx_anatop_enable_2p5_pulldown(true); - else - imx_anatop_enable_weak2p5(true); + if (cpu_is_imx7d()) { + /* PLL and PFDs overwrite set */ + regmap_write(anatop, ANADIG_ARM_PLL + REG_SET, 1 << 20); + regmap_write(anatop, ANADIG_DDR_PLL + REG_SET, 1 << 19); + regmap_write(anatop, ANADIG_SYS_PLL + REG_SET, 0x1ff << 17); + regmap_write(anatop, ANADIG_ENET_PLL + REG_SET, 1 << 13); + regmap_write(anatop, ANADIG_AUDIO_PLL + REG_SET, 1 << 24); + regmap_write(anatop, ANADIG_VIDEO_PLL + REG_SET, 1 << 24); + return; + } + + if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) + imx_anatop_disable_pu(true); + imx_anatop_enable_weak2p5(true); imx_anatop_enable_fet_odrive(true); - if (cpu_is_imx6sl()) + if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() || + cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) imx_anatop_disconnect_high_snvs(true); } void imx_anatop_post_resume(void) { - if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) - imx_anatop_enable_2p5_pulldown(false); - else - imx_anatop_enable_weak2p5(false); + if (cpu_is_imx7d()) { + /* PLL and PFDs overwrite clear */ + regmap_write(anatop, ANADIG_ARM_PLL + REG_CLR, 1 << 20); + regmap_write(anatop, ANADIG_DDR_PLL + REG_CLR, 1 << 19); + regmap_write(anatop, ANADIG_SYS_PLL + REG_CLR, 0x1ff << 17); + regmap_write(anatop, ANADIG_ENET_PLL + REG_CLR, 1 << 13); + regmap_write(anatop, ANADIG_AUDIO_PLL + REG_CLR, 1 << 24); + regmap_write(anatop, ANADIG_VIDEO_PLL + REG_CLR, 1 << 24); + return; + } + + if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) + imx_anatop_disable_pu(false); + + imx_anatop_enable_weak2p5(false); imx_anatop_enable_fet_odrive(false); - if (cpu_is_imx6sl()) + if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() || + cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) imx_anatop_disconnect_high_snvs(false); - } static void imx_anatop_usb_chrg_detect_disable(void) @@ -110,10 +190,11 @@ void __init imx_init_revision_from_anatop(void) { struct device_node *np; void __iomem *anatop_base; + void __iomem *src_base; unsigned int revision; - u32 digprog; + u32 digprog, sbmr2 = 0; u16 offset = ANADIG_DIGPROG; - u8 major_part, minor_part; + u16 major_part, minor_part; np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); anatop_base = of_iomap(np, 0); @@ -125,6 +206,20 @@ void __init imx_init_revision_from_anatop(void) digprog = readl_relaxed(anatop_base + offset); iounmap(anatop_base); + if ((digprog >> 16) == MXC_CPU_IMX6ULL) { + np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-src"); + if (np) { + src_base = of_iomap(np, 0); + WARN_ON(!src_base); + sbmr2 = readl_relaxed(src_base + 0x1c); + iounmap(src_base); + } + if (sbmr2 & (1 << 6)) { + digprog &= ~(0xff << 16); + digprog |= (MXC_CPU_IMX6ULZ << 16); + } + } + /* * On i.MX7D digprog value match linux version format, so * it needn't map again and we can use register value directly. @@ -144,24 +239,6 @@ void __init imx_init_revision_from_anatop(void) major_part = (digprog >> 8) & 0xf; minor_part = digprog & 0xf; revision = ((major_part + 1) << 4) | minor_part; - - if ((digprog >> 16) == MXC_CPU_IMX6ULL) { - void __iomem *src_base; - u32 sbmr2; - - np = of_find_compatible_node(NULL, NULL, - "fsl,imx6ul-src"); - src_base = of_iomap(np, 0); - WARN_ON(!src_base); - sbmr2 = readl_relaxed(src_base + SRC_SBMR2); - iounmap(src_base); - - /* src_sbmr2 bit 6 is to identify if it is i.MX6ULZ */ - if (sbmr2 & (1 << 6)) { - digprog &= ~(0xff << 16); - digprog |= (MXC_CPU_IMX6ULZ << 16); - } - } } mxc_set_cpu_type(digprog >> 16 & 0xff); diff --git a/arch/arm/mach-imx/busfreq-imx.c b/arch/arm/mach-imx/busfreq-imx.c new file mode 100644 index 000000000000..88135aa414f9 --- /dev/null +++ b/arch/arm/mach-imx/busfreq-imx.c @@ -0,0 +1,1441 @@ +/* + * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2017 NXP. + * Copyright 2018 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/cacheflush.h> +#include <asm/fncpy.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/tlb.h> +#include <linux/busfreq-imx.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <linux/reboot.h> +#include <linux/regulator/consumer.h> +#include <linux/sched.h> +#include <linux/suspend.h> +#include "hardware.h" +#include "common.h" + +#define LPAPM_CLK 24000000 +#define LOW_AUDIO_CLK 50000000 +#define HIGH_AUDIO_CLK 100000000 + +#define LOW_POWER_RUN_VOLTAGE 950000 + +#define MMDC_MDMISC_DDR_TYPE_DDR3 0 +#define MMDC_MDMISC_DDR_TYPE_LPDDR2 1 + +unsigned int ddr_med_rate; +unsigned int ddr_normal_rate; +unsigned long ddr_freq_change_total_size; +unsigned long ddr_freq_change_iram_base; +unsigned long ddr_freq_change_iram_phys; + +static int ddr_type; +static int low_bus_freq_mode; +static int audio_bus_freq_mode; +static int ultra_low_bus_freq_mode; +static int high_bus_freq_mode; +static int med_bus_freq_mode; +static int bus_freq_scaling_initialized; +static bool cancel_reduce_bus_freq; +static struct device *busfreq_dev; +static int busfreq_suspended; +static int bus_freq_scaling_is_active; +static int high_bus_count, med_bus_count, audio_bus_count, low_bus_count; +static unsigned int ddr_low_rate; +static int cur_bus_freq_mode; +static u32 org_arm_rate; + +extern unsigned long iram_tlb_phys_addr; +extern int unsigned long iram_tlb_base_addr; + +/* + * Bus frequency management by Linux + */ +extern int init_mmdc_lpddr2_settings(struct platform_device *dev); +extern int init_mmdc_lpddr2_settings_mx6q(struct platform_device *dev); +extern int init_mmdc_ddr3_settings_imx6_up(struct platform_device *dev); +extern int init_mmdc_ddr3_settings_imx6_smp(struct platform_device *dev); +extern int init_ddrc_ddr_settings(struct platform_device *dev); +extern int update_ddr_freq_imx_smp(int ddr_rate); +extern int update_ddr_freq_imx6_up(int ddr_rate); +extern int update_lpddr2_freq(int ddr_rate); +extern int update_lpddr2_freq_smp(int ddr_rate); + +#ifdef CONFIG_OPTEE +/* + * Bus frequency management by OPTEE OS + */ +extern int update_freq_optee(int ddr_rate); +extern int init_freq_optee(struct platform_device *busfreq_pdev); +#endif + +/** + * @brief Functions to init and update the busfreq function of + * device and memory type + */ +static struct busfreq_func { + int (*init)(struct platform_device *dev); + int (*update)(int ddr_rate); +} busfreq_func = {NULL, NULL}; + +DEFINE_MUTEX(bus_freq_mutex); + +static struct clk *osc_clk; +static struct clk *ahb_clk; +static struct clk *axi_sel_clk; +static struct clk *dram_root; +static struct clk *dram_alt_sel; +static struct clk *dram_alt_root; +static struct clk *pfd0_392m; +static struct clk *pfd2_270m; +static struct clk *pfd1_332m; +static struct clk *pll_dram; +static struct clk *ahb_sel_clk; +static struct clk *axi_clk; + +static struct clk *m4_clk; +static struct clk *pll3_clk; +static struct clk *pll2_400_clk; +static struct clk *periph_clk2_sel_clk; +static struct clk *periph_pre_clk; +static struct clk *pll2_200_clk; +static struct clk *periph_clk; +static struct clk *mmdc_clk; +static struct clk *periph_clk2_clk; +static struct clk *pll2_bus_clk; + +static struct clk *pll2_bypass_src_clk; +static struct clk *pll2_bypass_clk; +static struct clk *pll2_clk; +static struct clk *arm_clk; +static struct clk *step_clk; +static struct clk *pll1_clk; +static struct clk *pll1_bypass_src_clk; +static struct clk *pll1_bypass_clk; +static struct clk *pll1_sys_clk; +static struct clk *pll1_sw_clk; + +static struct clk *axi_alt_sel_clk; +static struct clk *pll3_pfd1_540m_clk; + +static struct clk *ocram_clk; +static struct clk *periph2_clk; +static struct clk *periph2_pre_clk; +static struct clk *periph2_clk2_clk; +static struct clk *periph2_clk2_sel_clk; + +static struct delayed_work low_bus_freq_handler; +static struct delayed_work bus_freq_daemon; + +static RAW_NOTIFIER_HEAD(busfreq_notifier_chain); + +static bool check_m4_sleep(void) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(500); + + while (imx_gpc_is_m4_sleeping() == 0) + if (time_after(jiffies, timeout)) + return false; + return true; +} + +static bool busfreq_notified_low = false; + +static int busfreq_notify(enum busfreq_event event) +{ + int ret; + + if (event == LOW_BUSFREQ_ENTER) { + WARN_ON(busfreq_notified_low); + busfreq_notified_low = true; + } else if (event == LOW_BUSFREQ_EXIT) { + WARN_ON(!busfreq_notified_low); + busfreq_notified_low = false; + } + ret = raw_notifier_call_chain(&busfreq_notifier_chain, event, NULL); + + return notifier_to_errno(ret); +} + +int register_busfreq_notifier(struct notifier_block *nb) +{ + return raw_notifier_chain_register(&busfreq_notifier_chain, nb); +} +EXPORT_SYMBOL(register_busfreq_notifier); + +int unregister_busfreq_notifier(struct notifier_block *nb) +{ + return raw_notifier_chain_unregister(&busfreq_notifier_chain, nb); +} +EXPORT_SYMBOL(unregister_busfreq_notifier); + +static struct clk *origin_step_parent; + +/* + * on i.MX6ULL, when entering low bus mode, the ARM core + * can run at 24MHz to support the low power run mode per + * to design team. + */ +static void imx6ull_lower_cpu_rate(bool enter) +{ + if (enter) { + org_arm_rate = clk_get_rate(arm_clk); + } + + clk_set_parent(pll1_bypass_clk, pll1_bypass_src_clk); + clk_set_parent(pll1_sw_clk, pll1_sys_clk); + + if (enter) { + origin_step_parent = clk_get_parent(step_clk); + clk_set_parent(step_clk, osc_clk); + clk_set_parent(pll1_sw_clk, step_clk); + clk_set_rate(arm_clk, LPAPM_CLK); + } else { + clk_set_parent(step_clk, origin_step_parent); + clk_set_parent(pll1_sw_clk, step_clk); + clk_set_rate(arm_clk, org_arm_rate); + clk_set_parent(pll1_bypass_clk, pll1_clk); + } +} + +/* + * enter_lpm_imx6_up and exit_lpm_imx6_up is used by + * i.MX6SX/i.MX6UL for entering and exiting lpm mode. + */ +static void enter_lpm_imx6_up(void) +{ + if (cpu_is_imx6sx() && imx_src_is_m4_enabled()) + if (!check_m4_sleep()) + pr_err("M4 is NOT in sleep!!!\n"); + + /* set periph_clk2 to source from OSC for periph */ + clk_set_parent(periph_clk2_sel_clk, osc_clk); + clk_set_parent(periph_clk, periph_clk2_clk); + /* set ahb/ocram to 24MHz */ + clk_set_rate(ahb_clk, LPAPM_CLK); + clk_set_rate(ocram_clk, LPAPM_CLK); + + if (audio_bus_count) { + /* Need to ensure that PLL2_PFD_400M is kept ON. */ + clk_prepare_enable(pll2_400_clk); + if (ddr_type == IMX_DDR_TYPE_DDR3) + busfreq_func.update(LOW_AUDIO_CLK); + else if (ddr_type == IMX_DDR_TYPE_LPDDR2 || + ddr_type == IMX_MMDC_DDR_TYPE_LPDDR3) + busfreq_func.update(HIGH_AUDIO_CLK); + clk_set_parent(periph2_clk2_sel_clk, pll3_clk); + clk_set_parent(periph2_pre_clk, pll2_400_clk); + clk_set_parent(periph2_clk, periph2_pre_clk); + /* + * As periph2_clk's parent is not changed from + * high mode to audio mode, so clk framework + * will not update its children's freq, but we + * change the mmdc's podf in asm code, so here + * need to update mmdc rate to make sure clk + * tree is right, although it will not do any + * change to hardware. + */ + if (high_bus_freq_mode) { + if (ddr_type == IMX_DDR_TYPE_DDR3) + clk_set_rate(mmdc_clk, LOW_AUDIO_CLK); + else if (ddr_type == IMX_DDR_TYPE_LPDDR2 || + ddr_type == IMX_MMDC_DDR_TYPE_LPDDR3) + clk_set_rate(mmdc_clk, HIGH_AUDIO_CLK); + } + + if ((cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) && low_bus_freq_mode) + imx6ull_lower_cpu_rate(false); + + audio_bus_freq_mode = 1; + low_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_AUDIO; + } else { + busfreq_func.update(LPAPM_CLK); + + clk_set_parent(periph2_clk2_sel_clk, osc_clk); + clk_set_parent(periph2_clk, periph2_clk2_clk); + + if (audio_bus_freq_mode) + clk_disable_unprepare(pll2_400_clk); + + if (cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) + imx6ull_lower_cpu_rate(true); + + low_bus_freq_mode = 1; + audio_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_LOW; + } +} + +static void enter_lpm_imx6_smp(void) +{ + if (cpu_is_imx6dl()) + /* Set axi to periph_clk */ + clk_set_parent(axi_sel_clk, periph_clk); + + if (audio_bus_count) { + /* Need to ensure that PLL2_PFD_400M is kept ON. */ + clk_prepare_enable(pll2_400_clk); + if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) + busfreq_func.update(LOW_AUDIO_CLK); + else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) + busfreq_func.update(HIGH_AUDIO_CLK); + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk2_sel_clk, pll3_clk); + if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) + clk_set_parent(periph_pre_clk, pll2_200_clk); + else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) + clk_set_parent(periph_pre_clk, pll2_400_clk); + clk_set_parent(periph_clk, periph_pre_clk); + + /* + * As periph_pre_clk's parent is not changed from + * high mode to audio mode on lpddr2, the clk framework + * will not update its children's freq, but we + * change the mmdc_ch0_axi podf in asm code, so here + * need to update mmdc rate to make sure clk + * tree is right, although it will not do any + * change to hardware. Calling get_rate will only call + * the .rate_recalc which is all we need. + */ + if (high_bus_freq_mode && mmdc_clk) + if (ddr_type == IMX_DDR_TYPE_LPDDR2) + clk_get_rate(mmdc_clk); + + audio_bus_freq_mode = 1; + low_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_AUDIO; + } else { + busfreq_func.update(LPAPM_CLK); + + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk2_sel_clk, osc_clk); + /* Set periph_clk parent to OSC via periph_clk2_sel */ + clk_set_parent(periph_clk, periph_clk2_clk); + if (audio_bus_freq_mode) + clk_disable_unprepare(pll2_400_clk); + low_bus_freq_mode = 1; + audio_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_LOW; + } +} + +static void exit_lpm_imx6_up(void) +{ + if ((cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) && low_bus_freq_mode) + imx6ull_lower_cpu_rate(false); + + clk_prepare_enable(pll2_400_clk); + + /* + * lower ahb/ocram's freq first to avoid too high + * freq during parent switch from OSC to pll3. + */ + if (cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz() + || cpu_is_imx6sll()) + clk_set_rate(ahb_clk, LPAPM_CLK / 4); + else + clk_set_rate(ahb_clk, LPAPM_CLK / 3); + + clk_set_rate(ocram_clk, LPAPM_CLK / 2); + /* set periph clk to from pll2_bus on i.MX6UL */ + if (cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) + clk_set_parent(periph_pre_clk, pll2_bus_clk); + /* set periph clk to from pll2_400 */ + else + clk_set_parent(periph_pre_clk, pll2_400_clk); + clk_set_parent(periph_clk, periph_pre_clk); + /* set periph_clk2 to pll3 */ + clk_set_parent(periph_clk2_sel_clk, pll3_clk); + + busfreq_func.update(ddr_normal_rate); + + /* correct parent info after ddr freq change in asm code */ + clk_set_parent(periph2_pre_clk, pll2_400_clk); + clk_set_parent(periph2_clk, periph2_pre_clk); + clk_set_parent(periph2_clk2_sel_clk, pll3_clk); + + /* + * As periph2_clk's parent is not changed from + * audio mode to high mode, so clk framework + * will not update its children's freq, but we + * change the mmdc's podf in asm code, so here + * need to update mmdc rate to make sure clk + * tree is right, although it will not do any + * change to hardware. + */ + if (audio_bus_freq_mode) + clk_set_rate(mmdc_clk, ddr_normal_rate); + + clk_disable_unprepare(pll2_400_clk); + + if (audio_bus_freq_mode) + clk_disable_unprepare(pll2_400_clk); +} + +static void exit_lpm_imx6_smp(void) +{ + struct clk *periph_clk_parent; + + if (cpu_is_imx6q() && ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) + periph_clk_parent = pll2_bus_clk; + else + periph_clk_parent = pll2_400_clk; + + clk_prepare_enable(pll2_400_clk); + + busfreq_func.update(ddr_normal_rate); + + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk2_sel_clk, pll3_clk); + clk_set_parent(periph_pre_clk, periph_clk_parent); + clk_set_parent(periph_clk, periph_pre_clk); + if (cpu_is_imx6dl()) { + /* Set axi to pll3_pfd1_540m */ + clk_set_parent(axi_alt_sel_clk, pll3_pfd1_540m_clk); + clk_set_parent(axi_sel_clk, axi_alt_sel_clk); + } + /* + * As periph_pre_clk's parent is not changed from + * high mode to audio mode on lpddr2, the clk framework + * will not update its children's freq, but we + * change the mmdc_ch0_axi podf in asm code, so here + * need to update mmdc rate to make sure clk + * tree is right, although it will not do any + * change to hardware. Calling get_rate will only call + * the .rate_recalc which is all we need. + */ + if (audio_bus_freq_mode && mmdc_clk) + if (ddr_type == IMX_DDR_TYPE_LPDDR2) + clk_get_rate(mmdc_clk); + + clk_disable_unprepare(pll2_400_clk); + if (audio_bus_freq_mode) + clk_disable_unprepare(pll2_400_clk); +} + +static void enter_lpm_imx6sl(void) +{ + if (high_bus_freq_mode) { + /* Set periph_clk to be sourced from OSC_CLK */ + clk_set_parent(periph_clk2_sel_clk, osc_clk); + clk_set_parent(periph_clk, periph_clk2_clk); + /* Ensure AHB/AXI clks are at 24MHz. */ + clk_set_rate(ahb_clk, LPAPM_CLK); + clk_set_rate(ocram_clk, LPAPM_CLK); + } + if (audio_bus_count) { + /* Set AHB to 8MHz to lower pwer.*/ + clk_set_rate(ahb_clk, LPAPM_CLK / 3); + + /* Set up DDR to 100MHz. */ + busfreq_func.update(HIGH_AUDIO_CLK); + + /* Fix the clock tree in kernel */ + clk_set_parent(periph2_pre_clk, pll2_200_clk); + clk_set_parent(periph2_clk, periph2_pre_clk); + + if (low_bus_freq_mode || ultra_low_bus_freq_mode) { + /* + * Fix the clock tree in kernel, make sure + * pll2_bypass is updated as it is + * sourced from PLL2. + */ + clk_set_parent(pll2_bypass_clk, pll2_clk); + /* + * Swtich ARM to run off PLL2_PFD2_400MHz + * since DDR is anyway at 100MHz. + */ + clk_set_parent(step_clk, pll2_400_clk); + clk_set_parent(pll1_sw_clk, step_clk); + + /* + * Need to ensure that PLL1 is bypassed and enabled + * before ARM-PODF is set. + */ + clk_set_parent(pll1_bypass_clk, pll1_bypass_src_clk); + + /* + * Ensure that the clock will be + * at original speed. + */ + clk_set_rate(arm_clk, org_arm_rate); + } + low_bus_freq_mode = 0; + ultra_low_bus_freq_mode = 0; + audio_bus_freq_mode = 1; + cur_bus_freq_mode = BUS_FREQ_AUDIO; + } else { + u32 arm_div, pll1_rate; + org_arm_rate = clk_get_rate(arm_clk); + if (org_arm_rate == 0) { + WARN_ON(1); + return; + } + if (low_bus_freq_mode && low_bus_count == 0) { + /* + * We are already in DDR @ 24MHz state, but + * no one but ARM needs the DDR. In this case, + * we can lower the DDR freq to 1MHz when ARM + * enters WFI in this state. Keep track of this state. + */ + ultra_low_bus_freq_mode = 1; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_ULTRA_LOW; + } else { + if (!ultra_low_bus_freq_mode && !low_bus_freq_mode) { + /* + * Anyway, make sure the AHB is running at 24MHz + * in low_bus_freq_mode. + */ + if (audio_bus_freq_mode) + clk_set_rate(ahb_clk, LPAPM_CLK); + /* + * Set DDR to 24MHz. + * Since we are going to bypass PLL2, + * we need to move ARM clk off PLL2_PFD2 + * to PLL1. Make sure the PLL1 is running + * at the lowest possible freq. + * To work well with CPUFREQ we want to ensure that + * the CPU freq does not change, so attempt to + * get a freq as close to 396MHz as possible. + */ + clk_set_rate(pll1_clk, + clk_round_rate(pll1_clk, (org_arm_rate * 2))); + pll1_rate = clk_get_rate(pll1_clk); + arm_div = pll1_rate / org_arm_rate; + if (pll1_rate / arm_div > org_arm_rate) + arm_div++; + /* + * Need to ensure that PLL1 is bypassed and enabled + * before ARM-PODF is set. + */ + clk_set_parent(pll1_bypass_clk, pll1_clk); + /* + * Ensure ARM CLK is lower before + * changing the parent. + */ + clk_set_rate(arm_clk, org_arm_rate / arm_div); + /* Now set the ARM clk parent to PLL1_SYS. */ + clk_set_parent(pll1_sw_clk, pll1_sys_clk); + + /* + * Set STEP_CLK back to OSC to save power and + * also to maintain the parent.The WFI iram code + * will switch step_clk to osc, but the clock API + * is not aware of the change and when a new request + * to change the step_clk parent to pll2_pfd2_400M + * is requested sometime later, the change is ignored. + */ + clk_set_parent(step_clk, osc_clk); + + /* Now set DDR to 24MHz. */ + busfreq_func.update(LPAPM_CLK); + + /* + * Fix the clock tree in kernel. + * Make sure PLL2 rate is updated as it gets + * bypassed in the DDR freq change code. + */ + clk_set_parent(pll2_bypass_clk, pll2_bypass_src_clk); + clk_set_parent(periph2_clk2_sel_clk, pll2_bus_clk); + clk_set_parent(periph2_clk, periph2_clk2_clk); + } + if (low_bus_count == 0) { + ultra_low_bus_freq_mode = 1; + low_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_ULTRA_LOW; + } else { + ultra_low_bus_freq_mode = 0; + low_bus_freq_mode = 1; + cur_bus_freq_mode = BUS_FREQ_LOW; + } + audio_bus_freq_mode = 0; + } + } +} + +static void exit_lpm_imx6sl(void) +{ + /* Change DDR freq in IRAM. */ + busfreq_func.update(ddr_normal_rate); + + /* + * Fix the clock tree in kernel. + * Make sure PLL2 rate is updated as it gets + * un-bypassed in the DDR freq change code. + */ + clk_set_parent(pll2_bypass_clk, pll2_clk); + clk_set_parent(periph2_pre_clk, pll2_400_clk); + clk_set_parent(periph2_clk, periph2_pre_clk); + + /* Ensure that periph_clk is sourced from PLL2_400. */ + clk_set_parent(periph_pre_clk, pll2_400_clk); + /* + * Before switching the perhiph_clk, ensure that the + * AHB/AXI will not be too fast. + */ + clk_set_rate(ahb_clk, LPAPM_CLK / 3); + clk_set_rate(ocram_clk, LPAPM_CLK / 2); + clk_set_parent(periph_clk, periph_pre_clk); + + if (low_bus_freq_mode || ultra_low_bus_freq_mode) { + /* Move ARM from PLL1_SW_CLK to PLL2_400. */ + clk_set_parent(step_clk, pll2_400_clk); + clk_set_parent(pll1_sw_clk, step_clk); + /* + * Need to ensure that PLL1 is bypassed and enabled + * before ARM-PODF is set. + */ + clk_set_parent(pll1_bypass_clk, pll1_bypass_src_clk); + clk_set_rate(arm_clk, org_arm_rate); + ultra_low_bus_freq_mode = 0; + } +} + +static void enter_lpm_imx7d(void) +{ + /* + * The AHB clock parent switch and divider change + * needs to keep previous/current parent enabled + * per design requirement, but when we switch the + * clock parent, previous AHB clock parent may be + * disabled by common clock framework, so here we + * have to make sure AHB's previous parent pfd2_270m + * is enabled during AHB set rate. + */ + clk_prepare_enable(pfd2_270m); + if (audio_bus_count) { + clk_prepare_enable(pfd0_392m); + busfreq_func.update(HIGH_AUDIO_CLK); + + clk_set_parent(dram_alt_sel, pfd0_392m); + clk_set_parent(dram_root, dram_alt_root); + if (high_bus_freq_mode) { + clk_set_parent(axi_sel_clk, osc_clk); + clk_set_parent(ahb_sel_clk, osc_clk); + clk_set_rate(ahb_clk, LPAPM_CLK); + } + clk_disable_unprepare(pfd0_392m); + audio_bus_freq_mode = 1; + low_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_AUDIO; + } else { + busfreq_func.update(LPAPM_CLK); + + clk_set_parent(dram_alt_sel, osc_clk); + clk_set_parent(dram_root, dram_alt_root); + if (high_bus_freq_mode) { + clk_set_parent(axi_sel_clk, osc_clk); + clk_set_parent(ahb_sel_clk, osc_clk); + clk_set_rate(ahb_clk, LPAPM_CLK); + } + low_bus_freq_mode = 1; + audio_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_LOW; + } + clk_disable_unprepare(pfd2_270m); +} + +static void exit_lpm_imx7d(void) +{ + clk_set_parent(axi_sel_clk, pfd1_332m); + clk_set_rate(ahb_clk, LPAPM_CLK / 2); + clk_set_parent(ahb_sel_clk, pfd2_270m); + + busfreq_func.update(ddr_normal_rate); + + clk_set_parent(dram_root, pll_dram); +} + +static void reduce_bus_freq(void) +{ + if (cpu_is_imx6()) + clk_prepare_enable(pll3_clk); + + if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode)) + busfreq_notify(LOW_BUSFREQ_EXIT); + else if (!audio_bus_count) + busfreq_notify(LOW_BUSFREQ_ENTER); + + if (cpu_is_imx7d()) + enter_lpm_imx7d(); + else if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) + enter_lpm_imx6_up(); + else if (cpu_is_imx6q() || cpu_is_imx6dl()) + enter_lpm_imx6_smp(); + else if (cpu_is_imx6sl()) + enter_lpm_imx6sl(); + + med_bus_freq_mode = 0; + high_bus_freq_mode = 0; + + if (cpu_is_imx6()) + clk_disable_unprepare(pll3_clk); + + if (audio_bus_freq_mode) + dev_dbg(busfreq_dev, + "Bus freq set to audio mode. Count: high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + if (low_bus_freq_mode) + dev_dbg(busfreq_dev, + "Bus freq set to low mode. Count: high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); +} + +static inline void cancel_low_bus_freq_handler(void) +{ + cancel_delayed_work(&low_bus_freq_handler); + cancel_reduce_bus_freq = true; +} + +static void reduce_bus_freq_handler(struct work_struct *work) +{ + mutex_lock(&bus_freq_mutex); + + if (!cancel_reduce_bus_freq) { + reduce_bus_freq(); + cancel_low_bus_freq_handler(); + } + + mutex_unlock(&bus_freq_mutex); +} + +/* + * Set the DDR, AHB to 24MHz. + * This mode will be activated only when none of the modules that + * need a higher DDR or AHB frequency are active. + */ +static int set_low_bus_freq(void) +{ + if (busfreq_suspended) + return 0; + + if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) + return 0; + + cancel_reduce_bus_freq = false; + + /* + * Check to see if we need to got from + * low bus freq mode to audio bus freq mode. + * If so, the change needs to be done immediately. + */ + if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode)) + reduce_bus_freq(); + else + /* + * Don't lower the frequency immediately. Instead + * scheduled a delayed work and drop the freq if + * the conditions still remain the same. + */ + schedule_delayed_work(&low_bus_freq_handler, + usecs_to_jiffies(3000000)); + return 0; +} + +/* + * Set the DDR to either 528MHz or 400MHz for iMX6qd + * or 400MHz for iMX6dl. + */ +static int set_high_bus_freq(int high_bus_freq) +{ + if (bus_freq_scaling_initialized && bus_freq_scaling_is_active) + cancel_low_bus_freq_handler(); + + if (busfreq_suspended) + return 0; + + if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) + return 0; + + if (high_bus_freq_mode) + return 0; + + /* medium bus freq is only supported for MX6DQ */ + if (med_bus_freq_mode && !high_bus_freq) + return 0; + + if (low_bus_freq_mode || ultra_low_bus_freq_mode) + busfreq_notify(LOW_BUSFREQ_EXIT); + + if (cpu_is_imx6()) + clk_prepare_enable(pll3_clk); + + if (cpu_is_imx7d()) + exit_lpm_imx7d(); + else if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) + exit_lpm_imx6_up(); + else if (cpu_is_imx6q() || cpu_is_imx6dl()) + exit_lpm_imx6_smp(); + else if (cpu_is_imx6sl()) + exit_lpm_imx6sl(); + + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_HIGH; + + if (cpu_is_imx6()) + clk_disable_unprepare(pll3_clk); + + if (high_bus_freq_mode) + dev_dbg(busfreq_dev, + "Bus freq set to high mode. Count: high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + if (med_bus_freq_mode) + dev_dbg(busfreq_dev, + "Bus freq set to med mode. Count: high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + + return 0; +} + +void request_bus_freq(enum bus_freq_mode mode) +{ + mutex_lock(&bus_freq_mutex); + + if (mode == BUS_FREQ_ULTRA_LOW) { + dev_dbg(busfreq_dev, "This mode cannot be requested!\n"); + mutex_unlock(&bus_freq_mutex); + return; + } + + if (mode == BUS_FREQ_HIGH) + high_bus_count++; + else if (mode == BUS_FREQ_MED) + med_bus_count++; + else if (mode == BUS_FREQ_AUDIO) + audio_bus_count++; + else if (mode == BUS_FREQ_LOW) + low_bus_count++; + + if (busfreq_suspended || !bus_freq_scaling_initialized || + !bus_freq_scaling_is_active) { + mutex_unlock(&bus_freq_mutex); + return; + } + + cancel_low_bus_freq_handler(); + + if ((mode == BUS_FREQ_HIGH) && (!high_bus_freq_mode)) { + set_high_bus_freq(1); + mutex_unlock(&bus_freq_mutex); + return; + } + + if ((mode == BUS_FREQ_MED) && (!high_bus_freq_mode) && + (!med_bus_freq_mode)) { + set_high_bus_freq(0); + mutex_unlock(&bus_freq_mutex); + return; + } + if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) && + (!med_bus_freq_mode) && (!audio_bus_freq_mode)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + mutex_unlock(&bus_freq_mutex); +} +EXPORT_SYMBOL(request_bus_freq); + +void release_bus_freq(enum bus_freq_mode mode) +{ + mutex_lock(&bus_freq_mutex); + + if (mode == BUS_FREQ_ULTRA_LOW) { + dev_dbg(busfreq_dev, + "This mode cannot be released!\n"); + mutex_unlock(&bus_freq_mutex); + return; + } + + if (mode == BUS_FREQ_HIGH) { + if (high_bus_count == 0) { + dev_err(busfreq_dev, "high bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + high_bus_count--; + } else if (mode == BUS_FREQ_MED) { + if (med_bus_count == 0) { + dev_err(busfreq_dev, "med bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + med_bus_count--; + } else if (mode == BUS_FREQ_AUDIO) { + if (audio_bus_count == 0) { + dev_err(busfreq_dev, "audio bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + audio_bus_count--; + } else if (mode == BUS_FREQ_LOW) { + if (low_bus_count == 0) { + dev_err(busfreq_dev, "low bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + low_bus_count--; + } + + if (busfreq_suspended || !bus_freq_scaling_initialized || + !bus_freq_scaling_is_active) { + mutex_unlock(&bus_freq_mutex); + return; + } + + if ((!audio_bus_freq_mode) && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count != 0)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + if ((!low_bus_freq_mode) && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count == 0) && + (low_bus_count != 0)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + if ((!ultra_low_bus_freq_mode) && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count == 0) && + (low_bus_count == 0)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + + mutex_unlock(&bus_freq_mutex); +} +EXPORT_SYMBOL(release_bus_freq); + +int get_bus_freq_mode(void) +{ + return cur_bus_freq_mode; +} +EXPORT_SYMBOL(get_bus_freq_mode); + +static struct map_desc ddr_iram_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_1M, + .type = MT_MEMORY_RWX_NONCACHED, +}; + +const static char *ddr_freq_iram_match[] __initconst = { + "fsl,ddr-lpm-sram", + NULL +}; + +static int __init imx_dt_find_ddr_sram(unsigned long node, + const char *uname, int depth, void *data) +{ + unsigned long ddr_iram_addr; + const __be32 *prop; + + if (of_flat_dt_match(node, ddr_freq_iram_match)) { + unsigned int len; + + prop = of_get_flat_dt_prop(node, "reg", &len); + if (prop == NULL || len != (sizeof(unsigned long) * 2)) + return -EINVAL; + ddr_iram_addr = be32_to_cpu(prop[0]); + ddr_freq_change_total_size = be32_to_cpu(prop[1]); + ddr_freq_change_iram_phys = ddr_iram_addr; + + /* Make sure ddr_freq_change_iram_phys is 8 byte aligned. */ + if ((uintptr_t)(ddr_freq_change_iram_phys) & (FNCPY_ALIGN - 1)) + ddr_freq_change_iram_phys += FNCPY_ALIGN - + ((uintptr_t)ddr_freq_change_iram_phys % + (FNCPY_ALIGN)); + } + return 0; +} + +void __init imx_busfreq_map_io(void) +{ + /* + * Get the address of IRAM to be used by the ddr frequency + * change code from the device tree. + */ + WARN_ON(of_scan_flat_dt(imx_dt_find_ddr_sram, NULL)); + if (ddr_freq_change_iram_phys) { + ddr_freq_change_iram_base = IMX_IO_P2V( + ddr_freq_change_iram_phys); + if ((iram_tlb_phys_addr & 0xFFF00000) != + (ddr_freq_change_iram_phys & 0xFFF00000)) { + /* We need to create a 1M page table entry. */ + ddr_iram_io_desc.virtual = IMX_IO_P2V( + ddr_freq_change_iram_phys & 0xFFF00000); + ddr_iram_io_desc.pfn = __phys_to_pfn( + ddr_freq_change_iram_phys & 0xFFF00000); + iotable_init(&ddr_iram_io_desc, 1); + } + memset((void *)ddr_freq_change_iram_base, 0, + ddr_freq_change_total_size); + } +} + +static void bus_freq_daemon_handler(struct work_struct *work) +{ + mutex_lock(&bus_freq_mutex); + if ((!low_bus_freq_mode) && (!ultra_low_bus_freq_mode) + && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count == 0)) + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); +} + +static ssize_t bus_freq_scaling_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (bus_freq_scaling_is_active) + return sprintf(buf, "Bus frequency scaling is enabled\n"); + else + return sprintf(buf, "Bus frequency scaling is disabled\n"); +} + +static ssize_t bus_freq_scaling_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + if (strncmp(buf, "1", 1) == 0) { + bus_freq_scaling_is_active = 1; + set_high_bus_freq(1); + /* + * We set bus freq to highest at the beginning, + * so we use this daemon thread to make sure system + * can enter low bus mode if + * there is no high bus request pending + */ + schedule_delayed_work(&bus_freq_daemon, + usecs_to_jiffies(5000000)); + } else if (strncmp(buf, "0", 1) == 0) { + if (bus_freq_scaling_is_active) + set_high_bus_freq(1); + bus_freq_scaling_is_active = 0; + } + return size; +} + +static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + mutex_lock(&bus_freq_mutex); + + if (event == PM_SUSPEND_PREPARE) { + if (cpu_is_imx7d() && imx_src_is_m4_enabled()) + imx_mu_lpm_ready(false); + high_bus_count++; + set_high_bus_freq(1); + busfreq_suspended = 1; + } else if (event == PM_POST_SUSPEND) { + busfreq_suspended = 0; + high_bus_count--; + if (cpu_is_imx7d() && imx_src_is_m4_enabled()) + imx_mu_lpm_ready(true); + schedule_delayed_work(&bus_freq_daemon, + usecs_to_jiffies(5000000)); + } + + mutex_unlock(&bus_freq_mutex); + + return NOTIFY_OK; +} + +static int busfreq_reboot_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + /* System is rebooting. Set the system into high_bus_freq_mode. */ + request_bus_freq(BUS_FREQ_HIGH); + + return 0; +} + +static struct notifier_block imx_bus_freq_pm_notifier = { + .notifier_call = bus_freq_pm_notify, +}; + +static struct notifier_block imx_busfreq_reboot_notifier = { + .notifier_call = busfreq_reboot_notifier_event, +}; + + +static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show, + bus_freq_scaling_enable_store); + +/*! + * This is the probe routine for the bus frequency driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ + +static int busfreq_probe(struct platform_device *pdev) +{ + u32 err; +#ifdef CONFIG_OPTEE + struct device_node *node_optee = 0; + uint32_t busfreq_val; +#endif + + busfreq_dev = &pdev->dev; + + /* Return if no IRAM space is allocated for ddr freq change code. */ + if (!ddr_freq_change_iram_base) + return -ENOMEM; + + if (cpu_is_imx6()) { + osc_clk = devm_clk_get(&pdev->dev, "osc"); + pll2_400_clk = devm_clk_get(&pdev->dev, "pll2_pfd2_396m"); + pll2_200_clk = devm_clk_get(&pdev->dev, "pll2_198m"); + pll2_bus_clk = devm_clk_get(&pdev->dev, "pll2_bus"); + pll3_clk = devm_clk_get(&pdev->dev, "pll3_usb_otg"); + periph_clk = devm_clk_get(&pdev->dev, "periph"); + periph_pre_clk = devm_clk_get(&pdev->dev, "periph_pre"); + periph_clk2_clk = devm_clk_get(&pdev->dev, "periph_clk2"); + periph_clk2_sel_clk = devm_clk_get(&pdev->dev, + "periph_clk2_sel"); + if (IS_ERR(osc_clk) || IS_ERR(pll2_400_clk) + || IS_ERR(pll2_200_clk) || IS_ERR(pll2_bus_clk) + || IS_ERR(pll3_clk) || IS_ERR(periph_clk) + || IS_ERR(periph_pre_clk) || IS_ERR(periph_clk2_clk) + || IS_ERR(periph_clk2_sel_clk)) { + dev_err(busfreq_dev, + "%s: failed to get busfreq clk\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6dl()) { + axi_alt_sel_clk = devm_clk_get(&pdev->dev, "axi_alt_sel"); + axi_sel_clk = devm_clk_get(&pdev->dev, "axi_sel"); + pll3_pfd1_540m_clk = devm_clk_get(&pdev->dev, "pll3_pfd1_540m"); + if (IS_ERR(axi_alt_sel_clk) || IS_ERR(axi_sel_clk) + || IS_ERR(pll3_pfd1_540m_clk)) { + dev_err(busfreq_dev, + "%s: failed to get busfreq clk\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6sx() || cpu_is_imx6sl() || cpu_is_imx6ul() || + cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) { + ahb_clk = devm_clk_get(&pdev->dev, "ahb"); + ocram_clk = devm_clk_get(&pdev->dev, "ocram"); + periph2_clk = devm_clk_get(&pdev->dev, "periph2"); + periph2_pre_clk = devm_clk_get(&pdev->dev, "periph2_pre"); + periph2_clk2_clk = devm_clk_get(&pdev->dev, "periph2_clk2"); + periph2_clk2_sel_clk = + devm_clk_get(&pdev->dev, "periph2_clk2_sel"); + if (IS_ERR(ahb_clk) || IS_ERR(ocram_clk) + || IS_ERR(periph2_clk) || IS_ERR(periph2_pre_clk) + || IS_ERR(periph2_clk2_clk) + || IS_ERR(periph2_clk2_sel_clk)) { + dev_err(busfreq_dev, + "%s: failed to get busfreq clk for imx6ul/sx/sl.\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) { + mmdc_clk = devm_clk_get(&pdev->dev, "mmdc"); + if (IS_ERR(mmdc_clk)) { + dev_err(busfreq_dev, + "%s: failed to get mmdc clk for imx6sx/ul.\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6q()) { + mmdc_clk = devm_clk_get(&pdev->dev, "mmdc"); + if (IS_ERR(mmdc_clk)) { + mmdc_clk = NULL; + } + } + + if (cpu_is_imx6sx()) { + m4_clk = devm_clk_get(&pdev->dev, "m4"); + if (IS_ERR(m4_clk)) { + dev_err(busfreq_dev, "%s: failed to get m4 clk.\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6sl()) { + pll2_bypass_src_clk = devm_clk_get(&pdev->dev, "pll2_bypass_src"); + pll2_bypass_clk = devm_clk_get(&pdev->dev, "pll2_bypass"); + pll2_clk = devm_clk_get(&pdev->dev, "pll2"); + if (IS_ERR(pll2_bypass_src_clk) || IS_ERR(pll2_bypass_clk) + || IS_ERR(pll2_clk)) { + dev_err(busfreq_dev, + "%s failed to get busfreq clk for imx6sl.\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6sl() || cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) { + arm_clk = devm_clk_get(&pdev->dev, "arm"); + step_clk = devm_clk_get(&pdev->dev, "step"); + pll1_clk = devm_clk_get(&pdev->dev, "pll1"); + pll1_bypass_src_clk = devm_clk_get(&pdev->dev, "pll1_bypass_src"); + pll1_bypass_clk = devm_clk_get(&pdev->dev, "pll1_bypass"); + pll1_sys_clk = devm_clk_get(&pdev->dev, "pll1_sys"); + pll1_sw_clk = devm_clk_get(&pdev->dev, "pll1_sw"); + if (IS_ERR(arm_clk) || IS_ERR(step_clk) || IS_ERR(pll1_clk) + || IS_ERR(pll1_bypass_src_clk) || IS_ERR(pll1_bypass_clk) + || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk)) { + dev_err(busfreq_dev, "%s failed to get busfreq clk for imx6ull/sl.\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx7d()) { + osc_clk = devm_clk_get(&pdev->dev, "osc"); + axi_sel_clk = devm_clk_get(&pdev->dev, "axi_sel"); + ahb_sel_clk = devm_clk_get(&pdev->dev, "ahb_sel"); + pfd0_392m = devm_clk_get(&pdev->dev, "pfd0_392m"); + dram_root = devm_clk_get(&pdev->dev, "dram_root"); + dram_alt_sel = devm_clk_get(&pdev->dev, "dram_alt_sel"); + pll_dram = devm_clk_get(&pdev->dev, "pll_dram"); + dram_alt_root = devm_clk_get(&pdev->dev, "dram_alt_root"); + pfd1_332m = devm_clk_get(&pdev->dev, "pfd1_332m"); + pfd2_270m = devm_clk_get(&pdev->dev, "pfd2_270m"); + ahb_clk = devm_clk_get(&pdev->dev, "ahb"); + axi_clk = devm_clk_get(&pdev->dev, "axi"); + if (IS_ERR(osc_clk) || IS_ERR(axi_sel_clk) || IS_ERR(ahb_clk) + || IS_ERR(pfd0_392m) || IS_ERR(dram_root) + || IS_ERR(dram_alt_sel) || IS_ERR(pll_dram) + || IS_ERR(dram_alt_root) || IS_ERR(pfd1_332m) + || IS_ERR(ahb_clk) || IS_ERR(axi_clk) + || IS_ERR(pfd2_270m)) { + dev_err(busfreq_dev, + "%s: failed to get busfreq clk\n", __func__); + return -EINVAL; + } + } + + err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + if (err) { + dev_err(busfreq_dev, + "Unable to register sysdev entry for BUSFREQ"); + return err; + } + + if (of_property_read_u32(pdev->dev.of_node, "fsl,max_ddr_freq", + &ddr_normal_rate)) { + dev_err(busfreq_dev, "max_ddr_freq entry missing\n"); + return -EINVAL; + } + + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + ultra_low_bus_freq_mode = 0; + cur_bus_freq_mode = BUS_FREQ_HIGH; + + bus_freq_scaling_is_active = 1; + bus_freq_scaling_initialized = 1; + + ddr_low_rate = LPAPM_CLK; + + INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler); + INIT_DELAYED_WORK(&bus_freq_daemon, bus_freq_daemon_handler); + register_pm_notifier(&imx_bus_freq_pm_notifier); + register_reboot_notifier(&imx_busfreq_reboot_notifier); + + /* enter low bus mode if no high speed device enabled */ + schedule_delayed_work(&bus_freq_daemon, + msecs_to_jiffies(20000)); + + /* + * Need to make sure to an entry for the ddr freq change code + * address in the IRAM page table. + * This is only required if the DDR freq code and suspend/idle + * code are in different OCRAM spaces. + */ + if ((iram_tlb_phys_addr & 0xFFF00000) != + (ddr_freq_change_iram_phys & 0xFFF00000)) { + unsigned long i; + + /* + * Make sure the ddr_iram virtual address has a mapping + * in the IRAM page table. + */ + i = ((IMX_IO_P2V(ddr_freq_change_iram_phys) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (ddr_freq_change_iram_phys & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } + + if (cpu_is_imx7d()) { + ddr_type = imx_ddrc_get_ddr_type(); + /* reduce ddr3 normal rate to 400M due to CKE issue on TO1.1 */ + if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_1 && + ddr_type == IMX_DDR_TYPE_DDR3) { + ddr_normal_rate = 400000000; + pr_info("ddr3 normal rate changed to 400MHz for TO1.1.\n"); + } + busfreq_func.init = &init_ddrc_ddr_settings; + busfreq_func.update = &update_ddr_freq_imx_smp; + + } else if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz() || + cpu_is_imx6sll()) { + ddr_type = imx_mmdc_get_ddr_type(); + if (ddr_type == IMX_DDR_TYPE_DDR3) { + busfreq_func.init = &init_mmdc_ddr3_settings_imx6_up; + busfreq_func.update = &update_ddr_freq_imx6_up; + } else if (ddr_type == IMX_DDR_TYPE_LPDDR2 || + ddr_type == IMX_MMDC_DDR_TYPE_LPDDR3) { + busfreq_func.init = &init_mmdc_lpddr2_settings; + busfreq_func.update = &update_lpddr2_freq; + } + } else if (cpu_is_imx6q() || cpu_is_imx6dl()) { + ddr_type = imx_mmdc_get_ddr_type(); + if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) { + busfreq_func.init = &init_mmdc_ddr3_settings_imx6_smp; + busfreq_func.update = &update_ddr_freq_imx_smp; + } else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) { + busfreq_func.init = &init_mmdc_lpddr2_settings_mx6q; + busfreq_func.update = &update_lpddr2_freq_smp; + } + } else if (cpu_is_imx6sl()) { + busfreq_func.init = &init_mmdc_lpddr2_settings; + busfreq_func.update = &update_lpddr2_freq; + } + +#ifdef CONFIG_OPTEE + /* + * Find the OPTEE node in the DT and look for the + * busfreq property. + * If property present and set to 1, busfreq is done by + * calling the OPTEE OS + */ + node_optee = of_find_compatible_node(NULL, NULL, "linaro,optee-tz"); + + if (node_optee) { + if (of_property_read_u32(node_optee, "busfreq", + &busfreq_val) == 0) { + pr_info("OPTEE busfreq %s", + (busfreq_val ? "Supported" : "Not Supported")); + if (busfreq_val) { + busfreq_func.init = &init_freq_optee; + busfreq_func.update = &update_freq_optee; + } + } + } +#endif + + if (busfreq_func.init) + err = busfreq_func.init(pdev); + else + err = -EINVAL; + + if (!err) { + if (cpu_is_imx6sx()) { + /* + * If M4 is enabled and rate > 24MHz, + * add high bus count + */ + if (imx_src_is_m4_enabled() && + (clk_get_rate(m4_clk) > LPAPM_CLK)) + high_bus_count++; + } + + if (cpu_is_imx7d() && imx_src_is_m4_enabled()) { + high_bus_count++; + imx_mu_lpm_ready(true); + } + } + + if (err) { + dev_err(busfreq_dev, "Busfreq init of ddr controller failed\n"); + return err; + } + + return 0; +} + +static const struct of_device_id imx_busfreq_ids[] = { + { .compatible = "fsl,imx_busfreq", }, + { /* sentinel */ } +}; + +static struct platform_driver busfreq_driver = { + .driver = { + .name = "imx_busfreq", + .owner = THIS_MODULE, + .of_match_table = imx_busfreq_ids, + }, + .probe = busfreq_probe, +}; + +/*! + * Initialise the busfreq_driver. + * + * @return The function always returns 0. + */ + +static int __init busfreq_init(void) +{ +#ifndef CONFIG_MX6_VPU_352M + if (platform_driver_register(&busfreq_driver) != 0) + return -ENODEV; + + pr_info("Bus freq driver module loaded\n"); +#endif + return 0; +} + +static void __exit busfreq_cleanup(void) +{ + sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&busfreq_driver); + bus_freq_scaling_initialized = 0; +} + +module_init(busfreq_init); +module_exit(busfreq_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("BusFreq driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-imx/busfreq_ddr3.c b/arch/arm/mach-imx/busfreq_ddr3.c new file mode 100644 index 000000000000..0088a5d80736 --- /dev/null +++ b/arch/arm/mach-imx/busfreq_ddr3.c @@ -0,0 +1,772 @@ +/* + * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file busfreq_ddr3.c + * + * @brief iMX6 DDR3 frequency change specific file. + * + * @ingroup PM + */ +#include <asm/cacheflush.h> +#include <asm/fncpy.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/tlb.h> +#include <linux/busfreq-imx.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/genalloc.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp.h> + +#include "hardware.h" +#include "common.h" + +#define SMP_WFE_CODE_SIZE 0x400 + +#define MIN_DLL_ON_FREQ 333000000 +#define MAX_DLL_OFF_FREQ 125000000 +#define MMDC0_MPMUR0 0x8b8 +#define MMDC0_MPMUR0_OFFSET 16 +#define MMDC0_MPMUR0_MASK 0x3ff + +/* + * This structure is for passing necessary data for low level ocram + * busfreq code(arch/arm/mach-imx/ddr3_freq_imx6.S), if this struct + * definition is changed, the offset definition in + * arch/arm/mach-imx/ddr3_freq_imx6.S must be also changed accordingly, + * otherwise, the busfreq change function will be broken! + * + * This structure will be placed in front of the asm code on ocram. + */ +struct imx6_busfreq_info { + u32 freq; + void *ddr_settings; + u32 dll_off; + void *iomux_offsets; + u32 mu_delay_val; +} __aligned(8); + +static struct imx6_busfreq_info *imx6_busfreq_info; + +/* DDR settings */ +static unsigned long (*iram_ddr_settings)[2]; +static unsigned long (*normal_mmdc_settings)[2]; +static unsigned long (*iram_iomux_settings)[2]; + +static void __iomem *mmdc_base; +static void __iomem *iomux_base; +static void __iomem *gic_dist_base; + +static int ddr_settings_size; +static int iomux_settings_size; +static int curr_ddr_rate; + +void (*imx6_up_change_ddr_freq)(struct imx6_busfreq_info *busfreq_info); +extern void imx6_up_ddr3_freq_change(struct imx6_busfreq_info *busfreq_info); +void (*imx7d_change_ddr_freq)(u32 freq) = NULL; +extern void imx7d_ddr3_freq_change(u32 freq); +extern void imx_lpddr3_freq_change(u32 freq); + +void (*mx6_change_ddr_freq)(u32 freq, void *ddr_settings, + bool dll_mode, void *iomux_offsets) = NULL; + +extern unsigned int ddr_normal_rate; +extern int low_bus_freq_mode; +extern int audio_bus_freq_mode; +extern void mx6_ddr3_freq_change(u32 freq, void *ddr_settings, + bool dll_mode, void *iomux_offsets); + +extern unsigned long save_ttbr1(void); +extern void restore_ttbr1(unsigned long ttbr1); +extern unsigned long ddr_freq_change_iram_base; + +extern unsigned long ddr_freq_change_total_size; +extern unsigned long iram_tlb_phys_addr; + +extern unsigned long mx6_ddr3_freq_change_start asm("mx6_ddr3_freq_change_start"); +extern unsigned long mx6_ddr3_freq_change_end asm("mx6_ddr3_freq_change_end"); +extern unsigned long imx6_up_ddr3_freq_change_start asm("imx6_up_ddr3_freq_change_start"); +extern unsigned long imx6_up_ddr3_freq_change_end asm("imx6_up_ddr3_freq_change_end"); + +#ifdef CONFIG_SMP +static unsigned long wfe_freq_change_iram_base; +volatile u32 *wait_for_ddr_freq_update; +static unsigned int online_cpus; +static u32 *irqs_used; + +void (*wfe_change_ddr_freq)(u32 cpuid, u32 *ddr_freq_change_done); +void (*imx7_wfe_change_ddr_freq)(u32 cpuid, u32 ocram_base); +extern void wfe_smp_freq_change(u32 cpuid, u32 *ddr_freq_change_done); +extern void imx7_smp_wfe(u32 cpuid, u32 ocram_base); +extern unsigned long wfe_smp_freq_change_start asm("wfe_smp_freq_change_start"); +extern unsigned long wfe_smp_freq_change_end asm("wfe_smp_freq_change_end"); +extern void __iomem *scu_base; +#endif + +unsigned long ddr3_dll_mx6sx[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04008032}, + {0x1C, 0x00048031}, + {0x1C, 0x05208030}, + {0x1C, 0x04008040}, + {0x818, 0x0}, + {0x18, 0x0}, +}; + +unsigned long ddr3_calibration_mx6sx[][2] = { + {0x83c, 0x0}, + {0x840, 0x0}, + {0x848, 0x0}, + {0x850, 0x0}, +}; + +unsigned long iomux_offsets_mx6sx[][2] = { + {0x330, 0x0}, + {0x334, 0x0}, + {0x338, 0x0}, + {0x33c, 0x0}, +}; + +unsigned long iomux_offsets_mx6ul[][2] = { + {0x280, 0x0}, + {0x284, 0x0}, +}; + +unsigned long ddr3_dll_mx6q[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04088032}, + {0x1C, 0x0408803a}, + {0x1C, 0x08408030}, + {0x1C, 0x08408038}, + {0x818, 0x0}, + {0x18, 0x0}, +}; + +unsigned long ddr3_calibration[][2] = { + {0x83c, 0x0}, + {0x840, 0x0}, + {0x483c, 0x0}, + {0x4840, 0x0}, + {0x848, 0x0}, + {0x4848, 0x0}, + {0x850, 0x0}, + {0x4850, 0x0}, +}; + +unsigned long iomux_offsets_mx6q[][2] = { + {0x5A8, 0x0}, + {0x5B0, 0x0}, + {0x524, 0x0}, + {0x51C, 0x0}, + {0x518, 0x0}, + {0x50C, 0x0}, + {0x5B8, 0x0}, + {0x5C0, 0x0}, +}; + +unsigned long ddr3_dll_mx6dl[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04008032}, + {0x1C, 0x0400803a}, + {0x1C, 0x07208030}, + {0x1C, 0x07208038}, + {0x818, 0x0}, + {0x18, 0x0}, +}; + +unsigned long iomux_offsets_mx6dl[][2] = { + {0x4BC, 0x0}, + {0x4C0, 0x0}, + {0x4C4, 0x0}, + {0x4C8, 0x0}, + {0x4CC, 0x0}, + {0x4D0, 0x0}, + {0x4D4, 0x0}, + {0x4D8, 0x0}, +}; + +int can_change_ddr_freq(void) +{ + return 1; +} + +#ifdef CONFIG_SMP +/* + * each active core apart from the one changing + * the DDR frequency will execute this function. + * the rest of the cores have to remain in WFE + * state until the frequency is changed. + */ +static irqreturn_t wait_in_wfe_irq(int irq, void *dev_id) +{ + u32 me; + + me = smp_processor_id(); +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, + &me); +#endif + if (cpu_is_imx7d()) + imx7_wfe_change_ddr_freq(0x8 * me, + (u32)ddr_freq_change_iram_base); + else + wfe_change_ddr_freq(0xff << (me * 8), + (u32 *)&iram_iomux_settings[0][1]); +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, + &me); +#endif + + return IRQ_HANDLED; +} +#endif + +/* change the DDR frequency. */ +int update_ddr_freq_imx_smp(int ddr_rate) +{ + int me = 0; + unsigned long ttbr1; + bool dll_off = false; + int i; +#ifdef CONFIG_SMP + unsigned int reg = 0; + int cpu = 0; +#endif + int mode = get_bus_freq_mode(); + + if (!can_change_ddr_freq()) + return -1; + + if (ddr_rate == curr_ddr_rate) + return 0; + + printk(KERN_DEBUG "\nBus freq set to %d start...\n", ddr_rate); + + if (cpu_is_imx6()) { + if ((mode == BUS_FREQ_LOW) || (mode == BUS_FREQ_AUDIO)) + dll_off = true; + + iram_ddr_settings[0][0] = ddr_settings_size; + iram_iomux_settings[0][0] = iomux_settings_size; + if (ddr_rate == ddr_normal_rate) { + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + iram_ddr_settings[i + 1][0] = + normal_mmdc_settings[i][0]; + iram_ddr_settings[i + 1][1] = + normal_mmdc_settings[i][1]; + } + } + } + + /* ensure that all Cores are in WFE. */ + local_irq_disable(); + +#ifdef CONFIG_SMP + me = smp_processor_id(); + + /* Make sure all the online cores are active */ + while (1) { + bool not_exited_busfreq = false; + u32 reg = 0; + + for_each_online_cpu(cpu) { + if (cpu_is_imx7d()) + reg = *(wait_for_ddr_freq_update + 1); + else if (cpu_is_imx6()) + reg = __raw_readl(scu_base + 0x08); + + if (reg & (0x02 << (cpu * 8))) + not_exited_busfreq = true; + } + if (!not_exited_busfreq) + break; + } + + wmb(); + *wait_for_ddr_freq_update = 1; + dsb(); + if (cpu_is_imx7d()) + online_cpus = *(wait_for_ddr_freq_update + 1); + else if (cpu_is_imx6()) + online_cpus = readl_relaxed(scu_base + 0x08); + for_each_online_cpu(cpu) { + *((char *)(&online_cpus) + (u8)cpu) = 0x02; + if (cpu != me) { + /* set the interrupt to be pending in the GIC. */ + reg = 1 << (irqs_used[cpu] % 32); + writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + + (irqs_used[cpu] / 32) * 4); + } + } + /* Wait for the other active CPUs to idle */ + while (1) { + u32 reg = 0; + + if (cpu_is_imx7d()) + reg = *(wait_for_ddr_freq_update + 1); + else if (cpu_is_imx6()) + reg = readl_relaxed(scu_base + 0x08); + reg |= (0x02 << (me * 8)); + if (reg == online_cpus) + break; + } +#endif + + /* Ensure iram_tlb_phys_addr is flushed to DDR. */ + __cpuc_flush_dcache_area(&iram_tlb_phys_addr, + sizeof(iram_tlb_phys_addr)); + if (cpu_is_imx6()) + outer_clean_range(__pa(&iram_tlb_phys_addr), + __pa(&iram_tlb_phys_addr + 1)); + + ttbr1 = save_ttbr1(); + /* Now we can change the DDR frequency. */ + if (cpu_is_imx7d()) + imx7d_change_ddr_freq(ddr_rate); + else if (cpu_is_imx6()) + mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, + dll_off, iram_iomux_settings); + restore_ttbr1(ttbr1); + curr_ddr_rate = ddr_rate; + +#ifdef CONFIG_SMP + wmb(); + /* DDR frequency change is done . */ + *wait_for_ddr_freq_update = 0; + dsb(); + + /* wake up all the cores. */ + sev(); +#endif + + local_irq_enable(); + + printk(KERN_DEBUG "Bus freq set to %d done! cpu=%d\n", ddr_rate, me); + + return 0; +} + +/* Used by i.MX6SX/i.MX6UL for updating the ddr frequency */ +int update_ddr_freq_imx6_up(int ddr_rate) +{ + int i; + bool dll_off = false; + unsigned long ttbr1; + int mode = get_bus_freq_mode(); + + if (ddr_rate == curr_ddr_rate) + return 0; + + printk(KERN_DEBUG "\nBus freq set to %d start...\n", ddr_rate); + + if ((mode == BUS_FREQ_LOW) || (mode == BUS_FREQ_AUDIO)) + dll_off = true; + + imx6_busfreq_info->dll_off = dll_off; + iram_ddr_settings[0][0] = ddr_settings_size; + iram_iomux_settings[0][0] = iomux_settings_size; + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + iram_ddr_settings[i + 1][0] = + normal_mmdc_settings[i][0]; + iram_ddr_settings[i + 1][1] = + normal_mmdc_settings[i][1]; + } + + local_irq_disable(); + + ttbr1 = save_ttbr1(); + imx6_busfreq_info->freq = ddr_rate; + imx6_busfreq_info->ddr_settings = iram_ddr_settings; + imx6_busfreq_info->iomux_offsets = iram_iomux_settings; + imx6_busfreq_info->mu_delay_val = ((readl_relaxed(mmdc_base + MMDC0_MPMUR0) + >> MMDC0_MPMUR0_OFFSET) & MMDC0_MPMUR0_MASK); + + imx6_up_change_ddr_freq(imx6_busfreq_info); + restore_ttbr1(ttbr1); + curr_ddr_rate = ddr_rate; + + local_irq_enable(); + + printk(KERN_DEBUG "Bus freq set to %d done!\n", ddr_rate); + + return 0; +} + +int init_ddrc_ddr_settings(struct platform_device *busfreq_pdev) +{ + int ddr_type = imx_ddrc_get_ddr_type(); +#ifdef CONFIG_SMP + struct device_node *node; + u32 cpu; + struct device *dev = &busfreq_pdev->dev; + int err; + struct irq_data *d; + + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a7-gic"); + if (!node) { + printk(KERN_ERR "failed to find imx7d-a7-gic device tree data!\n"); + return -EINVAL; + } + gic_dist_base = of_iomap(node, 0); + WARN(!gic_dist_base, "unable to map gic dist registers\n"); + + irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(), + GFP_KERNEL); + for_each_online_cpu(cpu) { + int irq; + /* + * set up a reserved interrupt to get all + * the active cores into a WFE state + * before changing the DDR frequency. + */ + irq = platform_get_irq(busfreq_pdev, cpu); + err = request_irq(irq, wait_in_wfe_irq, + IRQF_PERCPU, "ddrc", NULL); + if (err) { + dev_err(dev, + "Busfreq:request_irq failed %d, err = %d\n", + irq, err); + return err; + } + err = irq_set_affinity(irq, cpumask_of(cpu)); + if (err) { + dev_err(dev, + "Busfreq: Cannot set irq affinity irq=%d\n", + irq); + return err; + } + d = irq_get_irq_data(irq); + irqs_used[cpu] = d->hwirq + 32; + } + + /* Store the variable used to communicate between cores */ + wait_for_ddr_freq_update = (u32 *)ddr_freq_change_iram_base; + imx7_wfe_change_ddr_freq = (void *)fncpy( + (void *)ddr_freq_change_iram_base + 0x8, + &imx7_smp_wfe, SMP_WFE_CODE_SIZE - 0x8); +#endif + if (ddr_type == IMX_DDR_TYPE_DDR3) + imx7d_change_ddr_freq = (void *)fncpy( + (void *)ddr_freq_change_iram_base + SMP_WFE_CODE_SIZE, + &imx7d_ddr3_freq_change, + MX7_BUSFREQ_OCRAM_SIZE - SMP_WFE_CODE_SIZE); + else if (ddr_type == IMX_DDR_TYPE_LPDDR3 + || ddr_type == IMX_DDR_TYPE_LPDDR2) + imx7d_change_ddr_freq = (void *)fncpy( + (void *)ddr_freq_change_iram_base + + SMP_WFE_CODE_SIZE, + &imx_lpddr3_freq_change, + MX7_BUSFREQ_OCRAM_SIZE - SMP_WFE_CODE_SIZE); + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} + +/* Used by i.MX6SX/i.MX6UL for mmdc setting init. */ +int init_mmdc_ddr3_settings_imx6_up(struct platform_device *busfreq_pdev) +{ + int i; + struct device_node *node; + unsigned long ddr_code_size; + + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc"); + if (!node) { + printk(KERN_ERR "failed to find mmdc device tree data!\n"); + return -EINVAL; + } + mmdc_base = of_iomap(node, 0); + WARN(!mmdc_base, "unable to map mmdc registers\n"); + + if (cpu_is_imx6sx()) + node = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-iomuxc"); + else + node = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-iomuxc"); + if (!node) { + printk(KERN_ERR "failed to find iomuxc device tree data!\n"); + return -EINVAL; + } + iomux_base = of_iomap(node, 0); + WARN(!iomux_base, "unable to map iomux registers\n"); + + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6sx) + + ARRAY_SIZE(ddr3_calibration_mx6sx); + + normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); + memcpy(normal_mmdc_settings, ddr3_dll_mx6sx, + sizeof(ddr3_dll_mx6sx)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6sx)), + ddr3_calibration_mx6sx, sizeof(ddr3_calibration_mx6sx)); + + /* store the original DDR settings at boot. */ + for (i = 0; i < ddr_settings_size; i++) { + /* + * writes via command mode register cannot be read back. + * hence hardcode them in the initial static array. + * this may require modification on a per customer basis. + */ + if (normal_mmdc_settings[i][0] != 0x1C) + normal_mmdc_settings[i][1] = + readl_relaxed(mmdc_base + + normal_mmdc_settings[i][0]); + } + + if (cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz()) + iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6ul); + else + iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6sx); + + ddr_code_size = (&imx6_up_ddr3_freq_change_end -&imx6_up_ddr3_freq_change_start) *4 + + sizeof(*imx6_busfreq_info); + imx6_busfreq_info = (struct imx6_busfreq_info *)ddr_freq_change_iram_base; + + imx6_up_change_ddr_freq = (void *)fncpy((void *)ddr_freq_change_iram_base + sizeof(*imx6_busfreq_info), + &imx6_up_ddr3_freq_change, ddr_code_size - sizeof(*imx6_busfreq_info)); + + /* + * Store the size of the array in iRAM also, + * increase the size by 8 bytes. + */ + iram_iomux_settings = (void *)(ddr_freq_change_iram_base + ddr_code_size); + iram_ddr_settings = iram_iomux_settings + (iomux_settings_size * 8) + 8; + + if ((ddr_code_size + (iomux_settings_size + ddr_settings_size) * 8 + 16) + > ddr_freq_change_total_size) { + printk(KERN_ERR "Not enough memory allocated for DDR Frequency change code.\n"); + return EINVAL; + } + + for (i = 0; i < iomux_settings_size; i++) { + if (cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz()) { + iomux_offsets_mx6ul[i][1] = + readl_relaxed(iomux_base + + iomux_offsets_mx6ul[i][0]); + iram_iomux_settings[i + 1][0] = + iomux_offsets_mx6ul[i][0]; + iram_iomux_settings[i + 1][1] = + iomux_offsets_mx6ul[i][1]; + } else { + iomux_offsets_mx6sx[i][1] = + readl_relaxed(iomux_base + + iomux_offsets_mx6sx[i][0]); + iram_iomux_settings[i + 1][0] = + iomux_offsets_mx6sx[i][0]; + iram_iomux_settings[i + 1][1] = + iomux_offsets_mx6sx[i][1]; + } + } + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} + +int init_mmdc_ddr3_settings_imx6_smp(struct platform_device *busfreq_pdev) +{ + int i; + struct device_node *node; + unsigned long ddr_code_size; + unsigned long wfe_code_size = 0; +#ifdef CONFIG_SMP + u32 cpu; + struct device *dev = &busfreq_pdev->dev; + int err; + struct irq_data *d; +#endif + + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine"); + if (!node) { + printk(KERN_ERR "failed to find imx6q-mmdc device tree data!\n"); + return -EINVAL; + } + mmdc_base = of_iomap(node, 0); + WARN(!mmdc_base, "unable to map mmdc registers\n"); + + node = NULL; + if (cpu_is_imx6q()) + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-iomuxc"); + if (cpu_is_imx6dl()) + node = of_find_compatible_node(NULL, NULL, + "fsl,imx6dl-iomuxc"); + if (!node) { + printk(KERN_ERR "failed to find imx6q-iomux device tree data!\n"); + return -EINVAL; + } + iomux_base = of_iomap(node, 0); + WARN(!iomux_base, "unable to map iomux registers\n"); + + node = NULL; + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); + if (!node) { + printk(KERN_ERR "failed to find imx6q-a9-gic device tree data!\n"); + return -EINVAL; + } + gic_dist_base = of_iomap(node, 0); + WARN(!gic_dist_base, "unable to map gic dist registers\n"); + + if (cpu_is_imx6q()) + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + + ARRAY_SIZE(ddr3_calibration); + if (cpu_is_imx6dl()) + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + + ARRAY_SIZE(ddr3_calibration); + + normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); + if (cpu_is_imx6q()) { + memcpy(normal_mmdc_settings, ddr3_dll_mx6q, + sizeof(ddr3_dll_mx6q)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6q)), + ddr3_calibration, sizeof(ddr3_calibration)); + } + if (cpu_is_imx6dl()) { + memcpy(normal_mmdc_settings, ddr3_dll_mx6dl, + sizeof(ddr3_dll_mx6dl)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6dl)), + ddr3_calibration, sizeof(ddr3_calibration)); + } + /* store the original DDR settings at boot. */ + for (i = 0; i < ddr_settings_size; i++) { + /* + * writes via command mode register cannot be read back. + * hence hardcode them in the initial static array. + * this may require modification on a per customer basis. + */ + if (normal_mmdc_settings[i][0] != 0x1C) + normal_mmdc_settings[i][1] = + readl_relaxed(mmdc_base + + normal_mmdc_settings[i][0]); + } + +#ifdef CONFIG_SMP + irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(), + GFP_KERNEL); + + for_each_online_cpu(cpu) { + int irq; + + /* + * set up a reserved interrupt to get all + * the active cores into a WFE state + * before changing the DDR frequency. + */ + irq = platform_get_irq(busfreq_pdev, cpu); + err = request_irq(irq, wait_in_wfe_irq, + IRQF_PERCPU, "mmdc_1", NULL); + if (err) { + dev_err(dev, + "Busfreq:request_irq failed %d, err = %d\n", + irq, err); + return err; + } + err = irq_set_affinity(irq, cpumask_of(cpu)); + if (err) { + dev_err(dev, + "Busfreq: Cannot set irq affinity irq=%d,\n", + irq); + return err; + } + d = irq_get_irq_data(irq); + irqs_used[cpu] = d->hwirq + 32; + } +#endif + iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q); + + ddr_code_size = (&mx6_ddr3_freq_change_end - + &mx6_ddr3_freq_change_start) * 4; + + mx6_change_ddr_freq = (void *)fncpy((void *)ddr_freq_change_iram_base, + &mx6_ddr3_freq_change, ddr_code_size); + + /* + * Store the size of the array in iRAM also, + * increase the size by 8 bytes. + */ + iram_iomux_settings = (void *)(ddr_freq_change_iram_base + + ddr_code_size); + iram_ddr_settings = iram_iomux_settings + (iomux_settings_size * 8) + 8; +#ifdef CONFIG_SMP + wfe_freq_change_iram_base = (unsigned long)((u32 *)iram_ddr_settings + + (ddr_settings_size * 8) + 8); + + if (wfe_freq_change_iram_base & (FNCPY_ALIGN - 1)) + wfe_freq_change_iram_base += FNCPY_ALIGN - + ((uintptr_t)wfe_freq_change_iram_base % (FNCPY_ALIGN)); + + wfe_code_size = (&wfe_smp_freq_change_end - + &wfe_smp_freq_change_start) *4; + + wfe_change_ddr_freq = (void *)fncpy((void *)wfe_freq_change_iram_base, + &wfe_smp_freq_change, wfe_code_size); + + /* + * Store the variable used to communicate + * between cores in a non-cacheable IRAM area + */ + wait_for_ddr_freq_update = (u32 *)&iram_iomux_settings[0][1]; +#endif + + if ((ddr_code_size + wfe_code_size + (iomux_settings_size + + ddr_settings_size) * 8 + 16) + > ddr_freq_change_total_size) { + printk(KERN_ERR "Not enough memory for DDR Freq scale.\n"); + return EINVAL; + } + + if (cpu_is_imx6q()) { + /* store the IOMUX settings at boot. */ + for (i = 0; i < iomux_settings_size; i++) { + iomux_offsets_mx6q[i][1] = + readl_relaxed(iomux_base + + iomux_offsets_mx6q[i][0]); + iram_iomux_settings[i + 1][0] = + iomux_offsets_mx6q[i][0]; + iram_iomux_settings[i + 1][1] = + iomux_offsets_mx6q[i][1]; + } + } + + if (cpu_is_imx6dl()) { + for (i = 0; i < iomux_settings_size; i++) { + iomux_offsets_mx6dl[i][1] = + readl_relaxed(iomux_base + + iomux_offsets_mx6dl[i][0]); + iram_iomux_settings[i + 1][0] = + iomux_offsets_mx6dl[i][0]; + iram_iomux_settings[i + 1][1] = + iomux_offsets_mx6dl[i][1]; + } + } + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} diff --git a/arch/arm/mach-imx/busfreq_lpddr2.c b/arch/arm/mach-imx/busfreq_lpddr2.c new file mode 100644 index 000000000000..f5b3caa43645 --- /dev/null +++ b/arch/arm/mach-imx/busfreq_lpddr2.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2017 NXP. + */ + +/* + * 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 + */ + +/*! + * @file busfreq_lpddr2.c + * + * @brief iMX6 LPDDR2 frequency change specific file. + * + * @ingroup PM + */ +#include <asm/cacheflush.h> +#include <asm/fncpy.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/tlb.h> +#include <linux/busfreq-imx.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/genalloc.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/slab.h> + +#include "common.h" +#include "hardware.h" + +static struct device *busfreq_dev; +static int curr_ddr_rate; +static DEFINE_SPINLOCK(freq_lock); + +void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode) = NULL; + +extern unsigned int ddr_normal_rate; +extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode); +extern void imx6_up_lpddr2_freq_change(u32 freq, int bus_freq_mode); +extern void imx6sll_lpddr2_freq_change(u32 freq, int bus_freq_mode); +extern unsigned long save_ttbr1(void); +extern void restore_ttbr1(unsigned long ttbr1); +extern void mx6q_lpddr2_freq_change(u32 freq, void *ddr_settings); +extern unsigned long ddr_freq_change_iram_base; +extern unsigned long imx6_lpddr2_freq_change_start asm("imx6_lpddr2_freq_change_start"); +extern unsigned long imx6_lpddr2_freq_change_end asm("imx6_lpddr2_freq_change_end"); +extern unsigned long mx6q_lpddr2_freq_change_start asm("mx6q_lpddr2_freq_change_start"); +extern unsigned long mx6q_lpddr2_freq_change_end asm("mx6q_lpddr2_freq_change_end"); +extern unsigned long iram_tlb_phys_addr; + +struct mmdc_settings_info { + u32 size; + void *settings; + int freq; +} __aligned(8); +static struct mmdc_settings_info *mmdc_settings_info; +void (*mx6_change_lpddr2_freq_smp)(u32 ddr_freq, struct mmdc_settings_info + *mmdc_settings_info) = NULL; + +static int mmdc_settings_size; +static unsigned long (*mmdc_settings)[2]; +static unsigned long (*iram_mmdc_settings)[2]; +static unsigned long *iram_settings_size; +static unsigned long *iram_ddr_freq_chage; +unsigned long mmdc_timing_settings[][2] = { + {0x0C, 0x0}, /* mmdc_mdcfg0 */ + {0x10, 0x0}, /* mmdc_mdcfg1 */ + {0x14, 0x0}, /* mmdc_mdcfg2 */ + {0x18, 0x0}, /* mmdc_mdmisc */ + {0x38, 0x0}, /* mmdc_mdcfg3lp */ +}; + +#ifdef CONFIG_SMP +volatile u32 *wait_for_lpddr2_freq_update; +static unsigned int online_cpus; +static u32 *irqs_used; +void (*wfe_change_lpddr2_freq)(u32 cpuid, u32 *ddr_freq_change_done); +extern void wfe_smp_freq_change(u32 cpuid, u32 *ddr_freq_change_done); +extern unsigned long wfe_smp_freq_change_start asm("wfe_smp_freq_change_start"); +extern unsigned long wfe_smp_freq_change_end asm("wfe_smp_freq_change_end"); +extern void __iomem *scu_base; +static void __iomem *gic_dist_base; +#endif + +#ifdef CONFIG_SMP +static irqreturn_t wait_in_wfe_irq(int irq, void *dev_id) +{ + u32 me; + + me = smp_processor_id(); +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &me); +#endif + wfe_change_lpddr2_freq(0xff << (me * 8), + (u32 *)ddr_freq_change_iram_base); +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &me); +#endif + return IRQ_HANDLED; +} +#endif + +/* change the DDR frequency. */ +int update_lpddr2_freq(int ddr_rate) +{ + unsigned long ttbr1, flags; + int mode = get_bus_freq_mode(); + + if (ddr_rate == curr_ddr_rate) + return 0; + + printk(KERN_DEBUG "\nBus freq set to %d start...\n", ddr_rate); + + spin_lock_irqsave(&freq_lock, flags); + /* + * Flush the TLB, to ensure no TLB maintenance occurs + * when DDR is in self-refresh. + */ + ttbr1 = save_ttbr1(); + + /* Now change DDR frequency. */ + if (cpu_is_imx6sl()) + mx6_change_lpddr2_freq(ddr_rate, + (mode == BUS_FREQ_LOW || mode == BUS_FREQ_ULTRA_LOW) ? 1 : 0); + else + mx6_change_lpddr2_freq(ddr_rate, + (mode == BUS_FREQ_LOW || mode == BUS_FREQ_AUDIO) ? 1 : 0); + + restore_ttbr1(ttbr1); + + curr_ddr_rate = ddr_rate; + spin_unlock_irqrestore(&freq_lock, flags); + + printk(KERN_DEBUG "\nBus freq set to %d done...\n", ddr_rate); + + return 0; +} + +int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev) +{ + unsigned long ddr_code_size; + busfreq_dev = &busfreq_pdev->dev; + + ddr_code_size = SZ_4K; + + if (cpu_is_imx6sl()) + mx6_change_lpddr2_freq = (void *)fncpy( + (void *)ddr_freq_change_iram_base, + &mx6_lpddr2_freq_change, ddr_code_size); + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz()) + mx6_change_lpddr2_freq = (void *)fncpy( + (void *)ddr_freq_change_iram_base, + &imx6_up_lpddr2_freq_change, ddr_code_size); + if (cpu_is_imx6sll()) + mx6_change_lpddr2_freq = (void *)fncpy( + (void *)ddr_freq_change_iram_base, + &imx6sll_lpddr2_freq_change, ddr_code_size); + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} + +int update_lpddr2_freq_smp(int ddr_rate) +{ + unsigned long ttbr1; + int i, me = 0; +#ifdef CONFIG_SMP + int cpu = 0; + u32 reg = 0; +#endif + + if (ddr_rate == curr_ddr_rate) + return 0; + + printk(KERN_DEBUG "Bus freq set to %d start...\n", ddr_rate); + + for (i=0; i < mmdc_settings_size; i++) { + iram_mmdc_settings[i][0] = mmdc_settings[i][0]; + iram_mmdc_settings[i][1] = mmdc_settings[i][1]; + } + + mmdc_settings_info->size = mmdc_settings_size; + mmdc_settings_info->settings = iram_mmdc_settings; + mmdc_settings_info->freq = curr_ddr_rate; + + /* ensure that all Cores are in WFE. */ + local_irq_disable(); + +#ifdef CONFIG_SMP + me = smp_processor_id(); + + /* Make sure all the online cores are active */ + while (1) { + bool not_exited_busfreq = false; + for_each_online_cpu(cpu) { + reg = __raw_readl(scu_base + 0x08); + if (reg & (0x02 << (cpu * 8))) + not_exited_busfreq = true; + } + if (!not_exited_busfreq) + break; + } + + wmb(); + *wait_for_lpddr2_freq_update = 1; + dsb(); + online_cpus = readl_relaxed(scu_base + 0x08); + for_each_online_cpu(cpu) { + *((char *)(&online_cpus) + (u8)cpu) = 0x02; + if (cpu != me) { + reg = 1 << (irqs_used[cpu] % 32); + writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + + (irqs_used[cpu] / 32) * 4); + } + } + + /* Wait for the other active CPUs to idle */ + while (1) { + reg = 0; + reg = readl_relaxed(scu_base + 0x08); + reg |= (0x02 << (me * 8)); + if (reg == online_cpus) + break; + } +#endif + + /* Ensure iram_tlb_phys_addr is flushed to DDR. */ + __cpuc_flush_dcache_area(&iram_tlb_phys_addr, + sizeof(iram_tlb_phys_addr)); + outer_clean_range(__pa(&iram_tlb_phys_addr), + __pa(&iram_tlb_phys_addr + 1)); + /* + * Flush the TLB, to ensure no TLB maintenance occurs + * when DDR is in self-refresh. + */ + ttbr1 = save_ttbr1(); + + curr_ddr_rate = ddr_rate; + + /* Now change DDR frequency. */ + mx6_change_lpddr2_freq_smp(ddr_rate, mmdc_settings_info); + + restore_ttbr1(ttbr1); + +#ifdef CONFIG_SMP + wmb(); + /* DDR frequency change is done . */ + *wait_for_lpddr2_freq_update = 0; + dsb(); + /* wake up all the cores. */ + sev(); +#endif + + local_irq_enable(); + + printk(KERN_DEBUG "Bus freq set to %d done! cpu=%d\n", ddr_rate, me); + + return 0; +} + +int init_mmdc_lpddr2_settings_mx6q(struct platform_device *busfreq_pdev) +{ + struct device *dev = &busfreq_pdev->dev; + unsigned long ddr_code_size = 0; + unsigned long wfe_code_size = 0; + struct device_node *node; + void __iomem *mmdc_base; + int i; +#ifdef CONFIG_SMP + struct irq_data *d; + u32 cpu; + int err; +#endif + + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc"); + if (!node) { + printk(KERN_ERR "failed to find mmdc device tree data!\n"); + return -EINVAL; + } + + mmdc_base = of_iomap(node, 0); + if (!mmdc_base) { + dev_err(dev, "unable to map mmdc registers\n"); + return -EINVAL; + } + + mmdc_settings_size = ARRAY_SIZE(mmdc_timing_settings); + mmdc_settings = kmalloc((mmdc_settings_size * 8), GFP_KERNEL); + memcpy(mmdc_settings, mmdc_timing_settings, + sizeof(mmdc_timing_settings)); + +#ifdef CONFIG_SMP + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); + if (!node) { + printk(KERN_ERR "failed to find imx6q-a9-gic device tree data!\n"); + return -EINVAL; + } + + gic_dist_base = of_iomap(node, 0); + WARN(!gic_dist_base, "unable to map gic dist registers\n"); + + irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(), + GFP_KERNEL); + + for_each_online_cpu(cpu) { + int irq = platform_get_irq(busfreq_pdev, cpu); + err = request_irq(irq, wait_in_wfe_irq, IRQF_PERCPU, + "mmdc_1", NULL); + if (err) { + dev_err(dev, + "Busfreq:request_irq failed %d, err = %d\n", + irq, err); + return err; + } + err = irq_set_affinity(irq, cpumask_of(cpu)); + if (err) { + dev_err(dev, + "Busfreq: Cannot set irq affinity irq=%d,\n", + irq); + return err; + } + d = irq_get_irq_data(irq); + irqs_used[cpu] = d->hwirq + 32; + } + + /* Stoange_iram_basee the variable used to communicate between cores in + * a non-cacheable IRAM area */ + wait_for_lpddr2_freq_update = (u32 *)ddr_freq_change_iram_base; + wfe_code_size = (&wfe_smp_freq_change_end - &wfe_smp_freq_change_start) *4; + + wfe_change_lpddr2_freq = (void *)fncpy((void *)ddr_freq_change_iram_base + 0x8, + &wfe_smp_freq_change, wfe_code_size); +#endif + iram_settings_size = (void *)ddr_freq_change_iram_base + wfe_code_size + 0x8; + iram_mmdc_settings = (void *)iram_settings_size + sizeof(*mmdc_settings_info); + iram_ddr_freq_chage = (void *)iram_mmdc_settings + (mmdc_settings_size * 8) + 0x8; + mmdc_settings_info = (struct mmdc_settings_info *)iram_settings_size; + + ddr_code_size = (&mx6q_lpddr2_freq_change_end -&mx6q_lpddr2_freq_change_start) *4; + + mx6_change_lpddr2_freq_smp = (void *)fncpy(iram_ddr_freq_chage, + &mx6q_lpddr2_freq_change, ddr_code_size); + + /* save initial mmdc boot timing settings */ + for (i=0; i < mmdc_settings_size; i++) + mmdc_settings[i][1] = readl_relaxed(mmdc_base + + mmdc_settings[i][0]); + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} diff --git a/arch/arm/mach-imx/busfreq_optee.c b/arch/arm/mach-imx/busfreq_optee.c new file mode 100644 index 000000000000..c475402dd153 --- /dev/null +++ b/arch/arm/mach-imx/busfreq_optee.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +/* + * 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 + */ + +/*! + * @file busfreq_optee.c + * + * @brief iMX.6 and i.MX7 Bus Frequency change.\n + * Call OPTEE busfreq function regardless memory type and device. + * + * @ingroup PM + */ +#include <asm/fncpy.h> +#include <linux/busfreq-imx.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <linux/platform_device.h> + +#include "hardware.h" +#include "smc_sip.h" + + +extern unsigned int ddr_normal_rate; +static int curr_ddr_rate; + +#ifdef CONFIG_SMP +/* + * External declaration + */ +extern void imx_smp_wfe_optee(u32 cpuid, u32 status_addr); +extern unsigned long imx_smp_wfe_start asm("imx_smp_wfe_optee"); +extern unsigned long imx_smp_wfe_end asm("imx_smp_wfe_optee_end"); + +extern unsigned long ddr_freq_change_iram_base; + + +/** + * @brief Definition of the synchronization status + * structure used to control to CPUs status + * and on-going frequency change + */ +struct busfreq_sync { + uint32_t change_ongoing; + uint32_t wfe_status[NR_CPUS]; +} __aligned(8); + +static struct busfreq_sync *pSync; + +static void (*wfe_change_freq)(uint32_t *wfe_status, uint32_t *freq_done); + +static uint32_t *irqs_for_wfe; +static void __iomem *gic_dist_base; + +/** + * @brief Switch all active cores, except the one changing the + * bus frequency, in WFE mode until completion of the + * frequency change + * + * @param[in] irq Interrupt ID - not used + * @param[in] dev_id Client data - not used + * + * @retval IRQ_HANDLED Interrupt handled + */ +static irqreturn_t wait_in_wfe_irq(int irq, void *dev_id) +{ + uint32_t me; + + me = smp_processor_id(); +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, + &me); +#endif + + wfe_change_freq(&pSync->wfe_status[me], &pSync->change_ongoing); + +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, + &me); +#endif + + return IRQ_HANDLED; +} +#endif + +/** + * @brief Request OPTEE OS to change the memory bus frequency + * to \a ddr_rate value + * + * @param[in] rate Bus Frequency + * + * @retval 0 Success + */ +int update_freq_optee(int ddr_rate) +{ + struct arm_smccc_res res; + + uint32_t me = 0; + uint32_t dll_off = 0; + int mode = get_bus_freq_mode(); + +#ifdef CONFIG_SMP + uint32_t reg = 0; + uint32_t cpu = 0; + uint32_t online_cpus = 0; + uint32_t all_cpus = 0; +#endif + + pr_info("\nBusfreq OPTEE set from %d to %d start...\n", + curr_ddr_rate, ddr_rate); + + if (ddr_rate == curr_ddr_rate) + return 0; + + if (cpu_is_imx6()) { + if ((mode == BUS_FREQ_LOW) || (mode == BUS_FREQ_AUDIO)) + dll_off = 1; + } + + local_irq_disable(); + +#ifdef CONFIG_SMP + me = smp_processor_id(); + + /* Make sure all the online cores to be active */ + do { + all_cpus = 0; + + for_each_online_cpu(cpu) + all_cpus |= (pSync->wfe_status[cpu] << cpu); + } while (all_cpus); + + pSync->change_ongoing = 1; + dsb(); + + for_each_online_cpu(cpu) { + if (cpu != me) { + online_cpus |= (1 << cpu); + /* Set the interrupt to be pending in the GIC. */ + reg = 1 << (irqs_for_wfe[cpu] % 32); + writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + + (irqs_for_wfe[cpu] / 32) * 4); + } + } + + /* Wait for all active CPUs to be in WFE */ + do { + all_cpus = 0; + + for_each_online_cpu(cpu) + all_cpus |= (pSync->wfe_status[cpu] << cpu); + } while (all_cpus != online_cpus); + +#endif + + /* Now we can change the DDR frequency. */ + /* Call the TEE SiP */ + arm_smccc_smc(OPTEE_SMC_FAST_CALL_SIP_VAL(IMX_SIP_BUSFREQ_CHANGE), + ddr_rate, dll_off, 0, 0, 0, 0, 0, &res); + + curr_ddr_rate = ddr_rate; + +#ifdef CONFIG_SMP + /* DDR frequency change is done */ + pSync->change_ongoing = 0; + dsb(); + + /* wake up all the cores. */ + sev(); +#endif + + local_irq_enable(); + + pr_info("Busfreq OPTEE set to %d done! cpu=%d\n", + ddr_rate, me); + + return 0; +} + +#ifdef CONFIG_SMP +static int init_freq_optee_smp(struct platform_device *busfreq_pdev) +{ + struct device_node *node = 0; + struct device *dev = &busfreq_pdev->dev; + uint32_t cpu; + int err; + int irq; + struct irq_data *irq_data; + unsigned long wfe_iram_base; + + if (cpu_is_imx6()) { + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); + if (!node) { + if (cpu_is_imx6q()) + pr_debug("failed to find imx6q-a9-gic device tree data!\n"); + + return -EINVAL; + } + } else { + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a7-gic"); + if (!node) { + pr_debug("failed to find imx7d-a7-gic device tree data!\n"); + return -EINVAL; + } + } + + gic_dist_base = of_iomap(node, 0); + WARN(!gic_dist_base, "unable to map gic dist registers\n"); + + irqs_for_wfe = devm_kzalloc(dev, sizeof(uint32_t) * num_present_cpus(), + GFP_KERNEL); + + for_each_online_cpu(cpu) { + /* + * set up a reserved interrupt to get all + * the active cores into a WFE state + * before changing the DDR frequency. + */ + irq = platform_get_irq(busfreq_pdev, cpu); + + if (cpu_is_imx6()) { + err = request_irq(irq, wait_in_wfe_irq, + IRQF_PERCPU, "mmdc_1", NULL); + } else { + err = request_irq(irq, wait_in_wfe_irq, + IRQF_PERCPU, "ddrc", NULL); + } + + if (err) { + dev_err(dev, + "Busfreq:request_irq failed %d, err = %d\n", + irq, err); + return err; + } + + err = irq_set_affinity(irq, cpumask_of(cpu)); + if (err) { + dev_err(dev, + "Busfreq: Cannot set irq affinity irq=%d,\n", + irq); + return err; + } + + irq_data = irq_get_irq_data(irq); + irqs_for_wfe[cpu] = irq_data->hwirq + 32; + } + + /* Store the variable used to communicate between cores */ + pSync = (void *)ddr_freq_change_iram_base; + + memset(pSync, 0, sizeof(*pSync)); + + wfe_iram_base = ddr_freq_change_iram_base + sizeof(*pSync); + + if (wfe_iram_base & (FNCPY_ALIGN - 1)) + wfe_iram_base += FNCPY_ALIGN - + ((uintptr_t)wfe_iram_base % (FNCPY_ALIGN)); + + wfe_change_freq = (void *)fncpy((void *)wfe_iram_base, + &imx_smp_wfe_optee, + ((&imx_smp_wfe_end -&imx_smp_wfe_start) *4)); + + return 0; + +} + +int init_freq_optee(struct platform_device *busfreq_pdev) +{ + int err = -EINVAL; + struct device *dev = &busfreq_pdev->dev; + + if (num_present_cpus() <= 1) { + wfe_change_freq = NULL; + + /* Allocate the cores synchronization variables (not used) */ + pSync = devm_kzalloc(dev, sizeof(*pSync), GFP_KERNEL); + + if (pSync) + err = 0; + } else { + err = init_freq_optee_smp(busfreq_pdev); + } + + if (err == 0) + curr_ddr_rate = ddr_normal_rate; + + return err; +} +#else +int init_freq_optee(struct platform_device *busfreq_pdev) +{ + curr_ddr_rate = ddr_normal_rate; + return 0; +} +#endif + diff --git a/arch/arm/mach-imx/common.c b/arch/arm/mach-imx/common.c new file mode 100644 index 000000000000..2f644c6b2c28 --- /dev/null +++ b/arch/arm/mach-imx/common.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * 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/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_net.h> +#include <linux/slab.h> + +#include "hardware.h" + +unsigned long iram_tlb_base_addr; +unsigned long iram_tlb_phys_addr; + +unsigned long save_ttbr1(void) +{ + unsigned long lttbr1; + asm volatile( + ".align 4\n" + "mrc p15, 0, %0, c2, c0, 1\n" + : "=r" (lttbr1) + ); + return lttbr1; +} + +void restore_ttbr1(unsigned long ttbr1) +{ + asm volatile( + ".align 4\n" + "mcr p15, 0, %0, c2, c0, 1\n" + : : "r" (ttbr1) + ); +} + +#define OCOTP_MAC_OFF (cpu_is_imx7d() ? 0x640 : 0x620) +#define OCOTP_MACn(n) (OCOTP_MAC_OFF + (n) * 0x10) +void __init imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat) +{ + struct device_node *ocotp_np, *enet_np, *from = NULL; + void __iomem *base; + struct property *newmac; + u32 macaddr_low; + u32 macaddr_high = 0; + u32 macaddr1_high = 0; + u8 *macaddr; + int i, id; + + for (i = 0; i < 2; i++) { + enet_np = of_find_compatible_node(from, NULL, enet_compat); + if (!enet_np) + return; + + from = enet_np; + + if (of_get_mac_address(enet_np)) + goto put_enet_node; + + id = of_alias_get_id(enet_np, "ethernet"); + if (id < 0) + id = i; + + ocotp_np = of_find_compatible_node(NULL, NULL, ocotp_compat); + if (!ocotp_np) { + pr_warn("failed to find ocotp node\n"); + goto put_enet_node; + } + + base = of_iomap(ocotp_np, 0); + if (!base) { + pr_warn("failed to map ocotp\n"); + goto put_ocotp_node; + } + + macaddr_low = readl_relaxed(base + OCOTP_MACn(1)); + if (id) + macaddr1_high = readl_relaxed(base + OCOTP_MACn(2)); + else + macaddr_high = readl_relaxed(base + OCOTP_MACn(0)); + + newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); + if (!newmac) + goto put_ocotp_node; + + newmac->value = newmac + 1; + newmac->length = 6; + newmac->name = kstrdup("local-mac-address", GFP_KERNEL); + if (!newmac->name) { + kfree(newmac); + goto put_ocotp_node; + } + + macaddr = newmac->value; + if (id) { + macaddr[5] = (macaddr_low >> 16) & 0xff; + macaddr[4] = (macaddr_low >> 24) & 0xff; + macaddr[3] = macaddr1_high & 0xff; + macaddr[2] = (macaddr1_high >> 8) & 0xff; + macaddr[1] = (macaddr1_high >> 16) & 0xff; + macaddr[0] = (macaddr1_high >> 24) & 0xff; + } else { + macaddr[5] = macaddr_high & 0xff; + macaddr[4] = (macaddr_high >> 8) & 0xff; + macaddr[3] = (macaddr_high >> 16) & 0xff; + macaddr[2] = (macaddr_high >> 24) & 0xff; + macaddr[1] = macaddr_low & 0xff; + macaddr[0] = (macaddr_low >> 8) & 0xff; + } + + of_update_property(enet_np, newmac); + +put_ocotp_node: + of_node_put(ocotp_np); +put_enet_node: + of_node_put(enet_np); + } +} + +#ifndef CONFIG_HAVE_IMX_GPC +int imx_gpc_mf_request_on(unsigned int irq, unsigned int on) { return 0; } +EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on); +#endif + +#if !defined(CONFIG_SOC_IMX6SL) +u32 imx6_lpddr2_freq_change_start, imx6_lpddr2_freq_change_end; +void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode) {} +#endif + +#if !defined(CONFIG_SOC_IMX6SLL) +void imx6sll_lpddr2_freq_change(u32 freq, int bus_freq_mode) {} +#endif + +#if !defined(CONFIG_SOC_IMX6SX) && !defined(CONFIG_SOC_IMX6UL) +u32 imx6_up_ddr3_freq_change_start, imx6_up_ddr3_freq_change_end; +struct imx6_busfreq_info { +} __aligned(8); +void imx6_up_ddr3_freq_change(struct imx6_busfreq_info *busfreq_info) {} +void imx6_up_lpddr2_freq_change(u32 freq, int bus_freq_mode) {} +#endif + +#if !defined(CONFIG_SOC_IMX6Q) +u32 mx6_ddr3_freq_change_start, mx6_ddr3_freq_change_end; +u32 mx6q_lpddr2_freq_change_start, mx6q_lpddr2_freq_change_end; +u32 wfe_smp_freq_change_start, wfe_smp_freq_change_end; +void mx6_ddr3_freq_change(u32 freq, void *ddr_settings, + bool dll_mode, void *iomux_offsets) {} +void mx6q_lpddr2_freq_change(u32 freq, void *ddr_settings) {} +void wfe_smp_freq_change(u32 cpuid, u32 *ddr_freq_change_done) {} +#endif + +#if !defined(CONFIG_SOC_IMX7D) +void imx7_smp_wfe(u32 cpuid, u32 ocram_base) {} +void imx7d_ddr3_freq_change(u32 freq) {} +#endif + diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 5aa5796cff0e..f3c9175c4e8a 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -8,6 +8,7 @@ #define __ASM_ARCH_MXC_COMMON_H__ #include <linux/reboot.h> +#include <soc/imx/src.h> struct irq_data; struct platform_device; @@ -56,9 +57,19 @@ void imx_gpc_set_arm_power_in_lpm(bool power_off); void imx_gpc_set_l2_mem_power_in_lpm(bool power_off); void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw); void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw); +void imx_gpcv2_pre_suspend(bool arm_power_off); +void imx_gpcv2_post_resume(void); +unsigned int imx_gpcv2_is_mf_mix_off(void); +void imx_gpcv2_enable_wakeup_for_m4(void); +void imx_gpcv2_disable_wakeup_for_m4(void); void imx25_pm_init(void); void imx27_pm_init(void); void imx5_pmu_init(void); +#ifdef CONFIG_HAVE_IMX_MU +int imx_mu_lpm_ready(bool ready); +#else +static inline int imx_mu_lpm_ready(bool ready) { return 0; } +#endif enum mxc_cpu_pwr_mode { WAIT_CLOCKED, /* wfi only */ @@ -89,33 +100,95 @@ void imx_smp_prepare(void); static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} #endif +void imx6sx_set_m4_highfreq(bool high_freq); +void imx_mu_enable_m4_irqs_in_gic(bool enable); +#ifdef CONFIG_HAVE_IMX_GPC +void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable); +unsigned int imx_gpc_is_m4_sleeping(void); +#else +static inline void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable) {} +static inline unsigned int imx_gpc_is_m4_sleeping(void) { return 0; } +#endif +#ifdef CONFIG_HAVE_IMX_GPCV2 +int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on); +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn); +void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable); +#else +static inline int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on) { return 0; } +static inline void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) {} +static inline void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable) {} +#endif +void imx_gpc_hold_m4_in_sleep(void); +void imx_gpc_release_m4_in_sleep(void); +void __init imx_gpcv2_check_dt(void); +void imx_gpcv2_set_lpm_mode(enum mxc_cpu_pwr_mode mode); +void imx_gpcv2_set_cpu_power_gate_in_idle(bool pdn); +void imx_gpcv2_enable_rbc(bool enable); +bool imx_mu_is_m4_in_low_freq(void); +bool imx_mu_is_m4_in_stop(void); +void imx_mu_set_m4_run_mode(void); void imx_src_init(void); void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); +void imx_gpc_switch_pupscr_clk(bool flag); void imx_gpc_mask_all(void); void imx_gpc_restore_all(void); void imx_gpc_hwirq_mask(unsigned int hwirq); void imx_gpc_hwirq_unmask(unsigned int hwirq); +unsigned int imx_gpc_is_mf_mix_off(void); void imx_anatop_init(void); void imx_anatop_pre_suspend(void); void imx_anatop_post_resume(void); int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); +void imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat); +void imx6sl_low_power_idle(void); +void imx6sll_low_power_idle(void); +void imx6sx_low_power_idle(void); +void imx6ul_low_power_idle(void); +void imx6ull_low_power_idle(void); +void imx7d_low_power_idle(void); +#ifdef CONFIG_HAVE_IMX_MMDC int imx_mmdc_get_ddr_type(void); +int imx_mmdc_get_lpddr2_2ch_mode(void); +#else +static inline int imx_mmdc_get_ddr_type(void) { return 0; } +static inline int imx_mmdc_get_lpddr2_2ch_mode(void) { return 0; } +#endif int imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode); +void imx_busfreq_map_io(void); +void imx7_pm_map_io(void); +void imx6_pm_map_io(void); +void imx7ulp_pm_map_io(void); +void imx7ulp_enable_nmi(void); +void imx7ulp_poweroff(void); void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); #ifdef CONFIG_SUSPEND +void ca7_cpu_resume(void); void imx53_suspend(void __iomem *ocram_vbase); extern const u32 imx53_suspend_sz; void imx6_suspend(void __iomem *ocram_vbase); +void imx7_suspend(void __iomem *ocram_vbase); +void imx7ulp_cpu_resume(void); +void imx7ulp_suspend(void __iomem *ocram_vbase); #else +static inline void ca7_cpu_resume(void) {} static inline void imx53_suspend(void __iomem *ocram_vbase) {} static const u32 imx53_suspend_sz; static inline void imx6_suspend(void __iomem *ocram_vbase) {} +static inline void imx7_suspend(void __iomem *ocram_vbase) {} +static inline void imx7ulp_cpu_resume(void) {} +static inline void imx7ulp_suspend(void __iomem *ocram_vbase) {} +#endif + +#ifdef CONFIG_HAVE_IMX_DDRC +int imx_ddrc_get_ddr_type(void); +#else +static inline int imx_ddrc_get_ddr_type(void) { return 0; } #endif void v7_cpu_resume(void); @@ -126,6 +199,7 @@ void imx6dl_pm_init(void); void imx6sl_pm_init(void); void imx6sx_pm_init(void); void imx6ul_pm_init(void); +void imx7d_pm_init(void); void imx7ulp_pm_init(void); #ifdef CONFIG_PM @@ -151,4 +225,5 @@ static inline void imx_init_l2cache(void) {} extern const struct smp_operations imx_smp_ops; extern const struct smp_operations ls1021a_smp_ops; +extern bool uart_from_osc; #endif diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index 0b137eeffb61..87199853f1eb 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c @@ -128,7 +128,10 @@ struct device * __init imx_soc_device_init(void) soc_id = "i.MX6SX"; break; case MXC_CPU_IMX6Q: - soc_id = "i.MX6Q"; + if (imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) + soc_id = "i.MX6QP"; + else + soc_id = "i.MX6Q"; break; case MXC_CPU_IMX6UL: soc_id = "i.MX6UL"; diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c index 4521e5352bf6..e54acc2ac8a1 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sl.c +++ b/arch/arm/mach-imx/cpuidle-imx6sl.c @@ -1,26 +1,104 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2014 Freescale Semiconductor, Inc. + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP. */ +#include <linux/busfreq-imx.h> #include <linux/cpuidle.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/platform_device.h> +#include <linux/psci.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> #include <asm/cpuidle.h> +#include <asm/fncpy.h> +#include <asm/proc-fns.h> + +#include <uapi/linux/psci.h> #include "common.h" #include "cpuidle.h" +#include "hardware.h" + +#define MAX_MMDC_IO_NUM 19 + +static void __iomem *wfi_iram_base; +extern unsigned long iram_tlb_base_addr; + +#ifdef CONFIG_CPU_FREQ +extern unsigned long mx6sl_lpm_wfi_start asm("mx6sl_lpm_wfi_start"); +extern unsigned long mx6sl_lpm_wfi_end asm("mx6sl_lpm_wfi_end"); +#endif + +struct imx6_cpuidle_pm_info { + u32 pm_info_size; /* Size of pm_info */ + u32 ttbr; + void __iomem *mmdc_base; + void __iomem *iomuxc_base; + void __iomem *ccm_base; + void __iomem *l2_base; + void __iomem *anatop_base; + u32 mmdc_io_num; /*Number of MMDC IOs which need saved/restored. */ + u32 mmdc_io_val[MAX_MMDC_IO_NUM][2]; /* To save offset and value */ +} __aligned(8); + +static const u32 imx6sl_mmdc_io_offset[] __initconst = { + 0x30c, 0x310, 0x314, 0x318, /* DQM0 ~ DQM3 */ + 0x5c4, 0x5cc, 0x5d4, 0x5d8, /* GPR_B0DS ~ GPR_B3DS */ + 0x300, 0x31c, 0x338, 0x5ac, /*CAS, RAS, SDCLK_0, GPR_ADDS */ + 0x33c, 0x340, 0x5b0, 0x5c0, /*SODT0, SODT1, ,MODE_CTL, MODE */ + 0x330, 0x334, 0x320, /*SDCKE0, SDCK1, RESET */ +}; + +static struct regulator *vbus_ldo; +static struct regulator_dev *ldo2p5_dummy_regulator_rdev; +static struct regulator_init_data ldo2p5_dummy_initdata = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; +static int ldo2p5_dummy_enable; + +static void (*imx6sl_wfi_in_iram_fn)(void __iomem *iram_vbase, + int audio_mode, bool vbus_ldo); + +#define MX6SL_POWERDWN_IDLE_PARAM \ + ((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) static int imx6sl_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { + int mode = get_bus_freq_mode(); + imx6_set_lpm(WAIT_UNCLOCKED); - /* - * Software workaround for ERR005311, see function - * description for details. - */ - imx6sl_set_wait_clk(true); - cpu_do_idle(); - imx6sl_set_wait_clk(false); + + if ((mode == BUS_FREQ_AUDIO) || (mode == BUS_FREQ_ULTRA_LOW)) { + /* + * bit 2 used for low power mode; + * bit 1 used for the ldo2p5_dummmy enable + */ + if (psci_ops.cpu_suspend) { + psci_ops.cpu_suspend((MX6SL_POWERDWN_IDLE_PARAM | ((mode == BUS_FREQ_AUDIO ? 1 : 0) << 2) | + (ldo2p5_dummy_enable ? 1 : 0) << 1), __pa(cpu_resume)); + } else { + imx6sl_wfi_in_iram_fn(wfi_iram_base, (mode == BUS_FREQ_AUDIO) ? 1 : 0, + ldo2p5_dummy_enable); + } + } else { + /* + * Software workaround for ERR005311, see function + * description for details. + */ + imx6sl_set_wait_clk(true); + cpu_do_idle(); + imx6sl_set_wait_clk(false); + } imx6_set_lpm(WAIT_CLOCKED); return index; @@ -48,5 +126,109 @@ static struct cpuidle_driver imx6sl_cpuidle_driver = { int __init imx6sl_cpuidle_init(void) { + +#ifdef CONFIG_CPU_FREQ + struct imx6_cpuidle_pm_info *pm_info; + int i; + const u32 *mmdc_offset_array; + u32 wfi_code_size; + + vbus_ldo = regulator_get(NULL, "ldo2p5-dummy"); + if (IS_ERR(vbus_ldo)) + vbus_ldo = NULL; + + wfi_iram_base = (void *)(iram_tlb_base_addr + MX6_CPUIDLE_IRAM_ADDR_OFFSET); + + /* Make sure wif_iram_base is 8 byte aligned. */ + if ((uintptr_t)(wfi_iram_base) & (FNCPY_ALIGN - 1)) + wfi_iram_base += FNCPY_ALIGN - ((uintptr_t)wfi_iram_base % (FNCPY_ALIGN)); + + pm_info = wfi_iram_base; + pm_info->pm_info_size = sizeof(*pm_info); + pm_info->mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset); + mmdc_offset_array = imx6sl_mmdc_io_offset; + pm_info->mmdc_base = (void __iomem *)IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); + pm_info->ccm_base = (void __iomem *)IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); + pm_info->anatop_base = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + pm_info->iomuxc_base = (void __iomem *)IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); + pm_info->l2_base = (void __iomem *)IMX_IO_P2V(MX6Q_L2_BASE_ADDR); + + /* Only save mmdc io offset, settings will be saved in asm code */ + for (i = 0; i < pm_info->mmdc_io_num; i++) + pm_info->mmdc_io_val[i][0] = mmdc_offset_array[i]; + + /* calculate the wfi code size */ + wfi_code_size = (&mx6sl_lpm_wfi_end -&mx6sl_lpm_wfi_start) *4; + + imx6sl_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*pm_info), + &imx6sl_low_power_idle, wfi_code_size); +#endif + return cpuidle_register(&imx6sl_cpuidle_driver, NULL); } + +static int imx_ldo2p5_dummy_enable(struct regulator_dev *rdev) +{ + ldo2p5_dummy_enable = 1; + return 0; +} + +static int imx_ldo2p5_dummy_disable(struct regulator_dev *rdev) +{ + ldo2p5_dummy_enable = 0; + return 0; +} + +static int imx_ldo2p5_dummy_is_enable(struct regulator_dev *rdev) +{ + return ldo2p5_dummy_enable; +} + +static struct regulator_ops ldo2p5_dummy_ops = { + .enable = imx_ldo2p5_dummy_enable, + .disable = imx_ldo2p5_dummy_disable, + .is_enabled = imx_ldo2p5_dummy_is_enable, +}; + +static struct regulator_desc ldo2p5_dummy_desc = { + .name = "ldo2p5-dummy", + .id = -1, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &ldo2p5_dummy_ops, +}; + +static int ldo2p5_dummy_probe(struct platform_device *pdev) +{ + struct regulator_config config = { }; + int ret; + + config.dev = &pdev->dev; + config.init_data = &ldo2p5_dummy_initdata; + config.of_node = pdev->dev.of_node; + + ldo2p5_dummy_regulator_rdev = regulator_register(&ldo2p5_dummy_desc, &config); + if (IS_ERR(ldo2p5_dummy_regulator_rdev)) { + ret = PTR_ERR(ldo2p5_dummy_regulator_rdev); + dev_err(&pdev->dev, "Failed to register dummy ldo2p5 regulator: %d\n", ret); + return ret; + } + return 0; +} + +static const struct of_device_id imx_ldo2p5_dummy_ids[] = { + { .compatible = "fsl,imx6-dummy-ldo2p5", }, + { }, +}; +MODULE_DEVICE_TABLE(ofm, imx_ldo2p5_dummy_ids); + +static struct platform_driver ldo2p5_dummy_driver = { + .probe = ldo2p5_dummy_probe, + .driver = { + .name = "ldo2p5-dummy", + .owner = THIS_MODULE, + .of_match_table = imx_ldo2p5_dummy_ids, + }, +}; + +module_platform_driver(ldo2p5_dummy_driver); diff --git a/arch/arm/mach-imx/cpuidle-imx6sll.c b/arch/arm/mach-imx/cpuidle-imx6sll.c new file mode 100644 index 000000000000..bb8678ff56f0 --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx6sll.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/busfreq-imx.h> +#include <linux/cpuidle.h> +#include <linux/cpu_pm.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/psci.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <asm/cpuidle.h> +#include <asm/fncpy.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> + +#include <uapi/linux/psci.h> + +#include "common.h" +#include "cpuidle.h" +#include "hardware.h" + +#define MAX_MMDC_IO_NUM 14 + +#define PMU_LOW_PWR_CTRL 0x270 +#define XTALOSC24M_OSC_CONFIG0 0x2a0 +#define XTALOSC24M_OSC_CONFIG1 0x2b0 +#define XTALOSC24M_OSC_CONFIG2 0x2c0 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT 24 +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT 16 +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT 12 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT 4 +#define XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT 1 +#define XTALOSC24M_OSC_CONFIG0_START_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT 20 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK 0xfff +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT 0 + +extern unsigned long iram_tlb_phys_addr; +static void __iomem *wfi_iram_base; + +#ifdef CONFIG_CPU_FREQ +static void __iomem *wfi_iram_base_phys; +extern unsigned long mx6sll_lpm_wfi_start asm("mx6sll_lpm_wfi_start"); +extern unsigned long mx6sll_lpm_wfi_end asm("mx6sll_lpm_wfi_end"); +#endif + +struct imx6_pm_base { + phys_addr_t pbase; + void __iomem *vbase; +}; + +struct imx6_cpuidle_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 pm_info_size; /* Size of pm_info. */ + u32 ttbr; + struct imx6_pm_base mmdc_base; + struct imx6_pm_base iomuxc_base; + struct imx6_pm_base ccm_base; + struct imx6_pm_base gpc_base; + struct imx6_pm_base anatop_base; + struct imx6_pm_base src_base; + struct imx6_pm_base l2_base; + u32 saved_diagnostic; /* To save disagnostic register */ + u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ + u32 mmdc_io_val[MAX_MMDC_IO_NUM][2]; /* To save offset and value */ +} __aligned(8); + +static const u32 imx6sll_mmdc_io_offset[] __initconst = { + 0x294, 0x298, 0x29c, 0x2a0, /* DQM0, DQM1, RAS, CAS */ + 0x544, 0x54c, 0x554, 0x558, /* GPR_B0DS ~ GPR_B3DS */ + 0x530, 0x540, 0x2ac, 0x52c, /* MODE_CTL, MODE, SDCLK0, GPR_ADDS */ + 0x2a4, 0x2a8, /* SDCKE0, SDCKE1 */ +}; + +static void (*imx6sll_wfi_in_iram_fn)(void __iomem *iram_vbase); + +#define MX6SLL_POWERDWN_IDLE_PARAM \ + ((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +static int imx6sll_idle_finish(unsigned long val) +{ + if (psci_ops.cpu_suspend) + psci_ops.cpu_suspend(MX6SLL_POWERDWN_IDLE_PARAM, + __pa(cpu_resume)); + else + imx6sll_wfi_in_iram_fn(wfi_iram_base); + + return 0; +} + +static int imx6sll_enter_wait(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + int mode = get_bus_freq_mode(); + + imx6_set_lpm(WAIT_UNCLOCKED); + if ((index == 1) || ((mode != BUS_FREQ_LOW) && index == 2)) { + index = 1; + cpu_do_idle(); + } else { + imx_gpc_switch_pupscr_clk(true); + /* Need to notify there is a cpu pm operation. */ + cpu_pm_enter(); + cpu_cluster_pm_enter(); + + cpu_suspend(0, imx6sll_idle_finish); + + cpu_cluster_pm_exit(); + cpu_pm_exit(); + imx6_enable_rbc(false); + + imx_gpc_switch_pupscr_clk(false); + } + + imx6_set_lpm(WAIT_CLOCKED); + + return index; +} + +static struct cpuidle_driver imx6sll_cpuidle_driver = { + .name = "imx6sll_cpuidle", + .owner = THIS_MODULE, + .states = { + /* WFI */ + ARM_CPUIDLE_WFI_STATE, + /* WAIT */ + { + .exit_latency = 50, + .target_residency = 75, + .enter = imx6sll_enter_wait, + .name = "WAIT", + .desc = "Clock off", + }, + /* LOW POWER IDLE */ + { + /* + * RBC 130us + ARM gating 43us + RBC clear 65us + * + PLL2 relock 450us and some margin, here set + * it to 700us. + */ + .exit_latency = 700, + .target_residency = 1000, + .enter = imx6sll_enter_wait, + .name = "LOW-POWER-IDLE", + .desc = "ARM power off", + } + }, + .state_count = 3, + .safe_state_index = 0, +}; + +int __init imx6sll_cpuidle_init(void) +{ + void __iomem *anatop_base = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + u32 val; +#ifdef CONFIG_CPU_FREQ + struct imx6_cpuidle_pm_info *cpuidle_pm_info; + int i; + const u32 *mmdc_offset_array; + u32 wfi_code_size; + + wfi_iram_base_phys = (void *)(iram_tlb_phys_addr + MX6_CPUIDLE_IRAM_ADDR_OFFSET); + + /* Make sure wfi_iram_base is 8 byte aligned. */ + if ((uintptr_t)(wfi_iram_base_phys) & (FNCPY_ALIGN - 1)) + wfi_iram_base_phys += FNCPY_ALIGN - ((uintptr_t)wfi_iram_base_phys % (FNCPY_ALIGN)); + + wfi_iram_base = (void *)IMX_IO_P2V((unsigned long) wfi_iram_base_phys); + + cpuidle_pm_info = wfi_iram_base; + cpuidle_pm_info->pbase = (phys_addr_t) wfi_iram_base_phys; + cpuidle_pm_info->pm_info_size = sizeof(*cpuidle_pm_info); + cpuidle_pm_info->resume_addr = virt_to_phys(v7_cpu_resume); + cpuidle_pm_info->mmdc_io_num = ARRAY_SIZE(imx6sll_mmdc_io_offset); + mmdc_offset_array = imx6sll_mmdc_io_offset; + + cpuidle_pm_info->mmdc_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; + cpuidle_pm_info->mmdc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); + + cpuidle_pm_info->ccm_base.pbase = MX6Q_CCM_BASE_ADDR; + cpuidle_pm_info->ccm_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); + + cpuidle_pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; + cpuidle_pm_info->anatop_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + + cpuidle_pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; + cpuidle_pm_info->gpc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); + + cpuidle_pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; + cpuidle_pm_info->iomuxc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); + + cpuidle_pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; + cpuidle_pm_info->src_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); + + cpuidle_pm_info->l2_base.pbase = MX6Q_L2_BASE_ADDR; + cpuidle_pm_info->l2_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_L2_BASE_ADDR); + + /* Only save mmdc io offset, settings will be saved in asm code */ + for (i = 0; i < cpuidle_pm_info->mmdc_io_num; i++) + cpuidle_pm_info->mmdc_io_val[i][0] = mmdc_offset_array[i]; + + wfi_code_size = (&mx6sll_lpm_wfi_end -&mx6sll_lpm_wfi_start) *4; + + imx6sll_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*cpuidle_pm_info), + &imx6sll_low_power_idle, wfi_code_size); +#endif + + imx6_set_int_mem_clk_lpm(true); + + /* + * enable RC-OSC here, as it needs at least 4ms for RC-OSC to + * be stable, low power idle flow can NOT endure this big + * latency, so we make RC-OSC self-tuning enabled here. + */ + val = readl_relaxed(anatop_base + PMU_LOW_PWR_CTRL); + val |= 0x1; + writel_relaxed(val, anatop_base + PMU_LOW_PWR_CTRL); + /* + * config RC-OSC freq + * tune_enable = 1;tune_start = 1;hyst_plus = 0;hyst_minus = 0; + * osc_prog = 0xa7; + */ + writel_relaxed( + 0x4 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT | + 0xa7 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_START_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set count_trg = 0x2dc */ + writel_relaxed( + 0x40 << XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT | + 0x2dc << XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG1); + /* wait 4ms according to hardware design */ + msleep(4); + /* + * now add some hysteresis, hyst_plus=3, hyst_minus=3 + * (the minimum hysteresis that looks good is 2) + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG0); + val &= ~((XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT)); + val |= (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT); + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set the count_1m_trg = 0x2d7 */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG2); + val &= ~(XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK << + XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT); + val |= 0x2d7 << XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT; + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG2); + /* + * hardware design require to write XTALOSC24M_OSC_CONFIG0 or + * XTALOSC24M_OSC_CONFIG1 to + * make XTALOSC24M_OSC_CONFIG2 write work + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG1); + + return cpuidle_register(&imx6sll_cpuidle_driver, NULL); +} diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c index 74ea1720e3d8..692775a223a2 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sx.c +++ b/arch/arm/mach-imx/cpuidle-imx6sx.c @@ -1,20 +1,97 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2014 Freescale Semiconductor, Inc. + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. */ +#include <linux/busfreq-imx.h> #include <linux/cpuidle.h> #include <linux/cpu_pm.h> +#include <linux/delay.h> +#include <linux/genalloc.h> +#include <linux/interrupt.h> #include <linux/module.h> +#include <linux/psci.h> #include <asm/cacheflush.h> #include <asm/cpuidle.h> +#include <asm/fncpy.h> +#include <asm/mach/map.h> +#include <asm/proc-fns.h> #include <asm/suspend.h> +#include <asm/tlb.h> + +#include <uapi/linux/psci.h> #include "common.h" #include "cpuidle.h" #include "hardware.h" -static int imx6sx_idle_finish(unsigned long val) +#define MX6_MAX_MMDC_IO_NUM 19 + +#define PMU_LOW_PWR_CTRL 0x270 +#define XTALOSC24M_OSC_CONFIG0 0x2a0 +#define XTALOSC24M_OSC_CONFIG1 0x2b0 +#define XTALOSC24M_OSC_CONFIG2 0x2c0 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT 24 +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT 16 +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT 12 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT 4 +#define XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT 1 +#define XTALOSC24M_OSC_CONFIG0_START_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT 20 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK 0xfff +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT 0 + +extern unsigned long iram_tlb_phys_addr; + +static void __iomem *wfi_iram_base; +#ifdef CONFIG_CPU_FREQ +static void __iomem *wfi_iram_base_phys; +extern unsigned long mx6sx_lpm_wfi_start asm("mx6sx_lpm_wfi_start"); +extern unsigned long mx6sx_lpm_wfi_end asm("mx6sx_lpm_wfi_end"); +#endif + +struct imx6_pm_base { + phys_addr_t pbase; + void __iomem *vbase; +}; + +static const u32 imx6sx_mmdc_io_offset[] __initconst = { + 0x2ec, 0x2f0, 0x2f4, 0x2f8, /* DQM0 ~ DQM3 */ + 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ + 0x60c, 0x610, 0x61c, 0x620, /* B0DS ~ B3DS */ + 0x5f8, 0x608, 0x310, 0x314, /* CTL, MODE, SODT0, SODT1 */ + 0x300, 0x2fc, 0x32c, /* CAS, RAS, SDCLK_0 */ +}; + +struct imx6_cpuidle_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 pm_info_size; /* Size of pm_info. */ + u32 ttbr; + struct imx6_pm_base mmdc_base; + struct imx6_pm_base iomuxc_base; + struct imx6_pm_base ccm_base; + struct imx6_pm_base gpc_base; + struct imx6_pm_base l2_base; + struct imx6_pm_base anatop_base; + struct imx6_pm_base src_base; + struct imx6_pm_base sema4_base; + u32 saved_diagnostic; /* To save disagnostic register */ + u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ + u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ +} __aligned(8); + +static void (*imx6sx_wfi_in_iram_fn)(void __iomem *iram_vbase); + +#define MX6SX_POWERDWN_IDLE_PARAM \ + ((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +static int imx6_idle_finish(unsigned long val) { /* * for Cortex-A7 which has an internal L2 @@ -25,7 +102,11 @@ static int imx6sx_idle_finish(unsigned long val) * just call flush_cache_all() is fine. */ flush_cache_all(); - cpu_do_idle(); + if (psci_ops.cpu_suspend) + psci_ops.cpu_suspend(MX6SX_POWERDWN_IDLE_PARAM, + __pa(cpu_resume)); + else + imx6sx_wfi_in_iram_fn(wfi_iram_base); return 0; } @@ -33,29 +114,22 @@ static int imx6sx_idle_finish(unsigned long val) static int imx6sx_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - imx6_set_lpm(WAIT_UNCLOCKED); + int mode = get_bus_freq_mode(); - switch (index) { - case 1: + imx6_set_lpm(WAIT_UNCLOCKED); + if ((index == 1) || ((mode != BUS_FREQ_LOW) && index == 2)) { + index = 1; cpu_do_idle(); - break; - case 2: - imx6_enable_rbc(true); - imx_gpc_set_arm_power_in_lpm(true); - imx_set_cpu_jump(0, v7_cpu_resume); - /* Need to notify there is a cpu pm operation. */ - cpu_pm_enter(); - cpu_cluster_pm_enter(); - - cpu_suspend(0, imx6sx_idle_finish); - - cpu_cluster_pm_exit(); - cpu_pm_exit(); - imx_gpc_set_arm_power_in_lpm(false); - imx6_enable_rbc(false); - break; - default: - break; + } else { + /* Need to notify there is a cpu pm operation. */ + cpu_pm_enter(); + cpu_cluster_pm_enter(); + + cpu_suspend(0, imx6_idle_finish); + + cpu_cluster_pm_exit(); + cpu_pm_exit(); + imx6_enable_rbc(false); } imx6_set_lpm(WAIT_CLOCKED); @@ -69,25 +143,23 @@ static struct cpuidle_driver imx6sx_cpuidle_driver = { .states = { /* WFI */ ARM_CPUIDLE_WFI_STATE, - /* WAIT */ + /* WAIT MODE */ { .exit_latency = 50, .target_residency = 75, - .flags = CPUIDLE_FLAG_TIMER_STOP, .enter = imx6sx_enter_wait, .name = "WAIT", .desc = "Clock off", }, - /* WAIT + ARM power off */ + /* LOW POWER IDLE */ { /* - * ARM gating 31us * 5 + RBC clear 65us - * and some margin for SW execution, here set it - * to 300us. + * RBC 130us + ARM gating 93us + RBC clear 65us + * + PLL2 relock 450us and some margin, here set + * it to 800us. */ - .exit_latency = 300, - .target_residency = 500, - .flags = CPUIDLE_FLAG_TIMER_STOP, + .exit_latency = 800, + .target_residency = 1000, .enter = imx6sx_enter_wait, .name = "LOW-POWER-IDLE", .desc = "ARM power off", @@ -99,17 +171,119 @@ static struct cpuidle_driver imx6sx_cpuidle_driver = { int __init imx6sx_cpuidle_init(void) { + void __iomem *anatop_base = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + u32 val; +#ifdef CONFIG_CPU_FREQ + struct imx6_cpuidle_pm_info *cpuidle_pm_info; + int i; + const u32 *mmdc_offset_array; + u32 wfi_code_size; + + wfi_iram_base_phys = (void *)(iram_tlb_phys_addr + MX6_CPUIDLE_IRAM_ADDR_OFFSET); + + /* Make sure wfi_iram_base is 8 byte aligned. */ + if ((uintptr_t)(wfi_iram_base_phys) & (FNCPY_ALIGN - 1)) + wfi_iram_base_phys += FNCPY_ALIGN - ((uintptr_t)wfi_iram_base_phys % (FNCPY_ALIGN)); + + wfi_iram_base = (void *)IMX_IO_P2V((unsigned long) wfi_iram_base_phys); + + cpuidle_pm_info = wfi_iram_base; + cpuidle_pm_info->pbase = (phys_addr_t) wfi_iram_base_phys; + cpuidle_pm_info->pm_info_size = sizeof(*cpuidle_pm_info); + cpuidle_pm_info->resume_addr = virt_to_phys(v7_cpu_resume); + cpuidle_pm_info->mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset); + mmdc_offset_array = imx6sx_mmdc_io_offset; + + cpuidle_pm_info->mmdc_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; + cpuidle_pm_info->mmdc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); + + cpuidle_pm_info->ccm_base.pbase = MX6Q_CCM_BASE_ADDR; + cpuidle_pm_info->ccm_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); + + cpuidle_pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; + cpuidle_pm_info->anatop_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + + cpuidle_pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; + cpuidle_pm_info->gpc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); + + cpuidle_pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; + cpuidle_pm_info->iomuxc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); + + cpuidle_pm_info->l2_base.pbase = MX6Q_L2_BASE_ADDR; + cpuidle_pm_info->l2_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_L2_BASE_ADDR); + + cpuidle_pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; + cpuidle_pm_info->src_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); + + cpuidle_pm_info->sema4_base.pbase = MX6Q_SEMA4_BASE_ADDR; + cpuidle_pm_info->sema4_base.vbase = + (void __iomem *)IMX_IO_P2V(MX6Q_SEMA4_BASE_ADDR); + + /* only save mmdc io offset, settings will be saved in asm code */ + for (i = 0; i < cpuidle_pm_info->mmdc_io_num; i++) + cpuidle_pm_info->mmdc_io_val[i][0] = mmdc_offset_array[i]; + + /* code size should include cpuidle_pm_info size */ + wfi_code_size = (&mx6sx_lpm_wfi_end -&mx6sx_lpm_wfi_start) *4 + sizeof(*cpuidle_pm_info); + imx6sx_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*cpuidle_pm_info), + &imx6sx_low_power_idle, wfi_code_size); +#endif + imx6_set_int_mem_clk_lpm(true); - imx6_enable_rbc(false); - imx_gpc_set_l2_mem_power_in_lpm(false); - /* - * set ARM power up/down timing to the fastest, - * sw2iso and sw can be set to one 32K cycle = 31us - * except for power up sw2iso which need to be - * larger than LDO ramp up time. - */ - imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1); - imx_gpc_set_arm_power_down_timing(1, 1); + + if (imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) { + /* + * enable RC-OSC here, as it needs at least 4ms for RC-OSC to + * be stable, low power idle flow can NOT endure this big + * latency, so we make RC-OSC self-tuning enabled here. + */ + val = readl_relaxed(anatop_base + PMU_LOW_PWR_CTRL); + val |= 0x1; + writel_relaxed(val, anatop_base + PMU_LOW_PWR_CTRL); + /* + * config RC-OSC freq + * tune_enable = 1;tune_start = 1;hyst_plus = 0;hyst_minus = 0; + * osc_prog = 0xa7; + */ + writel_relaxed( + 0x4 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT | + 0xa7 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_START_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set count_trg = 0x2dc */ + writel_relaxed( + 0x40 << XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT | + 0x2dc << XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG1); + /* wait 4ms according to hardware design */ + msleep(4); + /* + * now add some hysteresis, hyst_plus=3, hyst_minus=3 + * (the minimum hysteresis that looks good is 2) + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG0); + val &= ~((XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT)); + val |= (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT); + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set the count_1m_trg = 0x2d7 */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG2); + val &= ~(XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK << + XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT); + val |= 0x2d7 << XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT; + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG2); + /* + * hardware design require to write XTALOSC24M_OSC_CONFIG0 or + * XTALOSC24M_OSC_CONFIG1 to + * make XTALOSC24M_OSC_CONFIG2 write work + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG1); + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG1); + } return cpuidle_register(&imx6sx_cpuidle_driver, NULL); } diff --git a/arch/arm/mach-imx/cpuidle-imx6ul.c b/arch/arm/mach-imx/cpuidle-imx6ul.c new file mode 100644 index 000000000000..4f22b8f0d02b --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx6ul.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/busfreq-imx.h> +#include <linux/cpuidle.h> +#include <linux/cpu_pm.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/psci.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <asm/cpuidle.h> +#include <asm/fncpy.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> + +#include <uapi/linux/psci.h> + +#include "common.h" +#include "cpuidle.h" +#include "hardware.h" + +#define MAX_MMDC_IO_NUM 14 + +#define PMU_LOW_PWR_CTRL 0x270 +#define XTALOSC24M_OSC_CONFIG0 0x2a0 +#define XTALOSC24M_OSC_CONFIG1 0x2b0 +#define XTALOSC24M_OSC_CONFIG2 0x2c0 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT 24 +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT 16 +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT 12 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT 4 +#define XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT 1 +#define XTALOSC24M_OSC_CONFIG0_START_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT 20 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK 0xfff +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT 0 + +extern unsigned long iram_tlb_phys_addr; +static void __iomem *wfi_iram_base; + +#ifdef CONFIG_CPU_FREQ +static void __iomem *wfi_iram_base_phys; +extern unsigned long mx6ul_lpm_wfi_start asm("mx6ul_lpm_wfi_start"); +extern unsigned long mx6ul_lpm_wfi_end asm("mx6ul_lpm_wfi_end"); +extern unsigned long mx6ull_lpm_wfi_start asm("mx6ull_lpm_wfi_start"); +extern unsigned long mx6ull_lpm_wfi_end asm("mx6ull_lpm_wfi_end"); +#endif + +struct imx6_pm_base { + phys_addr_t pbase; + void __iomem *vbase; +}; + +struct imx6_cpuidle_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 pm_info_size; /* Size of pm_info. */ + u32 ttbr; + struct imx6_pm_base mmdc_base; + struct imx6_pm_base iomuxc_base; + struct imx6_pm_base ccm_base; + struct imx6_pm_base gpc_base; + struct imx6_pm_base anatop_base; + struct imx6_pm_base src_base; + u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ + u32 mmdc_io_val[MAX_MMDC_IO_NUM][2]; /* To save offset and value */ +} __aligned(8); + +static const u32 imx6ul_mmdc_io_offset[] __initconst = { + 0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */ + 0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */ + 0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */ + 0x494, 0x4b0, /* MODE_CTL, MODE, */ +}; + +static void (*imx6ul_wfi_in_iram_fn)(void __iomem *iram_vbase); + +#define MX6UL_POWERDWN_IDLE_PARAM \ + ((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +static int imx6ul_idle_finish(unsigned long val) +{ + if (psci_ops.cpu_suspend) + psci_ops.cpu_suspend(MX6UL_POWERDWN_IDLE_PARAM, + __pa(cpu_resume)); + else + imx6ul_wfi_in_iram_fn(wfi_iram_base); + + return 0; +} + +static int imx6ul_enter_wait(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + int mode = get_bus_freq_mode(); + + imx6_set_lpm(WAIT_UNCLOCKED); + if ((index == 1) || ((mode != BUS_FREQ_LOW) && index == 2)) { + cpu_do_idle(); + index = 1; + } else { + /* + * i.MX6UL TO1.0 ARM power up uses IPG/2048 as clock source, + * from TO1.1, PGC_CPU_PUPSCR bit [5] is re-defined to switch + * clock to IPG/32, enable this bit to speed up the ARM power + * up process in low power idle case. + */ + if (cpu_is_imx6ul() && imx_get_soc_revision() > + IMX_CHIP_REVISION_1_0) + imx_gpc_switch_pupscr_clk(true); + /* Need to notify there is a cpu pm operation. */ + cpu_pm_enter(); + cpu_cluster_pm_enter(); + + cpu_suspend(0, imx6ul_idle_finish); + + cpu_cluster_pm_exit(); + cpu_pm_exit(); + imx6_enable_rbc(false); + + if (cpu_is_imx6ul() && imx_get_soc_revision() > + IMX_CHIP_REVISION_1_0) + imx_gpc_switch_pupscr_clk(false); + } + + imx6_set_lpm(WAIT_CLOCKED); + + return index; +} + +static struct cpuidle_driver imx6ul_cpuidle_driver_v2 = { + .name = "imx6ul_cpuidle", + .owner = THIS_MODULE, + .states = { + /* WFI */ + ARM_CPUIDLE_WFI_STATE, + /* WAIT */ + { + .exit_latency = 50, + .target_residency = 75, + .enter = imx6ul_enter_wait, + .name = "WAIT", + .desc = "Clock off", + }, + /* LOW POWER IDLE */ + { + /* + * RBC 130us + ARM gating 43us + RBC clear 65us + * + PLL2 relock 450us and some margin, here set + * it to 700us. + */ + .exit_latency = 700, + .target_residency = 1000, + .enter = imx6ul_enter_wait, + .name = "LOW-POWER-IDLE", + .desc = "ARM power off", + } + }, + .state_count = 3, + .safe_state_index = 0, +}; + +static struct cpuidle_driver imx6ul_cpuidle_driver = { + .name = "imx6ul_cpuidle", + .owner = THIS_MODULE, + .states = { + /* WFI */ + ARM_CPUIDLE_WFI_STATE, + /* WAIT */ + { + .exit_latency = 50, + .target_residency = 75, + .enter = imx6ul_enter_wait, + .name = "WAIT", + .desc = "Clock off", + }, + /* LOW POWER IDLE */ + { + /* + * RBC 130us + ARM gating 1370us + RBC clear 65us + * + PLL2 relock 450us and some margin, here set + * it to 2100us. + */ + .exit_latency = 2100, + .target_residency = 2500, + .enter = imx6ul_enter_wait, + .name = "LOW-POWER-IDLE", + .desc = "ARM power off", + } + }, + .state_count = 3, + .safe_state_index = 0, +}; + +int __init imx6ul_cpuidle_init(void) +{ + void __iomem *anatop_base = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + u32 val; +#ifdef CONFIG_CPU_FREQ + struct imx6_cpuidle_pm_info *cpuidle_pm_info; + int i; + const u32 *mmdc_offset_array; + u32 wfi_code_size; + + wfi_iram_base_phys = (void *)(iram_tlb_phys_addr + MX6_CPUIDLE_IRAM_ADDR_OFFSET); + + /* Make sure wfi_iram_base is 8 byte aligned. */ + if ((uintptr_t)(wfi_iram_base_phys) & (FNCPY_ALIGN - 1)) + wfi_iram_base_phys += FNCPY_ALIGN - ((uintptr_t)wfi_iram_base_phys % (FNCPY_ALIGN)); + + wfi_iram_base = (void *)IMX_IO_P2V((unsigned long) wfi_iram_base_phys); + + cpuidle_pm_info = wfi_iram_base; + cpuidle_pm_info->pbase = (phys_addr_t) wfi_iram_base_phys; + cpuidle_pm_info->pm_info_size = sizeof(*cpuidle_pm_info); + cpuidle_pm_info->resume_addr = virt_to_phys(v7_cpu_resume); + cpuidle_pm_info->mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset); + mmdc_offset_array = imx6ul_mmdc_io_offset; + + cpuidle_pm_info->mmdc_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; + cpuidle_pm_info->mmdc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); + + cpuidle_pm_info->ccm_base.pbase = MX6Q_CCM_BASE_ADDR; + cpuidle_pm_info->ccm_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); + + cpuidle_pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; + cpuidle_pm_info->anatop_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); + + cpuidle_pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; + cpuidle_pm_info->gpc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); + + cpuidle_pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; + cpuidle_pm_info->iomuxc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); + + cpuidle_pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; + cpuidle_pm_info->src_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); + + /* Only save mmdc io offset, settings will be saved in asm code */ + for (i = 0; i < cpuidle_pm_info->mmdc_io_num; i++) + cpuidle_pm_info->mmdc_io_val[i][0] = mmdc_offset_array[i]; + + /* calculate the wfi code size */ + if (cpu_is_imx6ul()) { + wfi_code_size = (&mx6ul_lpm_wfi_end -&mx6ul_lpm_wfi_start) *4; + + imx6ul_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*cpuidle_pm_info), + &imx6ul_low_power_idle, wfi_code_size); + } else { + wfi_code_size = (&mx6ull_lpm_wfi_end -&mx6ull_lpm_wfi_start) *4; + + imx6ul_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*cpuidle_pm_info), + &imx6ull_low_power_idle, wfi_code_size); + } +#endif + + imx6_set_int_mem_clk_lpm(true); + + /* + * enable RC-OSC here, as it needs at least 4ms for RC-OSC to + * be stable, low power idle flow can NOT endure this big + * latency, so we make RC-OSC self-tuning enabled here. + */ + val = readl_relaxed(anatop_base + PMU_LOW_PWR_CTRL); + val |= 0x1; + writel_relaxed(val, anatop_base + PMU_LOW_PWR_CTRL); + /* + * config RC-OSC freq + * tune_enable = 1;tune_start = 1;hyst_plus = 0;hyst_minus = 0; + * osc_prog = 0xa7; + */ + writel_relaxed( + 0x4 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT | + 0xa7 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_START_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set count_trg = 0x2dc */ + writel_relaxed( + 0x40 << XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT | + 0x2dc << XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG1); + /* wait 4ms according to hardware design */ + msleep(4); + /* + * now add some hysteresis, hyst_plus=3, hyst_minus=3 + * (the minimum hysteresis that looks good is 2) + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG0); + val &= ~((XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT)); + val |= (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT); + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set the count_1m_trg = 0x2d7 */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG2); + val &= ~(XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK << + XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT); + val |= 0x2d7 << XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT; + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG2); + /* + * hardware design require to write XTALOSC24M_OSC_CONFIG0 or + * XTALOSC24M_OSC_CONFIG1 to + * make XTALOSC24M_OSC_CONFIG2 write work + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG1); + + /* ARM power up time is reduced since TO1.1 */ + if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_0) + return cpuidle_register(&imx6ul_cpuidle_driver_v2, NULL); + else + return cpuidle_register(&imx6ul_cpuidle_driver, NULL); +} diff --git a/arch/arm/mach-imx/cpuidle-imx7d.c b/arch/arm/mach-imx/cpuidle-imx7d.c new file mode 100644 index 000000000000..e38c2c78290b --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx7d.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/busfreq-imx.h> +#include <linux/cpuidle.h> +#include <linux/cpu_pm.h> +#include <linux/delay.h> +#include <linux/genalloc.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/psci.h> +#include <asm/cp15.h> +#include <asm/cpuidle.h> +#include <asm/fncpy.h> +#include <asm/mach/map.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> +#include <asm/tlb.h> + +#include <uapi/linux/psci.h> + +#include "common.h" +#include "cpuidle.h" +#include "hardware.h" + +#define XTALOSC24M_OSC_CONFIG0 0x10 +#define XTALOSC24M_OSC_CONFIG1 0x20 +#define XTALOSC24M_OSC_CONFIG2 0x30 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT 24 +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT 16 +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK 0xf +#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT 12 +#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT 4 +#define XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT 1 +#define XTALOSC24M_OSC_CONFIG0_START_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT 20 +#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT 0 +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK 0xfff +#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT 0 + +#define XTALOSC_CTRL_24M 0x0 +#define XTALOSC_CTRL_24M_RC_OSC_EN_SHIFT 13 +#define REG_SET 0x4 + +static void __iomem *wfi_iram_base; +static void __iomem *wfi_iram_base_phys; +extern unsigned long iram_tlb_phys_addr; + +struct imx7_pm_base { + phys_addr_t pbase; + void __iomem *vbase; +}; + +struct imx7_cpuidle_pm_info { + phys_addr_t vbase; /* The virtual address of 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 pm_info_size; + u32 ttbr; + u32 num_online_cpus; + u32 num_lpi_cpus; + atomic_t val; + atomic_t flag0; + atomic_t flag1; + struct imx7_pm_base ddrc_base; + struct imx7_pm_base ccm_base; + struct imx7_pm_base anatop_base; + struct imx7_pm_base src_base; + struct imx7_pm_base iomuxc_gpr_base; + struct imx7_pm_base gpc_base; + struct imx7_pm_base gic_dist_base; +} __aligned(8); + +static atomic_t master_lpi = ATOMIC_INIT(0); +static atomic_t master_wait = ATOMIC_INIT(0); + +static void (*imx7d_wfi_in_iram_fn)(void __iomem *iram_vbase); +static struct imx7_cpuidle_pm_info *cpuidle_pm_info; + +#define MX7D_POWERDWN_IDLE_PARAM \ + ((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +#define MX7D_STANDBY_IDLE_PARAM \ + ((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_STANDBY << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +/* Mapped for the kernel, unlike cpuidle_pm_info->gic_dist_base.vbase */ +static void __iomem *imx7d_cpuidle_gic_base; + +static void imx_pen_lock(int cpu) +{ + if (cpu == 0) { + atomic_set(&cpuidle_pm_info->flag0, 1); + dsb(); + atomic_set(&cpuidle_pm_info->val, cpu); + do { + dsb(); + } while (atomic_read(&cpuidle_pm_info->flag1) == 1 + && atomic_read(&cpuidle_pm_info->val) == cpu) + ; + } else { + atomic_set(&cpuidle_pm_info->flag1, 1); + dsb(); + atomic_set(&cpuidle_pm_info->val, cpu); + do { + dsb(); + } while (atomic_read(&cpuidle_pm_info->flag0) == 1 + && atomic_read(&cpuidle_pm_info->val) == cpu) + ; + } +} + +static void imx_pen_unlock(int cpu) +{ + dsb(); + if (cpu == 0) + atomic_set(&cpuidle_pm_info->flag0, 0); + else + atomic_set(&cpuidle_pm_info->flag1, 0); +} + +static int imx7d_idle_finish(unsigned long val) +{ + if (psci_ops.cpu_suspend) + psci_ops.cpu_suspend(MX7D_POWERDWN_IDLE_PARAM, __pa(cpu_resume)); + else + imx7d_wfi_in_iram_fn(wfi_iram_base); + + return 0; +} + +static bool imx7d_gic_sgis_pending(void) +{ + void __iomem *sgip_base = imx7d_cpuidle_gic_base + 0x1f20; + + return (readl_relaxed(sgip_base + 0x0) | + readl_relaxed(sgip_base + 0x4) | + readl_relaxed(sgip_base + 0x8) | + readl_relaxed(sgip_base + 0xc)); +} + +static DEFINE_SPINLOCK(psci_lock); +static int imx7d_enter_low_power_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + int mode = get_bus_freq_mode(); + + + if ((index == 1) || ((mode != BUS_FREQ_LOW) && index == 2)) { + index = 1; + if (atomic_inc_return(&master_wait) == num_online_cpus()) + imx_gpcv2_set_lpm_mode(WAIT_UNCLOCKED); + + cpu_do_idle(); + + atomic_dec(&master_wait); + imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); + } else { + if (psci_ops.cpu_suspend) { + cpu_pm_enter(); + spin_lock(&psci_lock); + if (atomic_inc_return(&master_lpi) == num_online_cpus()) { + if (imx7d_gic_sgis_pending()) { + atomic_dec(&master_lpi); + index = -1; + goto psci_skip_lpi_flow; + } + + imx_gpcv2_set_lpm_mode(WAIT_UNCLOCKED); + imx_gpcv2_set_cpu_power_gate_in_idle(true); + + cpu_cluster_pm_enter(); + } + spin_unlock(&psci_lock); + + cpu_suspend(0, imx7d_idle_finish); + + spin_lock(&psci_lock); + if (atomic_read(&master_lpi) == num_online_cpus()) { + cpu_cluster_pm_exit(); + imx_gpcv2_set_cpu_power_gate_in_idle(false); + imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); + } + + atomic_dec(&master_lpi); +psci_skip_lpi_flow: + spin_unlock(&psci_lock); + cpu_pm_exit(); + } else { + imx_pen_lock(dev->cpu); + cpuidle_pm_info->num_online_cpus = num_online_cpus(); + ++cpuidle_pm_info->num_lpi_cpus; + cpu_pm_enter(); + if (cpuidle_pm_info->num_lpi_cpus == + cpuidle_pm_info->num_online_cpus) { + /* + * GPC will not wake on SGIs so check for them + * manually here. At this point we know the other cpu + * is in wfi or waiting for the lock and can't send + * any additional IPIs. + */ + if (imx7d_gic_sgis_pending()) { + index = -1; + goto skip_lpi_flow; + } + imx_gpcv2_set_lpm_mode(WAIT_UNCLOCKED); + imx_gpcv2_set_cpu_power_gate_in_idle(true); + cpu_cluster_pm_enter(); + } else { + imx_set_cpu_jump(dev->cpu, ca7_cpu_resume); + } + + cpu_suspend(0, imx7d_idle_finish); + + if (cpuidle_pm_info->num_lpi_cpus == + cpuidle_pm_info->num_online_cpus) { + cpu_cluster_pm_exit(); + imx_gpcv2_set_cpu_power_gate_in_idle(false); + imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); + } + +skip_lpi_flow: + cpu_pm_exit(); + --cpuidle_pm_info->num_lpi_cpus; + imx_pen_unlock(dev->cpu); + } + } + + return index; +} + +static struct cpuidle_driver imx7d_cpuidle_driver = { + .name = "imx7d_cpuidle", + .owner = THIS_MODULE, + .states = { + /* WFI */ + ARM_CPUIDLE_WFI_STATE, + /* WAIT MODE */ + { + .exit_latency = 50, + .target_residency = 75, + .flags = CPUIDLE_FLAG_TIMER_STOP, + .enter = imx7d_enter_low_power_idle, + .name = "WAIT", + .desc = "Clock off", + }, + /* LOW POWER IDLE */ + { + .exit_latency = 12000, + .target_residency = 22000, + .flags = CPUIDLE_FLAG_TIMER_STOP, + .enter = imx7d_enter_low_power_idle, + .name = "LOW-POWER-IDLE", + .desc = "ARM power off", + }, + }, + .state_count = 3, + .safe_state_index = 0, +}; + +int imx7d_enable_rcosc(void) +{ + void __iomem *anatop_base = + (void __iomem *)IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR); + u32 val; + + imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); + /* set RC-OSC freq and turn it on */ + writel_relaxed(0x1 << XTALOSC_CTRL_24M_RC_OSC_EN_SHIFT, + anatop_base + XTALOSC_CTRL_24M + REG_SET); + /* + * config RC-OSC freq + * tune_enable = 1;tune_start = 1;hyst_plus = 0;hyst_minus = 0; + * osc_prog = 0xa7; + */ + writel_relaxed( + 0x4 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT | + 0xa7 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT | + 0x1 << XTALOSC24M_OSC_CONFIG0_START_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set count_trg = 0x2dc */ + writel_relaxed( + 0x40 << XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT | + 0x2dc << XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT, + anatop_base + XTALOSC24M_OSC_CONFIG1); + /* wait at least 4ms according to hardware design */ + mdelay(6); + /* + * now add some hysteresis, hyst_plus=3, hyst_minus=3 + * (the minimum hysteresis that looks good is 2) + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG0); + val &= ~((XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK << + XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT)); + val |= (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | + (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT); + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG0); + /* set the count_1m_trg = 0x2d7 */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG2); + val &= ~(XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK << + XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT); + val |= 0x2d7 << XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT; + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG2); + /* + * hardware design require to write XTALOSC24M_OSC_CONFIG0 or + * XTALOSC24M_OSC_CONFIG1 to + * make XTALOSC24M_OSC_CONFIG2 write work + */ + val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG1); + writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG1); + + return 0; +} + +int __init imx7d_cpuidle_init(void) +{ + wfi_iram_base_phys = (void *)(iram_tlb_phys_addr + + MX7_CPUIDLE_OCRAM_ADDR_OFFSET); + + /* Make sure wfi_iram_base is 8 byte aligned. */ + if ((uintptr_t)(wfi_iram_base_phys) & (FNCPY_ALIGN - 1)) + wfi_iram_base_phys += FNCPY_ALIGN - + ((uintptr_t)wfi_iram_base_phys % (FNCPY_ALIGN)); + + wfi_iram_base = (void *)IMX_IO_P2V((unsigned long) wfi_iram_base_phys); + + cpuidle_pm_info = wfi_iram_base; + cpuidle_pm_info->vbase = (phys_addr_t) wfi_iram_base; + cpuidle_pm_info->pbase = (phys_addr_t) wfi_iram_base_phys; + cpuidle_pm_info->pm_info_size = sizeof(*cpuidle_pm_info); + cpuidle_pm_info->resume_addr = virt_to_phys(ca7_cpu_resume); + cpuidle_pm_info->num_online_cpus = num_online_cpus(); + + cpuidle_pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR; + cpuidle_pm_info->ddrc_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_DDRC_BASE_ADDR); + + cpuidle_pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR; + cpuidle_pm_info->ccm_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_CCM_BASE_ADDR); + + cpuidle_pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR; + cpuidle_pm_info->anatop_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR); + + cpuidle_pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR; + cpuidle_pm_info->src_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_SRC_BASE_ADDR); + + cpuidle_pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR; + cpuidle_pm_info->iomuxc_gpr_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR); + + cpuidle_pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR; + cpuidle_pm_info->gpc_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_GPC_BASE_ADDR); + + cpuidle_pm_info->gic_dist_base.pbase = MX7D_GIC_BASE_ADDR; + cpuidle_pm_info->gic_dist_base.vbase = + (void __iomem *)IMX_IO_P2V(MX7D_GIC_BASE_ADDR); + + imx7d_cpuidle_gic_base = ioremap(MX7D_GIC_BASE_ADDR, MX7D_GIC_SIZE); + + imx7d_enable_rcosc(); + + /* code size should include cpuidle_pm_info size */ + if (!psci_ops.cpu_suspend) { + imx7d_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + + sizeof(*cpuidle_pm_info), + &imx7d_low_power_idle, + MX7_CPUIDLE_OCRAM_SIZE - sizeof(*cpuidle_pm_info)); + } + + return cpuidle_register(&imx7d_cpuidle_driver, NULL); +} diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index ce552c096cae..340b0e3af05f 100644 --- a/arch/arm/mach-imx/cpuidle.h +++ b/arch/arm/mach-imx/cpuidle.h @@ -8,7 +8,11 @@ extern int imx5_cpuidle_init(void); extern int imx6q_cpuidle_init(void); extern int imx6sl_cpuidle_init(void); +extern int imx6sll_cpuidle_init(void); extern int imx6sx_cpuidle_init(void); +extern int imx6ul_cpuidle_init(void); +extern int imx7d_cpuidle_init(void); +extern int imx7d_enable_rcosc(void); extern int imx7ulp_cpuidle_init(void); #else static inline int imx5_cpuidle_init(void) @@ -23,10 +27,26 @@ static inline int imx6sl_cpuidle_init(void) { return 0; } +static inline int imx6sll_cpuidle_init(void) +{ + return 0; +} static inline int imx6sx_cpuidle_init(void) { return 0; } +static inline int imx6ul_cpuidle_init(void) +{ + return 0; +} +static inline int imx7d_cpuidle_init(void) +{ + return 0; +} +static inline int imx7d_enable_rcosc(void) +{ + return 0; +} static inline int imx7ulp_cpuidle_init(void) { return 0; diff --git a/arch/arm/mach-imx/ddr3_freq_imx6.S b/arch/arm/mach-imx/ddr3_freq_imx6.S new file mode 100644 index 000000000000..e6f7f74f7d32 --- /dev/null +++ b/arch/arm/mach-imx/ddr3_freq_imx6.S @@ -0,0 +1,1103 @@ +/* + * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include <asm/smp_scu.h> +#include "hardware.h" + +#define MMDC0_MDPDC 0x4 +#define MMDC0_MDCF0 0x0c +#define MMDC0_MDCF1 0x10 +#define MMDC0_MDMISC 0x18 +#define MMDC0_MDSCR 0x1c +#define MMDC0_MAARCR 0x400 +#define MMDC0_MAPSR 0x404 +#define MMDC0_MADPCR0 0x410 +#define MMDC0_MPZQHWCTRL 0x800 +#define MMDC1_MPZQHWCTRL 0x4800 +#define MMDC0_MPODTCTRL 0x818 +#define MMDC1_MPODTCTRL 0x4818 +#define MMDC0_MPDGCTRL0 0x83c +#define MMDC1_MPDGCTRL0 0x483c +#define MMDC0_MPMUR0 0x8b8 +#define MMDC1_MPMUR0 0x48b8 + +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1c +#define CCM_CDHIPR 0x48 + +#define L2_CACHE_SYNC 0x730 +#define PL310_AUX_CTRL 0x104 +#define PL310_DCACHE_LOCKDOWN_BASE 0x900 +#define PL310_AUX_16WAY_BIT 0x10000 +#define PL310_LOCKDOWN_NBREGS 8 +#define PL310_LOCKDOWN_SZREG 4 +#define PL310_8WAYS_MASK 0x00FF +#define PL310_16WAYS_UPPERMASK 0xFF00 + +#define IMX6QP_REVISION_ID 0x630100 +#define ANADIG_DIGPROG 0x260 + +.extern iram_tlb_phys_addr + +.globl mx6_ddr3_freq_change_start +.globl mx6_ddr3_freq_change_end + + .align 3 + + .macro is_mx6qp + + /* check if the SOC is i.MX6QP */ + ldr r0, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) + ldr r1, [r0, #ANADIG_DIGPROG] + ldr r2, =IMX6QP_REVISION_ID + cmp r1, r2 + + .endm + + .macro switch_to_528MHz + + /* check if periph_clk_sel is already set */ + ldr r0, [r6, #CCM_CBCDR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq set_ahb_podf_before_switch + + /* change periph_clk to be sourced from pll3_clk. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(3 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 20) + str r0, [r6, #CCM_CBCDR] + + /* + * set the AHB dividers before the switch, + * don't change AXI clock divider, + * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0xd00 + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update528: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update528 + + /* now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch3: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch3 + + b switch_pre_periph_clk_528 + +set_ahb_podf_before_switch: + /* + * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0xd00 + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update528_1: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update528_1 + +switch_pre_periph_clk_528: + + /* now switch pre_periph_clk to PLL2_528MHz. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0xc << 16) + str r0, [r6, #CCM_CBCMR] + + /* now switch periph_clk back. */ + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch4: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch4 + + .endm + + .macro switch_to_400MHz + + /* check if periph_clk_sel is already set. */ + ldr r0, [r6, #CCM_CBCDR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq set_ahb_podf_before_switch1 + + /* change periph_clk to be sourced from pll3_clk. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(3 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 24) + str r0, [r6, #CCM_CBCDR] + + /* now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch5: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch5 + + b switch_pre_periph_clk_400 + +set_ahb_podf_before_switch1: + /* + * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(0x9 << 8) + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update400_1: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update400_1 + +switch_pre_periph_clk_400: + + /* now switch pre_periph_clk to PFD_400MHz. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0xc << 16) + orr r0, r0, #(0x4 << 16) + str r0, [r6, #CCM_CBCMR] + + /* now switch periph_clk back. */ + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch6: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch6 + + /* + * change AHB divider so that we are at 400/3=133MHz. + * don't change AXI clock divider. + * set the MMDC_DIV=1, AXI_DIV=2, AHB_DIV=3, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(0x9 << 8) + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update400_2: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update400_2 + + .endm + + .macro switch_to_50MHz + + /* check if periph_clk_sel is already set. */ + ldr r0, [r6, #CCM_CBCDR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq switch_pre_periph_clk_50 + + /* + * set the periph_clk to be sourced from PLL2_PFD_200M + * change periph_clk to be sourced from pll3_clk. + * ensure PLL3 is the source and set the divider to 1. + */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0x3 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 24) + str r0, [r6, #CCM_CBCDR] + + /* now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch_50: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch_50 + +switch_pre_periph_clk_50: + + /* now switch pre_periph_clk to PFD_200MHz. */ + ldr r0, [r6, #CCM_CBCMR] + orr r0, r0, #(0xc << 16) + str r0, [r6, #CCM_CBCMR] + + /* + * set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(0x18 << 16) + orr r0, r0, #(0x3 << 16) + + /* + * if changing AHB divider remember to change + * the IPGPER divider too below. + */ + orr r0, r0, #0x1d00 + str r0, [r6, #CCM_CBCDR] + +wait_div_update_50: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update_50 + + /* now switch periph_clk back. */ + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch2: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch2 + + .endm + + .macro switch_to_24MHz + /* + * change the freq now try setting DDR to 24MHz. + * source it from the periph_clk2 ensure the + * periph_clk2 is sourced from 24MHz and the + * divider is 1. + */ + + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0x3 << 12) + orr r0, r0, #(1 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 24) + str r0, [r6, #CCM_CBCDR] + + /* now switch periph_clk to 24MHz. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch1: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch1 + + /* change all the dividers to 1. */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(1 << 8) + str r0, [r6, #CCM_CBCDR] + + /* Wait for the divider to change. */ +wait_div_update: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update + + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r11, lr} + + ldr r7, =v7_flush_kern_cache_all + mov lr, pc + mov pc, r7 + pop {r0 - r11, lr} + + /* disable d-cache */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + dsb + isb + + push {r0 - r11, lr} + + ldr r7, =v7_flush_kern_cache_all + mov lr, pc + mov pc, r7 + pop {r0 - r11, lr} + + .endm + +/* + * mx6_ddr3_freq_change + * + * idle the processor (eg, wait for interrupt). + * make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx6_ddr3_freq_change) + +mx6_ddr3_freq_change_start: + stmfd sp!, {r4-r12} + + /* + * r5 -> mmdc_base + * r6 -> ccm_base + * r7 -> iomux_base + * r12 -> l2_base + */ + mov r4, r0 + mov r8, r1 + mov r9, r2 + mov r11, r3 + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* + * Need to flush and disable L1 before + * disabling L2, we need data to + * coherent. Flushing L1 pushes + * everyhting to L2. We sync L2 later, but + * it can still have dirty lines. + * While exiting, we need to enable L2 first + * and then L1. + */ + disable_l1_dcache + +#ifdef CONFIG_CACHE_L2X0 + /* + * Make sure the L2 buffers are drained. + * Sync operation on L2 drains the buffers. + */ + ldr r12, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + + /* Wait for background operations to complete. */ +wait_for_l2_to_idle: + ldr r1, [r12, #L2_CACHE_SYNC] + cmp r1, #0x0 + bne wait_for_l2_to_idle + + mov r1, #0x0 + str r1, [r12, #L2_CACHE_SYNC] + + dsb + isb + + ldr r1, [r12, #PL310_AUX_CTRL] + tst r1, #PL310_AUX_16WAY_BIT + mov r1, #PL310_8WAYS_MASK + orrne r1, #PL310_16WAYS_UPPERMASK + mov r6, #PL310_LOCKDOWN_NBREGS + add r5, r12, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r1, [r5], #PL310_LOCKDOWN_SZREG + str r1, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + + /* Now switch the TTBR. */ + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + + ldr r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) + ldr r6, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) + ldr r7, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) + + /* Read the Original MU delay value */ + ldr r1, [r5, #MMDC0_MPMUR0] + mov r10, r1, lsr #16 + ldr r1, =0x3ff + and r10, r10, r1 + + /* disable automatic power saving. */ + ldr r0, [r5, #MMDC0_MAPSR] + orr r0, r0, #0x01 + str r0, [r5, #MMDC0_MAPSR] + + /* disable MMDC power down timer. */ + ldr r0, [r5, #MMDC0_MDPDC] + bic r0, r0, #(0xff << 8) + str r0, [r5, #MMDC0_MDPDC] + + /* delay for a while */ + ldr r1, =4 +delay1: + ldr r2, =0 +cont1: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont1 + sub r1, r1, #1 + cmp r1, #0 + bgt delay1 + + /* set CON_REG */ + ldr r0, =0x8000 + str r0, [r5, #MMDC0_MDSCR] +poll_conreq_set_1: + ldr r0, [r5, #MMDC0_MDSCR] + and r0, r0, #(0x4 << 12) + cmp r0, #(0x4 << 12) + bne poll_conreq_set_1 + + /* + * if requested frequency is great than + * 300MHz, skip setting bypass adopt mode. + */ + ldr r1, =300000000 + cmp r4, r1 + bge 1f + + is_mx6qp + bne 1f + /* Switch to adopt mode, set MMDC0_MAARCR bit25~26 to 2b'01 */ + ldr r0, [r5, #MMDC0_MAARCR] + bic r0, r0, #(0x3 << 25) + orr r0, #(0x01 << 25) + str r0 , [r5, #MMDC0_MAARCR] +1: + ldr r0, =0x00008050 + str r0, [r5, #MMDC0_MDSCR] + ldr r0, =0x00008058 + str r0, [r5, #MMDC0_MDSCR] + + /* + * if requested frequency is greater than + * 300MHz go to DLL on mode. + */ + ldr r1, =300000000 + cmp r4, r1 + bge dll_on_mode + +dll_off_mode: + + /* if DLL is currently on, turn it off. */ + cmp r9, #1 + beq continue_dll_off_1 + + ldr r0, =0x00018031 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x00018039 + str r0, [r5, #MMDC0_MDSCR] + + ldr r1, =10 +delay1a: + ldr r2, =0 +cont1a: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont1a + sub r1, r1, #1 + cmp r1, #0 + bgt delay1a + +continue_dll_off_1: + /* set DVFS - enter self refresh mode */ + ldr r0, [r5, #MMDC0_MAPSR] + orr r0, r0, #(1 << 21) + str r0, [r5, #MMDC0_MAPSR] + + /* de-assert con_req */ + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] + +poll_dvfs_set_1: + ldr r0, [r5, #MMDC0_MAPSR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + bne poll_dvfs_set_1 + + ldr r1, =24000000 + cmp r4, r1 + beq switch_freq_24 + + switch_to_50MHz + b continue_dll_off_2 + +switch_freq_24: + switch_to_24MHz + +continue_dll_off_2: + + /* set SBS - block ddr accesses */ + ldr r0, [r5, #MMDC0_MADPCR0] + orr r0, r0, #(1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + /* clear DVFS - exit from self refresh mode */ + ldr r0, [r5, #MMDC0_MAPSR] + bic r0, r0, #(1 << 21) + str r0, [r5, #MMDC0_MAPSR] + +poll_dvfs_clear_1: + ldr r0, [r5, #MMDC0_MAPSR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq poll_dvfs_clear_1 + + /* if DLL was previously on, continue DLL off routine. */ + cmp r9, #1 + beq continue_dll_off_3 + + ldr r0, =0x00018031 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x00018039 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x08208030 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x08208038 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x00088032 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x0008803A + str r0, [r5, #MMDC0_MDSCR] + + /* delay for a while. */ + ldr r1, =4 +delay_1: + ldr r2, =0 +cont_1: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont_1 + sub r1, r1, #1 + cmp r1, #0 + bgt delay_1 + + ldr r0, [r5, #MMDC0_MDCF0] + bic r0, r0, #0xf + orr r0, r0, #0x3 + str r0, [r5, #MMDC0_MDCF0] + + ldr r0, [r5, #MMDC0_MDCF1] + bic r0, r0, #0x7 + orr r0, r0, #0x4 + str r0, [r5, #MMDC0_MDCF1] + + ldr r0, [r5, #MMDC0_MDMISC] + bic r0, r0, #(0x3 << 16) /* walat = 0x1 */ + orr r0, r0, #(0x1 << 16) + bic r0, r0, #(0x7 << 6) /* ralat = 0x2 */ + orr r0, r0, #(0x2 << 6) + str r0, [r5, #MMDC0_MDMISC] + + /* enable dqs pull down in the IOMUX. */ + ldr r1, [r11] + add r11, r11, #8 + ldr r2, =0x3028 +update_iomux: + ldr r0, [r11, #0x0] + ldr r3, [r7, r0] + bic r3, r3, r2 + orr r3, r3, #(0x3 << 12) + orr r3, r3, #0x28 + str r3, [r7, r0] + add r11, r11, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_iomux + + /* ODT disabled. */ + ldr r0, =0x0 + ldr r2, =MMDC0_MPODTCTRL + str r0, [r5, r2] + ldr r2, =MMDC1_MPODTCTRL + str r0, [r5, r2] + + /* DQS gating disabled. */ + ldr r2, =MMDC0_MPDGCTRL0 + ldr r0, [r5, r2] + orr r0, r0, #(1 << 29) + str r0, [r5, r2] + + ldr r2, =MMDC1_MPDGCTRL0 + ldr r0, [r5, r2] + orr r0, r0, #(0x1 << 29) + str r0, [r5, r2] + + /* Add workaround for ERR005778.*/ + /* double the original MU_UNIT_DEL_NUM. */ + lsl r10, r10, #1 + + /* Bypass the automatic MU by setting the mu_byp_en */ + ldr r2, [r5, #MMDC0_MPMUR0] + orr r2, r2, #0x400 + orr r2, r2, r10 + str r2, [r5, #MMDC0_MPMUR0] + ldr r0, =MMDC1_MPMUR0 + str r2, [r5, r0] + + /* Now perform a force measure */ + ldr r0, [r5, #MMDC0_MPMUR0] + orr r0, r0, #0x800 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + /* Wait for FRC_MSR to clear. */ +1: + ldr r0, [r5, #MMDC0_MPMUR0] + and r0, r0, #0x800 + ldr r1, [r5, r2] + and r1, r1, #0x800 + orr r0, r0, r1 + cmp r0, #0x0 + bne 1b + +continue_dll_off_3: + /* clear SBS - unblock accesses to DDR. */ + ldr r0, [r5, #MMDC0_MADPCR0] + bic r0, r0, #(0x1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] +poll_conreq_clear_1: + ldr r0, [r5, #MMDC0_MDSCR] + and r0, r0, #(0x4 << 12) + cmp r0, #(0x4 << 12) + beq poll_conreq_clear_1 + + b done + +dll_on_mode: + /* assert DVFS - enter self refresh mode. */ + ldr r0, [r5, #MMDC0_MAPSR] + orr r0, r0, #(1 << 21) + str r0, [r5, #MMDC0_MAPSR] + + /* de-assert CON_REQ. */ + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] + + /* poll DVFS ack. */ +poll_dvfs_set_2: + ldr r0, [r5, #MMDC0_MAPSR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + bne poll_dvfs_set_2 + + ldr r1, =528000000 + cmp r4, r1 + beq switch_freq_528 + + switch_to_400MHz + + b continue_dll_on + +switch_freq_528: + switch_to_528MHz + +continue_dll_on: + + /* set SBS step-by-step mode. */ + ldr r0, [r5, #MMDC0_MADPCR0] + orr r0, r0, #( 1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + /* clear DVFS - exit self refresh mode. */ + ldr r0, [r5, #MMDC0_MAPSR] + bic r0, r0, #(1 << 21) + str r0, [r5, #MMDC0_MAPSR] + +poll_dvfs_clear_2: + ldr r0, [r5, #MMDC0_MAPSR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq poll_dvfs_clear_2 + + /* if DLL is currently off, turn it back on. */ + cmp r9, #0 + beq update_calibration_only + + /* issue zq calibration command */ + ldr r0, [r5, #MMDC0_MPZQHWCTRL] + orr r0, r0, #0x3 + str r0, [r5, #MMDC0_MPZQHWCTRL] + ldr r2, =MMDC1_MPZQHWCTRL + str r0, [r5, r2] + + /* enable DQS gating. */ + ldr r2, =MMDC0_MPDGCTRL0 + ldr r0, [r5, r2] + bic r0, r0, #(1 << 29) + str r0, [r5, r2] + + ldr r2, =MMDC1_MPDGCTRL0 + ldr r0, [r5, r2] + bic r0, r0, #(1 << 29) + str r0, [r5, r2] + + /* force measure. */ + ldr r0, =0x00000800 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + + /* Wait for FRC_MSR to clear. */ +1: + ldr r0, [r5, #MMDC0_MPMUR0] + and r0, r0, #0x800 + ldr r1, [r5, r2] + and r1, r1, #0x800 + orr r0, r0, r1 + cmp r0, #0x0 + bne 1b + + /* disable dqs pull down in the IOMUX. */ + ldr r1, [r11] + add r11, r11, #8 +update_iomux1: + ldr r0, [r11, #0x0] + ldr r3, [r11, #0x4] + str r3, [r7, r0] + add r11, r11, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_iomux1 + + /* config MMDC timings to 528MHz. */ + ldr r9, [r8] + add r8, r8, #8 + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + /* configure ddr devices to dll on, odt. */ + ldr r0, =0x00048031 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x00048039 + str r0, [r5, #MMDC0_MDSCR] + + /* delay for while. */ + ldr r1, =4 +delay7: + ldr r2, =0 +cont7: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont7 + sub r1, r1, #1 + cmp r1, #0 + bgt delay7 + + /* reset dll. */ + ldr r0, =0x09408030 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x09408038 + str r0, [r5, #MMDC0_MDSCR] + + /* delay for while. */ + ldr r1, =100 +delay8: + ldr r2, =0 +cont8: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont8 + sub r1, r1, #1 + cmp r1, #0 + bgt delay8 + + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, =0x00428031 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x00428039 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + /* issue a zq command. */ + ldr r0, =0x04008040 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x04008048 + str r0, [r5, #MMDC0_MDSCR] + + /* MMDC ODT enable. */ + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + ldr r2, =0x4818 + str r3, [r5, r2] + + /* delay for while. */ + ldr r1, =40 +delay15: + ldr r2, =0 +cont15: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont15 + sub r1, r1, #1 + cmp r1, #0 + bgt delay15 + + /* enable MMDC power down timer. */ + ldr r0, [r5, #MMDC0_MDPDC] + orr r0, r0, #(0x55 << 8) + str r0, [r5, #MMDC0_MDPDC] + + b update_calibration + +update_calibration_only: + ldr r1, [r8] + sub r1, r1, #7 + add r8, r8, #64 + b update_calib + +update_calibration: + /* write the new calibration values. */ + mov r1, r9 + sub r1, r1, #7 + +update_calib: + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_calib + + /* perform a force measurement. */ + ldr r0, =0x800 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + + /* Wait for FRC_MSR to clear. */ +1: + ldr r0, [r5, #MMDC0_MPMUR0] + and r0, r0, #0x800 + ldr r1, [r5, r2] + and r1, r1, #0x800 + orr r0, r0, r1 + cmp r0, #0x0 + bne 1b + + /* clear SBS - unblock DDR accesses. */ + ldr r0, [r5, #MMDC0_MADPCR0] + bic r0, r0, #(1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + is_mx6qp + bne 3f + /* + * Switch back to adopt_bp mode, set MMDC0_MAARCR + * bit25~26 to 2b'10. + */ + ldr r0, [r5, #MMDC0_MAARCR] + bic r0, r0, #(0x3 << 25) + orr r0, r0, #(0x2 << 25) + str r0, [r5, #MMDC0_MAARCR] +3: + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] +poll_conreq_clear_2: + ldr r0, [r5, #MMDC0_MDSCR] + and r0, r0, #(0x4 << 12) + cmp r0, #(0x4 << 12) + beq poll_conreq_clear_2 + +done: + /* MMDC0_MAPSR adopt power down enable. */ + ldr r0, [r5, #MMDC0_MAPSR] + bic r0, r0, #0x01 + str r0, [r5, #MMDC0_MAPSR] + +#ifdef CONFIG_CACHE_L2X0 + ldr r1, [r12, #PL310_AUX_CTRL] + tst r1, #PL310_AUX_16WAY_BIT + mov r6, #PL310_LOCKDOWN_NBREGS + mov r1, #0x00 /* 8 ways mask */ + orrne r1, #0x0000 /* 16 ways mask */ + add r5, r12, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r1, [r5], #PL310_LOCKDOWN_SZREG + str r1, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b + + isb + dsb +#endif + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + isb + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + isb + dsb + + /* restore registers */ + ldmfd sp!, {r4-r12} + mov pc, lr + + /* + * Add ltorg here to ensure that all + * literals are stored here and are + * within the text space. + */ + .ltorg +mx6_ddr3_freq_change_end: diff --git a/arch/arm/mach-imx/ddr3_freq_imx6sx.S b/arch/arm/mach-imx/ddr3_freq_imx6sx.S new file mode 100644 index 000000000000..1ac0d017bdf9 --- /dev/null +++ b/arch/arm/mach-imx/ddr3_freq_imx6sx.S @@ -0,0 +1,764 @@ +/* + * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include "hardware.h" + +.globl imx6_up_ddr3_freq_change_start +.globl imx6_up_ddr3_freq_change_end + +#define MMDC0_MDPDC 0x4 +#define MMDC0_MDCF0 0xc +#define MMDC0_MDCF1 0x10 +#define MMDC0_MDMISC 0x18 +#define MMDC0_MDSCR 0x1c +#define MMDC0_MAPSR 0x404 +#define MMDC0_MADPCR0 0x410 +#define MMDC0_MPZQHWCTRL 0x800 +#define MMDC0_MPODTCTRL 0x818 +#define MMDC0_MPDGCTRL0 0x83c +#define MMDC0_MPMUR0 0x8b8 + +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1c +#define CCM_CDHIPR 0x48 + +#define L2_CACHE_SYNC 0x730 +#define PL310_AUX_CTRL 0x104 +#define PL310_DCACHE_LOCKDOWN_BASE 0x900 +#define PL310_AUX_16WAY_BIT 0x10000 +#define PL310_LOCKDOWN_NBREGS 8 +#define PL310_LOCKDOWN_SZREG 4 +#define PL310_8WAYS_MASK 0x00FF +#define PL310_16WAYS_UPPERMASK 0xFF00 + +#define BUSFREQ_INFO_FREQ_OFFSET 0x0 +#define BUSFREQ_INFO_DDR_SETTINGS_OFFSET 0x4 +#define BUSFREQ_INFO_DLL_OFF_OFFSET 0x8 +#define BUSFREQ_INFO_IOMUX_OFFSETS_OFFSET 0xc +#define BUSFREQ_INFO_MU_DELAY_OFFSET 0x10 + +.extern iram_tlb_phys_addr + + .align 3 + + /* Check if the cpu is cortex-a7 */ + .macro is_ca7 + + /* Read the primary cpu number is MPIDR */ + mrc p15, 0, r7, c0, c0, 0 + ldr r8, =0xfff0 + and r7, r7, r8 + ldr r8, =0xc070 + cmp r7, r8 + + .endm + + .macro do_delay + +1: + ldr r9, =0 +2: + ldr r10, [r4, r9] + add r9, r9, #4 + cmp r9, #16 + bne 2b + sub r8, r8, #1 + cmp r8, #0 + bgt 1b + + .endm + + .macro wait_for_ccm_handshake + +3: + ldr r8, [r5, #CCM_CDHIPR] + cmp r8, #0 + bne 3b + + .endm + + .macro switch_to_400MHz + + /* check whether periph2_clk is already from top path */ + ldr r8, [r5, #CCM_CBCDR] + ands r8, #(1 << 26) + beq skip_periph2_clk2_switch_400m + + /* now switch periph2_clk back. */ + ldr r8, [r5, #CCM_CBCDR] + bic r8, r8, #(1 << 26) + str r8, [r5, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* + * on i.MX6SX, pre_periph2_clk will be always from + * pll2_pfd2, so no need to set pre_periph2_clk + * parent, just set the mmdc divider directly. + */ +skip_periph2_clk2_switch_400m: + + /* fabric_mmdc_podf to 0 */ + ldr r8, [r5, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + str r8, [r5, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro switch_to_50MHz + + /* check whether periph2_clk is already from top path */ + ldr r8, [r5, #CCM_CBCDR] + ands r8, #(1 << 26) + beq skip_periph2_clk2_switch_50m + + /* now switch periph2_clk back. */ + ldr r8, [r5, #CCM_CBCDR] + bic r8, r8, #(1 << 26) + str r8, [r5, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* + * on i.MX6SX, pre_periph2_clk will be always from + * pll2_pfd2, so no need to set pre_periph2_clk + * parent, just set the mmdc divider directly. + */ +skip_periph2_clk2_switch_50m: + + /* fabric_mmdc_podf to 7 so that mmdc is 400 / 8 = 50MHz */ + ldr r8, [r5, #CCM_CBCDR] + orr r8, r8, #(0x7 << 3) + str r8, [r5, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro switch_to_24MHz + + /* periph2_clk2 sel to OSC_CLK */ + ldr r8, [r5, #CCM_CBCMR] + orr r8, r8, #(1 << 20) + str r8, [r5, #CCM_CBCMR] + + /* periph2_clk2_podf to 0 */ + ldr r8, [r5, #CCM_CBCDR] + bic r8, r8, #0x7 + str r8, [r5, #CCM_CBCDR] + + /* periph2_clk sel to periph2_clk2 */ + ldr r8, [r5, #CCM_CBCDR] + orr r8, r8, #(0x1 << 26) + str r8, [r5, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* fabric_mmdc_podf to 0 */ + ldr r8, [r5, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + str r8, [r5, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + +/* + * imx6_up_ddr3_freq_change + * Below code can be used by i.MX6SX and i.MX6UL. + * + * idle the processor (eg, wait for interrupt). + * make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(imx6_up_ddr3_freq_change) + +imx6_up_ddr3_freq_change_start: + stmfd sp!, {r4 - r11} + + ldr r1, [r0, #BUSFREQ_INFO_DDR_SETTINGS_OFFSET] + ldr r2, [r0, #BUSFREQ_INFO_DLL_OFF_OFFSET] + ldr r3, [r0, #BUSFREQ_INFO_IOMUX_OFFSETS_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + ldr r4, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) + ldr r5, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) + ldr r6, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) + + is_ca7 + beq skip_disable_l2 + +#ifdef CONFIG_CACHE_L2X0 + /* + * make sure the L2 buffers are drained, + * sync operation on L2 drains the buffers. + */ + ldr r8, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + + /* Wait for background operations to complete. */ +wait_for_l2_to_idle: + ldr r7, [r8, #0x730] + cmp r7, #0x0 + bne wait_for_l2_to_idle + + mov r7, #0x0 + str r7, [r8, #L2_CACHE_SYNC] + + /* Lock L2. */ + + ldr r9, [r8, #PL310_AUX_CTRL] + tst r9, #PL310_AUX_16WAY_BIT + mov r9, #PL310_8WAYS_MASK + orrne r9, #PL310_16WAYS_UPPERMASK + mov r10, #PL310_LOCKDOWN_NBREGS + add r11, r8, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r9, [r11], #PL310_LOCKDOWN_SZREG + str r9, [r11], #PL310_LOCKDOWN_SZREG + subs r10, r10, #1 + bne 1b + + /* + * The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb +#endif + +skip_disable_l2: + /* disable automatic power saving. */ + ldr r8, [r4, #MMDC0_MAPSR] + orr r8, r8, #0x1 + str r8, [r4, #MMDC0_MAPSR] + + /* disable MMDC power down timer. */ + ldr r8, [r4, #MMDC0_MDPDC] + bic r8, r8, #(0xff << 8) + str r8, [r4, #MMDC0_MDPDC] + + /* delay for a while */ + ldr r8, =4 + do_delay + + /* set CON_REG */ + ldr r8, =0x8000 + str r8, [r4, #MMDC0_MDSCR] +poll_conreq_set_1: + ldr r8, [r4, #MMDC0_MDSCR] + and r8, r8, #(0x4 << 12) + cmp r8, #(0x4 << 12) + bne poll_conreq_set_1 + + /* + * if requested frequency is greater than + * 300MHz go to DLL on mode. + */ + ldr r8, [r0, #BUSFREQ_INFO_FREQ_OFFSET] + ldr r9, =300000000 + cmp r8, r9 + bge dll_on_mode + +dll_off_mode: + /* if DLL is currently on, turn it off. */ + cmp r2, #1 + beq continue_dll_off_1 + + ldr r8, =0x00018031 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x00018039 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =10 + do_delay + +continue_dll_off_1: + /* set DVFS - enter self refresh mode */ + ldr r8, [r4, #MMDC0_MAPSR] + orr r8, r8, #(1 << 21) + str r8, [r4, #MMDC0_MAPSR] + + /* de-assert con_req */ + mov r8, #0x0 + str r8, [r4, #MMDC0_MDSCR] + +poll_dvfs_set_1: + ldr r8, [r4, #MMDC0_MAPSR] + and r8, r8, #(1 << 25) + cmp r8, #(1 << 25) + bne poll_dvfs_set_1 + + ldr r8, [r0, #BUSFREQ_INFO_FREQ_OFFSET] + ldr r9, =24000000 + cmp r8, r9 + beq switch_freq_24 + + switch_to_50MHz + b continue_dll_off_2 + +switch_freq_24: + switch_to_24MHz + +continue_dll_off_2: + /* set SBS - block ddr accesses */ + ldr r8, [r4, #MMDC0_MADPCR0] + orr r8, r8, #(1 << 8) + str r8, [r4, #MMDC0_MADPCR0] + + /* clear DVFS - exit from self refresh mode */ + ldr r8, [r4, #MMDC0_MAPSR] + bic r8, r8, #(1 << 21) + str r8, [r4, #MMDC0_MAPSR] + +poll_dvfs_clear_1: + ldr r8, [r4, #MMDC0_MAPSR] + and r8, r8, #(1 << 25) + cmp r8, #(1 << 25) + beq poll_dvfs_clear_1 + + /* if DLL was previously on, continue DLL off routine. */ + cmp r2, #1 + beq continue_dll_off_3 + + ldr r8, =0x00018031 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x00018039 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x04208030 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x04208038 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x00088032 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x0008803A + str r8, [r4, #MMDC0_MDSCR] + + /* delay for a while. */ + ldr r8, =4 + do_delay + + ldr r8, [r4, #MMDC0_MDCF0] + bic r8, r8, #0xf + orr r8, r8, #0x3 + str r8, [r4, #MMDC0_MDCF0] + + ldr r8, [r4, #MMDC0_MDCF1] + bic r8, r8, #0x7 + orr r8, r8, #0x4 + str r8, [r4, #MMDC0_MDCF1] + + ldr r8, [r4, #MMDC0_MDMISC] + bic r8, r8, #(0x3 << 16) /* walat = 0x1 */ + orr r8, r8, #(0x1 << 16) + bic r8, r8, #(0x7 << 6) /* ralat = 0x2 */ + orr r8, r8, #(0x2 << 6) + str r8, [r4, #MMDC0_MDMISC] + + /* enable dqs pull down in the IOMUX. */ + ldr r8, [r3] + add r3, r3, #8 + ldr r9, =0x3028 +update_iomux: + ldr r10, [r3] + ldr r11, [r6, r10] + bic r11, r11, r9 + orr r11, r11, #(0x3 << 12) + orr r11, r11, #0x28 + str r11, [r6, r10] + add r3, r3, #8 + sub r8, r8, #1 + cmp r8, #0 + bgt update_iomux + + /* ODT disabled. */ + ldr r8, =0x0 + str r8, [r4, #MMDC0_MPODTCTRL] + + /* DQS gating disabled. */ + ldr r8, [r4, #MMDC0_MPDGCTRL0] + orr r8, r8, #(1 << 29) + str r8, [r4, #MMDC0_MPDGCTRL0] + + /* Add workaround for ERR005778.*/ + /* double the original MU_UNIT_DEL_NUM. */ + ldr r8, [r0, #BUSFREQ_INFO_MU_DELAY_OFFSET] + lsl r8, r8, #1 + + /* Bypass the automatic MU by setting the mu_byp_en */ + ldr r10, [r4, #MMDC0_MPMUR0] + orr r10, r10, #0x400 + /* Set the MU_BYP_VAL */ + orr r10, r10, r8 + str r10, [r4, #MMDC0_MPMUR0] + + /* Now perform a force measure */ + ldr r8, [r4, #MMDC0_MPMUR0] + orr r8, r8, #0x800 + str r8, [r4, #MMDC0_MPMUR0] + /* Wait for FRC_MSR to clear. */ +1: + ldr r8, [r4, #MMDC0_MPMUR0] + and r8, r8, #0x800 + cmp r8, #0x0 + bne 1b + +continue_dll_off_3: + /* clear SBS - unblock accesses to DDR. */ + ldr r8, [r4, #MMDC0_MADPCR0] + bic r8, r8, #(0x1 << 8) + str r8, [r4, #MMDC0_MADPCR0] + + mov r8, #0x0 + str r8, [r4, #MMDC0_MDSCR] +poll_conreq_clear_1: + ldr r8, [r4, #MMDC0_MDSCR] + and r8, r8, #(0x4 << 12) + cmp r8, #(0x4 << 12) + beq poll_conreq_clear_1 + + b done + +dll_on_mode: + /* assert DVFS - enter self refresh mode. */ + ldr r8, [r4, #MMDC0_MAPSR] + orr r8, r8, #(1 << 21) + str r8, [r4, #MMDC0_MAPSR] + + /* de-assert CON_REQ. */ + mov r8, #0x0 + str r8, [r4, #MMDC0_MDSCR] + + /* poll DVFS ack. */ +poll_dvfs_set_2: + ldr r8, [r4, #MMDC0_MAPSR] + and r8, r8, #(1 << 25) + cmp r8, #(1 << 25) + bne poll_dvfs_set_2 + + switch_to_400MHz + + /* set SBS step-by-step mode. */ + ldr r8, [r4, #MMDC0_MADPCR0] + orr r8, r8, #(1 << 8) + str r8, [r4, #MMDC0_MADPCR0] + + /* clear DVFS - exit self refresh mode. */ + ldr r8, [r4, #MMDC0_MAPSR] + bic r8, r8, #(1 << 21) + str r8, [r4, #MMDC0_MAPSR] + +poll_dvfs_clear_2: + ldr r8, [r4, #MMDC0_MAPSR] + ands r8, r8, #(1 << 25) + bne poll_dvfs_clear_2 + + /* if DLL is currently off, turn it back on. */ + cmp r2, #0 + beq update_calibration_only + + /* issue zq calibration command */ + ldr r8, [r4, #MMDC0_MPZQHWCTRL] + orr r8, r8, #0x3 + str r8, [r4, #MMDC0_MPZQHWCTRL] + + /* enable DQS gating. */ + ldr r10, =MMDC0_MPDGCTRL0 + ldr r8, [r4, r10] + bic r8, r8, #(1 << 29) + str r8, [r4, r10] + + /* Now perform a force measure */ + ldr r8, =0x00000800 + str r8, [r4, #MMDC0_MPMUR0] + /* Wait for FRC_MSR to clear. */ +1: + ldr r8, [r4, #MMDC0_MPMUR0] + and r8, r8, #0x800 + cmp r8, #0x0 + bne 1b + + /* disable dqs pull down in the IOMUX. */ + ldr r8, [r3] + add r3, r3, #8 +update_iomux1: + ldr r10, [r3, #0x0] + ldr r11, [r3, #0x4] + str r11, [r6, r10] + add r3, r3, #8 + sub r8, r8, #1 + cmp r8, #0 + bgt update_iomux1 + + /* config MMDC timings to 400MHz. */ + ldr r1, [r0, #BUSFREQ_INFO_DDR_SETTINGS_OFFSET] + ldr r7, [r1] + add r1, r1, #8 + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + /* configure ddr devices to dll on, odt. */ + ldr r8, =0x00028031 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x00028039 + str r8, [r4, #MMDC0_MDSCR] + + /* delay for while. */ + ldr r8, =4 + do_delay + + /* reset dll. */ + ldr r8, =0x09208030 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x09208038 + str r8, [r4, #MMDC0_MDSCR] + + /* delay for while. */ + ldr r8, =100 + do_delay + + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + ldr r8, =0x00428031 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x00428039 + str r8, [r4, #MMDC0_MDSCR] + + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + /* issue a zq command. */ + ldr r8, =0x04008040 + str r8, [r4, #MMDC0_MDSCR] + + ldr r8, =0x04008048 + str r8, [r4, #MMDC0_MDSCR] + + /* MMDC ODT enable. */ + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + + /* delay for while. */ + ldr r8, =40 + do_delay + + /* enable MMDC power down timer. */ + ldr r8, [r4, #MMDC0_MDPDC] + orr r8, r8, #(0x55 << 8) + str r8, [r4, #MMDC0_MDPDC] + + b update_calibration + +update_calibration_only: + ldr r8, [r1] + sub r8, r8, #7 + add r1, r1, #64 + b update_calib + +update_calibration: + /* write the new calibration values. */ + mov r8, r7 + sub r8, r8, #7 + +update_calib: + ldr r10, [r1, #0x0] + ldr r11, [r1, #0x4] + str r11, [r4, r10] + add r1, r1, #8 + sub r8, r8, #1 + cmp r8, #0 + bgt update_calib + + /* perform a force measurement. */ + ldr r8, =0x800 + str r8, [r4, #MMDC0_MPMUR0] + /* Wait for FRC_MSR to clear. */ +1: + ldr r8, [r4, #MMDC0_MPMUR0] + and r8, r8, #0x800 + cmp r8, #0x0 + bne 1b + + /* clear SBS - unblock DDR accesses. */ + ldr r8, [r4, #MMDC0_MADPCR0] + bic r8, r8, #(1 << 8) + str r8, [r4, #MMDC0_MADPCR0] + + mov r8, #0x0 + str r8, [r4, #MMDC0_MDSCR] +poll_conreq_clear_2: + ldr r8, [r4, #MMDC0_MDSCR] + and r8, r8, #(0x4 << 12) + cmp r8, #(0x4 << 12) + beq poll_conreq_clear_2 + +done: + + /* MMDC0_MAPSR adopt power down enable. */ + ldr r8, [r4, #MMDC0_MAPSR] + bic r8, r8, #0x01 + str r8, [r4, #MMDC0_MAPSR] + + is_ca7 + beq skip_enable_l2 + +#ifdef CONFIG_CACHE_L2X0 + /* Unlock L2. */ + ldr r8, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + ldr r9, [r8, #PL310_AUX_CTRL] + tst r9, #PL310_AUX_16WAY_BIT + mov r10, #PL310_LOCKDOWN_NBREGS + mov r9, #0x00 /* 8 ways mask */ + orrne r9, #0x0000 /* 16 ways mask */ + add r11, r8, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r9, [r11], #PL310_LOCKDOWN_SZREG + str r9, [r11], #PL310_LOCKDOWN_SZREG + subs r10, r10, #1 + bne 1b + +#endif + +skip_enable_l2: + /* Enable L1 data cache. */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #0x4 + mcr p15, 0, r7, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #0x800 + mcr p15, 0, r7, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r7, =0x0 + mcr p15, 0, r7, c7, c1, 6 + + /* restore registers */ + ldmfd sp!, {r4 - r11} + mov pc, lr + + /* + * Add ltorg here to ensure that all + * literals are stored here and are + * within the text space. + */ + .ltorg +imx6_up_ddr3_freq_change_end: +ENDPROC(imx6_up_ddr3_freq_change) diff --git a/arch/arm/mach-imx/ddr3_freq_imx7d.S b/arch/arm/mach-imx/ddr3_freq_imx7d.S new file mode 100644 index 000000000000..9342e0d83f5e --- /dev/null +++ b/arch/arm/mach-imx/ddr3_freq_imx7d.S @@ -0,0 +1,586 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include "hardware.h" + +#define DDRC_MSTR 0x0 +#define DDRC_STAT 0x4 +#define DDRC_MRCTRL0 0x10 +#define DDRC_MRCTRL1 0x14 +#define DDRC_MRSTAT 0x18 +#define DDRC_PWRCTL 0x30 +#define DDRC_RFSHCTL3 0x60 +#define DDRC_RFSHTMG 0x64 +#define DDRC_DBG1 0x304 +#define DDRC_SWCTL 0x320 +#define DDRC_SWSTAT 0x324 +#define DDRC_PSTAT 0x3fc +#define DDRC_PCTRL_0 0x490 +#define DDRC_ZQCTL0 0x180 +#define DDRC_DFIMISC 0x1b0 +#define DDRC_DBGCAM 0x308 +#define DDRPHY_LP_CON0 0x18 +#define IOMUXC_GPR8 0x20 +#define DDRPHY_MDLL_CON0 0xb0 +#define DDRPHY_MDLL_CON1 0xb4 +#define DDRPHY_OFFSETD_CON0 0x50 +#define DDRPHY_OFFSETR_CON0 0x20 +#define DDRPHY_OFFSETR_CON1 0x24 +#define DDRPHY_OFFSETR_CON2 0x28 +#define DDRPHY_OFFSETW_CON0 0x30 +#define DDRPHY_OFFSETW_CON1 0x34 +#define DDRPHY_OFFSETW_CON2 0x38 +#define DDRPHY_CA_WLDSKEW_CON0 0x6c +#define DDRPHY_CA_DSKEW_CON0 0x7c +#define DDRPHY_CA_DSKEW_CON1 0x80 +#define DDRPHY_CA_DSKEW_CON2 0x84 + +#define ANADIG_DIGPROG 0x800 + + .align 3 + + .macro switch_to_below_100m + + ldr r7, =0x2 + str r7, [r4, #DDRC_DBG1] + + ldr r6, =0x36000000 +1: + ldr r7, [r4, #DDRC_DBGCAM] + and r7, r7, r6 + cmp r7, r6 + bne 1b + + ldr r6, =0x1 +2: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 2b + + ldr r7, =0x10f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x0 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800010f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r6, =0x1 +3: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 3b + + ldr r7, =0x20f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x8 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800020f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r6, =0x1 +4: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 4b + + ldr r7, =0x10f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x1 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800010f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r7, =0x20 + str r7, [r4, #DDRC_PWRCTL] + + ldr r6, =0x23 +5: + ldr r7, [r4, #DDRC_STAT] + and r7, r7, r6 + cmp r7, r6 + bne 5b + + ldr r7, =0x0 + str r7, [r4, #DDRC_SWCTL] + + ldr r7, =0x03048001 + str r7, [r4, #DDRC_MSTR] + + ldr r7, =0x1 + str r7, [r4, #DDRC_SWCTL] + + ldr r6, =0x1 +6: + ldr r7, [r4, #DDRC_SWSTAT] + and r7, r7, r6 + cmp r7, r6 + bne 6b + + ldr r7, =0x10010100 + str r7, [r5, #0x4] + + ldr r6, =24000000 + cmp r0, r6 + beq 25f + + ldr r7, =0x000B000D + str r7,[r4, #DDRC_RFSHTMG] + b 7f + +25: + ldr r7, =0x00030004 + str r7,[r4, #DDRC_RFSHTMG] + + /* dram alt sel set to OSC */ + ldr r7, =0x10000000 + ldr r8, =0xa080 + str r7, [r2, r8] + /* dram root set to from dram alt, div by 1 */ + ldr r7, =0x11000000 + ldr r8, =0x9880 + str r7, [r2, r8] + b 8f +7: + /* dram alt sel set to pfd0_392m */ + ldr r7, =0x15000000 + ldr r8, =0xa080 + str r7, [r2, r8] + /* dram root set to from dram alt, div by 4 */ + ldr r7, =0x11000003 + ldr r8, =0x9880 + str r7, [r2, r8] +8: + ldr r7, =0x202ffd0 + str r7, [r5, #DDRPHY_MDLL_CON0] + + ldr r7, =0x1000007f + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r7, =0x7f7f7f7f + str r7, [r5, #DDRPHY_OFFSETR_CON0] + str r7, [r5, #DDRPHY_OFFSETR_CON1] + ldr r7, =0x7f + str r7, [r5, #DDRPHY_OFFSETR_CON2] + + ldr r7, =0x7f7f7f7f + str r7, [r5, #DDRPHY_OFFSETW_CON0] + str r7, [r5, #DDRPHY_OFFSETW_CON1] + ldr r7, =0x7f + str r7, [r5, #DDRPHY_OFFSETW_CON2] + + ldr r7, [r9, #ANADIG_DIGPROG] + and r7, r7, #0x11 + cmp r7, #0x11 + bne 20f + + ldr r7, =0x0 + str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0] + ldr r7, =0x60606060 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + ldr r7, =0x00006060 + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] + b 21f +20: + ldr r7, =0x0 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] +21: + ldr r7, =0x1100007f + str r7, [r5, #DDRPHY_OFFSETD_CON0] + ldr r7, =0x1000007f + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r7, =0x0 + str r7, [r4, #DDRC_PWRCTL] + + ldr r6, =0x1 +9: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 9b + + ldr r7, =0xf0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x820 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800000f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r6, =0x1 +10: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 10b + + ldr r7, =0x800020 + str r7, [r4, #DDRC_ZQCTL0] + + ldr r7, =0x0 + str r7, [r4, #DDRC_DBG1] + + /* enable auto self-refresh */ + ldr r7, [r4, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r4, #DDRC_PWRCTL] + + .endm + + .macro switch_to_533m + + ldr r7, =0x2 + str r7, [r4, #DDRC_DBG1] + + ldr r7, =0x78 + str r7, [r3, #IOMUXC_GPR8] + orr r7, r7, #0x100 + str r7, [r3, #IOMUXC_GPR8] + + ldr r6, =0x30000000 +11: + ldr r7, [r4, #DDRC_DBGCAM] + and r7, r7, r6 + cmp r7, r6 + bne 11b + + ldr r6, =0x1 +12: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 12b + + ldr r7, =0x10f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x1 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800010f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r7, =0x20 + str r7, [r4, #DDRC_PWRCTL] + + ldr r6, =0x23 +13: + ldr r7, [r4, #DDRC_STAT] + and r7, r7, r6 + cmp r7, r6 + bne 13b + + ldr r7, =0x03040001 + str r7, [r4, #DDRC_MSTR] + + ldr r7, =0x40800020 + str r7, [r4, #DDRC_ZQCTL0] + + + ldr r7, =0x10210100 + str r7, [r5, #0x4] + + ldr r7, =0x00040046 + str r7, [r4, #DDRC_RFSHTMG] + + /* dram root set to from dram main, div by 2 */ + ldr r7, =0x10000001 + ldr r8, =0x9880 + str r7, [r2, r8] + + ldr r7, =0x1010007e + str r7, [r5, #DDRPHY_MDLL_CON0] + + ldr r7, =0x10000008 + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r7, =0x08080808 + str r7, [r5, #DDRPHY_OFFSETR_CON0] + str r7, [r5, #DDRPHY_OFFSETR_CON1] + ldr r7, =0x8 + str r7, [r5, #DDRPHY_OFFSETR_CON2] + + ldr r7, =0x08080808 + str r7, [r5, #DDRPHY_OFFSETW_CON0] + str r7, [r5, #DDRPHY_OFFSETW_CON1] + ldr r7, =0x8 + str r7, [r5, #DDRPHY_OFFSETW_CON2] + + ldr r7, [r9, #ANADIG_DIGPROG] + and r7, r7, #0x11 + cmp r7, #0x11 + bne 22f + + ldr r7, =0x40404040 + str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0] + ldr r7, =0x18181818 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + ldr r7, =0x40401818 + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] + b 23f +22: + ldr r7, =0x0 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] +23: + ldr r7, =0x11000008 + str r7, [r5, #DDRPHY_OFFSETD_CON0] + ldr r7, =0x10000008 + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r6, =0x4 +14: + ldr r7, [r5, #DDRPHY_MDLL_CON1] + and r7, r7, r6 + cmp r7, r6 + bne 14b + + ldr r7, =0x1 + str r7, [r4, #DDRC_RFSHCTL3] + ldr r7, =0x3 + str r7, [r4, #DDRC_RFSHCTL3] + + ldr r7, =0x0 + str r7, [r4, #DDRC_PWRCTL] + + ldr r6, =0x1 +15: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 15b + + ldr r7, =0x10f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x0 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800010f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r6, =0x1 +16: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 16b + + ldr r7, =0xf0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x930 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800000f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r7, =0x0 + str r7, [r4, #DDRC_RFSHCTL3] + ldr r7, =0x2 + str r7, [r4, #DDRC_RFSHCTL3] + + ldr r6, =0x1 +17: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 17b + + ldr r7, =0xf0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x930 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800000f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r6, =0x1 +18: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 18b + + ldr r7, =0x20f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x408 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800020f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r6, =0x1 +19: + ldr r7, [r4, #DDRC_MRSTAT] + and r7, r7, r6 + cmp r7, r6 + beq 19b + + ldr r7, =0x10f0 + str r7, [r4, #DDRC_MRCTRL0] + ldr r7, =0x4 + str r7, [r4, #DDRC_MRCTRL1] + ldr r7, =0x800010f0 + str r7, [r4, #DDRC_MRCTRL0] + + ldr r7, =0x0 + str r7, [r4, #DDRC_DBG1] + + /* enable auto self-refresh */ + ldr r7, [r4, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r4, #DDRC_PWRCTL] + + .endm + +ENTRY(imx7d_ddr3_freq_change) + push {r2 - r9} + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + ldr r2, =IMX_IO_P2V(MX7D_CCM_BASE_ADDR) + ldr r3, =IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR) + ldr r4, =IMX_IO_P2V(MX7D_DDRC_BASE_ADDR) + ldr r5, =IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR) + ldr r9, =IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR) + + ldr r6, =100000000 + cmp r0, r6 + bgt set_to_533m + +set_to_below_100m: + switch_to_below_100m + b done + +set_to_533m: + switch_to_533m + b done + +done: + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + dsb + isb + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + /* Restore registers */ + pop {r2 - r9} + mov pc, lr + .ltorg +ENDPROC(imx7d_ddr3_freq_change) diff --git a/arch/arm/mach-imx/ddrc.c b/arch/arm/mach-imx/ddrc.c new file mode 100644 index 000000000000..9c7f627d465e --- /dev/null +++ b/arch/arm/mach-imx/ddrc.c @@ -0,0 +1,86 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * 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/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> + +#include "hardware.h" + +#define DDRC_MSTR 0x0 +#define BM_DDRC_MSTR_DDR3 0x1 +#define BM_DDRC_MSTR_LPDDR2 0x4 +#define BM_DDRC_MSTR_LPDDR3 0x8 + +static int ddr_type; + +static int imx_ddrc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + void __iomem *ddrc_base, *reg; + u32 val; + + ddrc_base = of_iomap(np, 0); + WARN_ON(!ddrc_base); + + reg = ddrc_base + DDRC_MSTR; + /* Get ddr type */ + val = readl_relaxed(reg); + val &= (BM_DDRC_MSTR_DDR3 | BM_DDRC_MSTR_LPDDR2 + | BM_DDRC_MSTR_LPDDR3); + + switch (val) { + case BM_DDRC_MSTR_DDR3: + pr_info("DDR type is DDR3!\n"); + ddr_type = IMX_DDR_TYPE_DDR3; + break; + case BM_DDRC_MSTR_LPDDR2: + pr_info("DDR type is LPDDR2!\n"); + ddr_type = IMX_DDR_TYPE_LPDDR2; + break; + case BM_DDRC_MSTR_LPDDR3: + pr_info("DDR type is LPDDR3!\n"); + ddr_type = IMX_DDR_TYPE_LPDDR3; + break; + default: + break; + } + + return 0; +} + +int imx_ddrc_get_ddr_type(void) +{ + return ddr_type; +} + +static struct of_device_id imx_ddrc_dt_ids[] = { + { .compatible = "fsl,imx7-ddrc", }, + { /* sentinel */ } +}; + +static struct platform_driver imx_ddrc_driver = { + .driver = { + .name = "imx-ddrc", + .owner = THIS_MODULE, + .of_match_table = imx_ddrc_dt_ids, + }, + .probe = imx_ddrc_probe, +}; + +static int __init imx_ddrc_init(void) +{ + return platform_driver_register(&imx_ddrc_driver); +} +postcore_initcall(imx_ddrc_init); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index b5b557fe2c49..838d93381c07 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -14,22 +14,153 @@ #include "common.h" #include "hardware.h" -#define GPC_CNTR 0x0 +#define GPC_CNTR 0x000 +#define GPC_CNTR_L2_PGE 22 + #define GPC_IMR1 0x008 +#define GPC_PGC_MF_PDN 0x220 #define GPC_PGC_CPU_PDN 0x2a0 #define GPC_PGC_CPU_PUPSCR 0x2a4 #define GPC_PGC_CPU_PDNSCR 0x2a8 #define GPC_PGC_SW2ISO_SHIFT 0x8 #define GPC_PGC_SW_SHIFT 0x0 - -#define GPC_CNTR_L2_PGE_SHIFT 22 +#define GPC_M4_LPSR 0x2c +#define GPC_M4_LPSR_M4_SLEEPING_SHIFT 4 +#define GPC_M4_LPSR_M4_SLEEPING_MASK 0x1 +#define GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK 0x1 +#define GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT 0 +#define GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_MASK 0x1 +#define GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_SHIFT 1 + +#define GPC_PGC_CPU_SW_SHIFT 0 +#define GPC_PGC_CPU_SW_MASK 0x3f +#define GPC_PGC_CPU_SW2ISO_SHIFT 8 +#define GPC_PGC_CPU_SW2ISO_MASK 0x3f #define IMR_NUM 4 #define GPC_MAX_IRQS (IMR_NUM * 32) +/* for irq #74 and #75 */ +#define GPC_USB_VBUS_WAKEUP_IRQ_MASK 0xc00 + +/* for irq #150 and #151 */ +#define GPC_ENET_WAKEUP_IRQ_MASK 0xC00000 + static void __iomem *gpc_base; static u32 gpc_wake_irqs[IMR_NUM]; static u32 gpc_saved_imrs[IMR_NUM]; +static u32 gpc_mf_irqs[IMR_NUM]; +static u32 gpc_mf_request_on[IMR_NUM]; +static DEFINE_SPINLOCK(gpc_lock); + +void imx_gpc_add_m4_wake_up_irq(u32 hwirq, bool enable) +{ + unsigned int idx = hwirq / 32; + unsigned long flags; + u32 mask; + + /* Sanity check for SPI irq */ + if (hwirq < 32) + return; + + mask = 1 << hwirq % 32; + spin_lock_irqsave(&gpc_lock, flags); + gpc_wake_irqs[idx] = enable ? gpc_wake_irqs[idx] | mask : + gpc_wake_irqs[idx] & ~mask; + spin_unlock_irqrestore(&gpc_lock, flags); +} + +void imx_gpc_hold_m4_in_sleep(void) +{ + int val; + unsigned long timeout = jiffies + msecs_to_jiffies(500); + + /* wait M4 in wfi before asserting hold request */ + while (!imx_gpc_is_m4_sleeping()) + if (time_after(jiffies, timeout)) + pr_err("M4 is NOT in expected sleep!\n"); + + val = readl_relaxed(gpc_base + GPC_M4_LPSR); + val &= ~(GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK << + GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT); + writel_relaxed(val, gpc_base + GPC_M4_LPSR); + + timeout = jiffies + msecs_to_jiffies(500); + while (readl_relaxed(gpc_base + GPC_M4_LPSR) + & (GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_MASK << + GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_SHIFT)) + if (time_after(jiffies, timeout)) + pr_err("Wait M4 hold ack timeout!\n"); +} + +void imx_gpc_release_m4_in_sleep(void) +{ + int val; + + val = readl_relaxed(gpc_base + GPC_M4_LPSR); + val |= GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK << + GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT; + writel_relaxed(val, gpc_base + GPC_M4_LPSR); +} + +unsigned int imx_gpc_is_m4_sleeping(void) +{ + if (readl_relaxed(gpc_base + GPC_M4_LPSR) & + (GPC_M4_LPSR_M4_SLEEPING_MASK << + GPC_M4_LPSR_M4_SLEEPING_SHIFT)) + return 1; + + return 0; +} + +bool imx_gpc_usb_wakeup_enabled(void) +{ + if (!(cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll())) + return false; + + /* + * for SoC later than i.MX6SX, USB vbus wakeup + * only needs weak 2P5 on, stop_mode_config is + * NOT needed, so we check if is USB vbus wakeup + * is enabled(assume irq #74 and #75) to decide + * if to keep weak 2P5 on. + */ + if (gpc_wake_irqs[1] & GPC_USB_VBUS_WAKEUP_IRQ_MASK) + return true; + + return false; +} + +bool imx_gpc_enet_wakeup_enabled(void) +{ + if (!cpu_is_imx6q()) + return false; + + if (gpc_wake_irqs[3] & GPC_ENET_WAKEUP_IRQ_MASK) + return true; + + return false; +} + +unsigned int imx_gpc_is_mf_mix_off(void) +{ + return readl_relaxed(gpc_base + GPC_PGC_MF_PDN); +} + +static void imx_gpc_mf_mix_off(void) +{ + int i; + + for (i = 0; i < IMR_NUM; i++) + if (((gpc_wake_irqs[i] | gpc_mf_request_on[i]) & + gpc_mf_irqs[i]) != 0) + return; + + pr_info("Turn off M/F mix!\n"); + /* turn off mega/fast mix */ + writel_relaxed(0x1, gpc_base + GPC_PGC_MF_PDN); +} void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw) { @@ -53,9 +184,9 @@ void imx_gpc_set_l2_mem_power_in_lpm(bool power_off) u32 val; val = readl_relaxed(gpc_base + GPC_CNTR); - val &= ~(1 << GPC_CNTR_L2_PGE_SHIFT); + val &= ~(1 << GPC_CNTR_L2_PGE); if (power_off) - val |= 1 << GPC_CNTR_L2_PGE_SHIFT; + val |= 1 << GPC_CNTR_L2_PGE; writel_relaxed(val, gpc_base + GPC_CNTR); } @@ -64,6 +195,11 @@ void imx_gpc_pre_suspend(bool arm_power_off) void __iomem *reg_imr1 = gpc_base + GPC_IMR1; int i; + /* power down the mega-fast power domain */ + if ((cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) && arm_power_off) + imx_gpc_mf_mix_off(); + /* Tell GPC to power off ARM core when suspend */ if (arm_power_off) imx_gpc_set_arm_power_in_lpm(arm_power_off); @@ -81,6 +217,10 @@ void imx_gpc_post_resume(void) /* Keep ARM core powered on for other low-power modes */ imx_gpc_set_arm_power_in_lpm(false); + /* Keep M/F mix powered on for other low-power modes */ + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) + writel_relaxed(0x0, gpc_base + GPC_PGC_MF_PDN); for (i = 0; i < IMR_NUM; i++) writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); @@ -89,11 +229,14 @@ void imx_gpc_post_resume(void) static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) { unsigned int idx = d->hwirq / 32; + unsigned long flags; u32 mask; mask = 1 << d->hwirq % 32; + spin_lock_irqsave(&gpc_lock, flags); gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : gpc_wake_irqs[idx] & ~mask; + spin_unlock_irqrestore(&gpc_lock, flags); /* * Do *not* call into the parent, as the GIC doesn't have any @@ -225,11 +368,78 @@ static const struct irq_domain_ops imx_gpc_domain_ops = { .free = irq_domain_free_irqs_common, }; +int imx_gpc_mf_power_on(unsigned int irq, unsigned int on) +{ + struct irq_desc *d = irq_to_desc(irq); + unsigned int idx = d->irq_data.hwirq / 32; + unsigned long flags; + u32 mask; + + mask = 1 << (d->irq_data.hwirq % 32); + spin_lock_irqsave(&gpc_lock, flags); + gpc_mf_request_on[idx] = on ? gpc_mf_request_on[idx] | mask : + gpc_mf_request_on[idx] & ~mask; + spin_unlock_irqrestore(&gpc_lock, flags); + + return 0; +} + +int imx_gpc_mf_request_on(unsigned int irq, unsigned int on) +{ + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) + return imx_gpc_mf_power_on(irq, on); + else if (cpu_is_imx7d()) + return imx_gpcv2_mf_power_on(irq, on); + else + return 0; +} +EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on); + +void imx_gpc_switch_pupscr_clk(bool flag) +{ + static u32 pupscr_sw2iso, pupscr_sw; + u32 ratio, pupscr = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR); + + if (flag) { + /* save the init clock setting IPG/2048 for IPG@66Mhz */ + pupscr_sw2iso = (pupscr >> GPC_PGC_CPU_SW2ISO_SHIFT) & + GPC_PGC_CPU_SW2ISO_MASK; + pupscr_sw = (pupscr >> GPC_PGC_CPU_SW_SHIFT) & + GPC_PGC_CPU_SW_MASK; + /* + * i.MX6UL TO1.0 ARM power up uses IPG/2048 as clock source, + * from TO1.1, PGC_CPU_PUPSCR bit [5] is re-defined to switch + * clock to IPG/32, enable this bit to speed up the ARM power + * up process in low power idle case(IPG@1.5Mhz). So the sw and + * sw2iso need to be adjusted as below: + * sw_new(sw2iso_new) = (2048 * 1.5 / 66 * 32) * sw(sw2iso) + */ + ratio = 3072 / (66 * 32); + pupscr &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT | + GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT); + pupscr |= (ratio * pupscr_sw + 1) << GPC_PGC_CPU_SW_SHIFT | + 1 << 5 | (ratio * pupscr_sw2iso + 1) << + GPC_PGC_CPU_SW2ISO_SHIFT; + writel_relaxed(pupscr, gpc_base + GPC_PGC_CPU_PUPSCR); + } else { + /* restore back after exit from low power idle */ + pupscr &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT | + GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT); + pupscr |= pupscr_sw << GPC_PGC_CPU_SW_SHIFT | + pupscr_sw2iso << GPC_PGC_CPU_SW2ISO_SHIFT; + writel_relaxed(pupscr, gpc_base + GPC_PGC_CPU_PUPSCR); + } +} + static int __init imx_gpc_init(struct device_node *node, struct device_node *parent) { struct irq_domain *parent_domain, *domain; int i; + u32 val; + u32 cpu_pupscr_sw2iso, cpu_pupscr_sw; + u32 cpu_pdnscr_iso2sw, cpu_pdnscr_iso; if (!parent) { pr_err("%pOF: no parent, giving up\n", node); @@ -258,12 +468,70 @@ static int __init imx_gpc_init(struct device_node *node, for (i = 0; i < IMR_NUM; i++) writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); + /* Read supported wakeup source in M/F domain */ + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || + cpu_is_imx6ulz() || cpu_is_imx6sll()) { + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0, + &gpc_mf_irqs[0]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1, + &gpc_mf_irqs[1]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 2, + &gpc_mf_irqs[2]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 3, + &gpc_mf_irqs[3]); + if (!(gpc_mf_irqs[0] | gpc_mf_irqs[1] | + gpc_mf_irqs[2] | gpc_mf_irqs[3])) + pr_info("No wakeup source in Mega/Fast domain found!\n"); + } + + /* clear the L2_PGE bit on i.MX6SLL */ + if (cpu_is_imx6sll()) { + val = readl_relaxed(gpc_base + GPC_CNTR); + val &= ~(1 << GPC_CNTR_L2_PGE); + writel_relaxed(val, gpc_base + GPC_CNTR); + } + /* * Clear the OF_POPULATED flag set in of_irq_init so that * later the GPC power domain driver will not be skipped. */ of_node_clear_flag(node, OF_POPULATED); + /* + * If there are CPU isolation timing settings in dts, + * update them according to dts, otherwise, keep them + * with default value in registers. + */ + cpu_pupscr_sw2iso = cpu_pupscr_sw = + cpu_pdnscr_iso2sw = cpu_pdnscr_iso = 0; + + /* Read CPU isolation setting for GPC */ + of_property_read_u32(node, "fsl,cpu_pupscr_sw2iso", &cpu_pupscr_sw2iso); + of_property_read_u32(node, "fsl,cpu_pupscr_sw", &cpu_pupscr_sw); + of_property_read_u32(node, "fsl,cpu_pdnscr_iso2sw", &cpu_pdnscr_iso2sw); + of_property_read_u32(node, "fsl,cpu_pdnscr_iso", &cpu_pdnscr_iso); + + /* Return if no property found in dtb */ + if ((cpu_pupscr_sw2iso | cpu_pupscr_sw + | cpu_pdnscr_iso2sw | cpu_pdnscr_iso) == 0) + return 0; + + /* Update CPU PUPSCR timing if it is defined in dts */ + val = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR); + val &= ~(GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT); + val &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT); + val |= cpu_pupscr_sw2iso << GPC_PGC_CPU_SW2ISO_SHIFT; + val |= cpu_pupscr_sw << GPC_PGC_CPU_SW_SHIFT; + writel_relaxed(val, gpc_base + GPC_PGC_CPU_PUPSCR); + + /* Update CPU PDNSCR timing if it is defined in dts */ + val = readl_relaxed(gpc_base + GPC_PGC_CPU_PDNSCR); + val &= ~(GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT); + val &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT); + val |= cpu_pdnscr_iso2sw << GPC_PGC_CPU_SW2ISO_SHIFT; + val |= cpu_pdnscr_iso << GPC_PGC_CPU_SW_SHIFT; + writel_relaxed(val, gpc_base + GPC_PGC_CPU_PDNSCR); + return 0; } IRQCHIP_DECLARE(imx_gpc, "fsl,imx6q-gpc", imx_gpc_init); diff --git a/arch/arm/mach-imx/gpcv2.c b/arch/arm/mach-imx/gpcv2.c new file mode 100644 index 000000000000..3e8ab91cb97f --- /dev/null +++ b/arch/arm/mach-imx/gpcv2.c @@ -0,0 +1,851 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * 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/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/regulator/consumer.h> + +#include "common.h" +#include "hardware.h" + +#define IMR_NUM 4 +#define GPC_MAX_IRQS (IMR_NUM * 32) +#define GPC_LPCR_A7_BSC 0x0 +#define GPC_LPCR_A7_AD 0x4 +#define GPC_LPCR_M4 0x8 +#define GPC_SLPCR 0x14 +#define GPC_MLPCR 0x20 +#define GPC_PGC_ACK_SEL_A7 0x24 +#define GPC_MISC 0x2c +#define GPC_IMR1_CORE0 0x30 +#define GPC_IMR1_CORE1 0x40 +#define GPC_IMR1_M4 0x50 +#define GPC_SLOT0_CFG 0xb0 +#define GPC_PGC_CPU_MAPPING 0xec +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0 +#define GPC_PU_PGC_SW_PUP_REQ 0xf8 +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc +#define GPC_PU_PGC_SW_PDN_REQ 0x104 +#define GPC_GTOR 0x124 +#define GPC_PGC_C0 0x800 +#define GPC_PGC_C0_PUPSCR 0x804 +#define GPC_PGC_SCU_TIMING 0x890 +#define GPC_PGC_C1 0x840 +#define GPC_PGC_C1_PUPSCR 0x844 +#define GPC_PGC_SCU 0x880 +#define GPC_PGC_FM 0xa00 + +#define BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP 0x70000000 +#define BM_LPCR_A7_BSC_CPU_CLK_ON_LPM 0x4000 +#define BM_LPCR_A7_BSC_LPM1 0xc +#define BM_LPCR_A7_BSC_LPM0 0x3 +#define BP_LPCR_A7_BSC_LPM1 2 +#define BP_LPCR_A7_BSC_LPM0 0 +#define BM_LPCR_M4_MASK_DSM_TRIGGER 0x80000000 +#define BM_SLPCR_EN_DSM 0x80000000 +#define BM_SLPCR_RBC_EN 0x40000000 +#define BM_SLPCR_REG_BYPASS_COUNT 0x3f000000 +#define BM_SLPCR_VSTBY 0x4 +#define BM_SLPCR_SBYOS 0x2 +#define BM_SLPCR_BYPASS_PMIC_READY 0x1 +#define BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE 0x10000 +#define BM_LPCR_A7_AD_L2PGE 0x10000 +#define BM_LPCR_A7_AD_EN_C1_PUP 0x800 +#define BM_LPCR_A7_AD_EN_C1_IRQ_PUP 0x400 +#define BM_LPCR_A7_AD_EN_C0_PUP 0x200 +#define BM_LPCR_A7_AD_EN_C0_IRQ_PUP 0x100 +#define BM_LPCR_A7_AD_EN_PLAT_PDN 0x10 +#define BM_LPCR_A7_AD_EN_C1_PDN 0x8 +#define BM_LPCR_A7_AD_EN_C1_WFI_PDN 0x4 +#define BM_LPCR_A7_AD_EN_C0_PDN 0x2 +#define BM_LPCR_A7_AD_EN_C0_WFI_PDN 0x1 + +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2 +#define BM_GPC_PGC_PCG 0x1 +#define BM_GPC_PGC_CORE_PUPSCR 0x7fff80 + +#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK 0x80000000 +#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK 0x8000 +#define BM_GPC_MLPCR_MEMLP_CTL_DIS 0x1 + +#define BP_LPCR_A7_BSC_IRQ_SRC 28 + +#define MAX_SLOT_NUMBER 10 +#define A7_LPM_WAIT 0x5 +#define A7_LPM_STOP 0xa + +enum imx_gpc_slot { + CORE0_A7, + CORE1_A7, + SCU_A7, + FAST_MEGA_MIX, + MIPI_PHY, + PCIE_PHY, + USB_OTG1_PHY, + USB_OTG2_PHY, + USB_HSIC_PHY, + CORE0_M4, +}; + +static void __iomem *gpc_base; +static u32 gpcv2_wake_irqs[IMR_NUM]; +static u32 gpcv2_saved_imrs[IMR_NUM]; +static u32 gpcv2_saved_imrs_m4[IMR_NUM]; +static u32 gpcv2_mf_irqs[IMR_NUM]; +static u32 gpcv2_mf_request_on[IMR_NUM]; +static DEFINE_SPINLOCK(gpcv2_lock); + +void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable) +{ + unsigned int idx = hwirq / 32; + unsigned long flags; + u32 mask; + + /* Sanity check for SPI irq */ + if (hwirq < 32) + return; + + mask = 1 << hwirq % 32; + spin_lock_irqsave(&gpcv2_lock, flags); + gpcv2_wake_irqs[idx] = enable ? gpcv2_wake_irqs[idx] | mask : + gpcv2_wake_irqs[idx] & ~mask; + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on) +{ + unsigned int idx = d->hwirq / 32; + unsigned long flags; + u32 mask; + + BUG_ON(idx >= IMR_NUM); + + mask = 1 << d->hwirq % 32; + spin_lock_irqsave(&gpcv2_lock, flags); + gpcv2_wake_irqs[idx] = on ? gpcv2_wake_irqs[idx] | mask : + gpcv2_wake_irqs[idx] & ~mask; + spin_unlock_irqrestore(&gpcv2_lock, flags); + + return 0; +} + +void imx_gpcv2_mask_all(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + for (i = 0; i < IMR_NUM; i++) { + gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); + writel_relaxed(~0, reg_imr1 + i * 4); + } +} + +void imx_gpcv2_restore_all(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4); +} + +void imx_gpcv2_hwirq_unmask(unsigned int hwirq) +{ + void __iomem *reg; + u32 val; + + reg = gpc_base + GPC_IMR1_CORE0 + (hwirq / 32) * 4; + val = readl_relaxed(reg); + val &= ~(1 << hwirq % 32); + writel_relaxed(val, reg); +} + +void imx_gpcv2_hwirq_mask(unsigned int hwirq) +{ + void __iomem *reg; + u32 val; + + reg = gpc_base + GPC_IMR1_CORE0 + (hwirq / 32) * 4; + val = readl_relaxed(reg); + val |= 1 << (hwirq % 32); + writel_relaxed(val, reg); +} + +static void imx_gpcv2_irq_unmask(struct irq_data *d) +{ + imx_gpcv2_hwirq_unmask(d->hwirq); + irq_chip_unmask_parent(d); +} + +static void imx_gpcv2_irq_mask(struct irq_data *d) +{ + imx_gpcv2_hwirq_mask(d->hwirq); + irq_chip_mask_parent(d); +} + +void imx_gpcv2_set_slot_ack(u32 index, enum imx_gpc_slot m_core, + bool mode, bool ack) +{ + u32 val; + + if (index >= MAX_SLOT_NUMBER) + pr_err("Invalid slot index!\n"); + /* set slot */ + writel_relaxed(readl_relaxed(gpc_base + GPC_SLOT0_CFG + index * 4) | + ((mode + 1) << (m_core * 2)), + gpc_base + GPC_SLOT0_CFG + index * 4); + + if (ack) { + /* set ack */ + val = readl_relaxed(gpc_base + GPC_PGC_ACK_SEL_A7); + /* clear dummy ack */ + val &= ~(1 << (15 + (mode ? 16 : 0))); + val |= 1 << (m_core + (mode ? 16 : 0)); + writel_relaxed(val, gpc_base + GPC_PGC_ACK_SEL_A7); + } +} + +void imx_gpcv2_set_lpm_mode(enum mxc_cpu_pwr_mode mode) +{ + unsigned long flags; + u32 val1, val2; + + spin_lock_irqsave(&gpcv2_lock, flags); + + val1 = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC); + val2 = readl_relaxed(gpc_base + GPC_SLPCR); + + /* all cores' LPM settings must be same */ + val1 &= ~(BM_LPCR_A7_BSC_LPM0 | BM_LPCR_A7_BSC_LPM1); + + val1 |= BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + + val2 &= ~(BM_SLPCR_EN_DSM | BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | + BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY); + /* + * GPC: When improper low-power sequence is used, + * the SoC enters low power mode before the ARM core executes WFI. + * + * Software workaround: + * 1) Software should trigger IRQ #32 (IOMUX) to be always pending + * by setting IOMUX_GPR1_IRQ. + * 2) Software should then unmask IRQ #32 in GPC before setting GPC + * Low-Power mode. + * 3) Software should mask IRQ #32 right after GPC Low-Power mode + * is set. + */ + switch (mode) { + case WAIT_CLOCKED: + imx_gpcv2_hwirq_unmask(0); + break; + case WAIT_UNCLOCKED: + val1 |= A7_LPM_WAIT << BP_LPCR_A7_BSC_LPM0; + val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + imx_gpcv2_hwirq_mask(0); + break; + case STOP_POWER_ON: + val1 |= A7_LPM_STOP << BP_LPCR_A7_BSC_LPM0; + val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + val2 |= BM_SLPCR_EN_DSM; + val2 |= BM_SLPCR_RBC_EN; + val2 |= BM_SLPCR_BYPASS_PMIC_READY; + imx_gpcv2_hwirq_mask(0); + break; + case STOP_POWER_OFF: + val1 |= A7_LPM_STOP << BP_LPCR_A7_BSC_LPM0; + val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + val2 |= BM_SLPCR_EN_DSM; + val2 |= BM_SLPCR_RBC_EN; + val2 |= BM_SLPCR_SBYOS; + val2 |= BM_SLPCR_VSTBY; + val2 |= BM_SLPCR_BYPASS_PMIC_READY; + imx_gpcv2_hwirq_mask(0); + break; + default: + return; + } + writel_relaxed(val1, gpc_base + GPC_LPCR_A7_BSC); + writel_relaxed(val2, gpc_base + GPC_SLPCR); + + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_plat_power_gate_by_lpm(bool pdn) +{ + u32 val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); + + val &= ~(BM_LPCR_A7_AD_EN_PLAT_PDN | BM_LPCR_A7_AD_L2PGE); + if (pdn) + val |= BM_LPCR_A7_AD_EN_PLAT_PDN | BM_LPCR_A7_AD_L2PGE; + + writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); +} + +void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset) +{ + u32 val = readl_relaxed(gpc_base + offset) & (~BM_GPC_PGC_PCG); + + if (enable) + val |= BM_GPC_PGC_PCG; + + writel_relaxed(val, gpc_base + offset); +} + +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) +{ + u32 val = readl_relaxed(gpc_base + (pdn ? + GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)); + + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; + writel_relaxed(val, gpc_base + (pdn ? + GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)); + + while ((readl_relaxed(gpc_base + (pdn ? + GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)) & + BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0) + ; + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); +} + +void imx_gpcv2_set_cpu_power_gate_by_wfi(u32 cpu, bool pdn) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gpcv2_lock, flags); + val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); + + if (cpu == 0) { + if (pdn) { + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0); + val |= BM_LPCR_A7_AD_EN_C0_WFI_PDN | + BM_LPCR_A7_AD_EN_C0_IRQ_PUP; + } else { + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); + val &= ~(BM_LPCR_A7_AD_EN_C0_WFI_PDN | + BM_LPCR_A7_AD_EN_C0_IRQ_PUP); + } + } + if (cpu == 1) { + if (pdn) { + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); + val |= BM_LPCR_A7_AD_EN_C1_WFI_PDN | + BM_LPCR_A7_AD_EN_C1_IRQ_PUP; + } else { + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); + val &= ~(BM_LPCR_A7_AD_EN_C1_WFI_PDN | + BM_LPCR_A7_AD_EN_C1_IRQ_PUP); + } + } + writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_cpu_power_gate_by_lpm(u32 cpu, bool pdn) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gpcv2_lock, flags); + + val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); + if (cpu == 0) { + if (pdn) + val |= BM_LPCR_A7_AD_EN_C0_PDN | + BM_LPCR_A7_AD_EN_C0_PUP; + else + val &= ~(BM_LPCR_A7_AD_EN_C0_PDN | + BM_LPCR_A7_AD_EN_C0_PUP); + } + if (cpu == 1) { + if (pdn) + val |= BM_LPCR_A7_AD_EN_C1_PDN | + BM_LPCR_A7_AD_EN_C1_PUP; + else + val &= ~(BM_LPCR_A7_AD_EN_C1_PDN | + BM_LPCR_A7_AD_EN_C1_PUP); + } + + writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_cpu_power_gate_in_idle(bool pdn) +{ + unsigned long flags; + u32 cpu; + + for_each_possible_cpu(cpu) + imx_gpcv2_set_cpu_power_gate_by_lpm(cpu, pdn); + + spin_lock_irqsave(&gpcv2_lock, flags); + + imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C0); + if (num_online_cpus() > 1) + imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C1); + imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_SCU); + imx_gpcv2_set_plat_power_gate_by_lpm(pdn); + + if (pdn) { + imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false); + if (num_online_cpus() > 1) + imx_gpcv2_set_slot_ack(2, CORE1_A7, false, false); + imx_gpcv2_set_slot_ack(3, SCU_A7, false, true); + imx_gpcv2_set_slot_ack(6, SCU_A7, true, false); + if (num_online_cpus() > 1) + imx_gpcv2_set_slot_ack(6, CORE1_A7, true, false); + imx_gpcv2_set_slot_ack(6, CORE0_A7, true, true); + } else { + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 0 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 2 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 3 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 6 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 7 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 8 * 0x4); + writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | + BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, + gpc_base + GPC_PGC_ACK_SEL_A7); + imx_gpcv2_enable_rbc(false); + } + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_mix_phy_gate_by_lpm(u32 pdn_index, u32 pup_index) +{ + /* set power down slot */ + writel_relaxed(1 << (FAST_MEGA_MIX * 2), + gpc_base + GPC_SLOT0_CFG + pdn_index * 4); + + /* set power up slot */ + writel_relaxed(1 << (FAST_MEGA_MIX * 2 + 1), + gpc_base + GPC_SLOT0_CFG + pup_index * 4); +} + +unsigned int imx_gpcv2_is_mf_mix_off(void) +{ + return readl_relaxed(gpc_base + GPC_PGC_FM); +} + +static void imx_gpcv2_mf_mix_off(void) +{ + int i; + + for (i = 0; i < IMR_NUM; i++) + if (((gpcv2_wake_irqs[i] | gpcv2_mf_request_on[i]) & + gpcv2_mf_irqs[i]) != 0) + return; + + pr_info("Turn off Mega/Fast mix in DSM\n"); + imx_gpcv2_set_slot_ack(1, FAST_MEGA_MIX, false, false); + imx_gpcv2_set_slot_ack(5, FAST_MEGA_MIX, true, false); + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_FM); +} + +int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on) +{ + struct irq_desc *desc = irq_to_desc(irq); + unsigned long hwirq = desc->irq_data.hwirq; + unsigned int idx = hwirq / 32; + unsigned long flags; + u32 mask = 1 << (hwirq % 32); + + BUG_ON(idx >= IMR_NUM); + + spin_lock_irqsave(&gpcv2_lock, flags); + gpcv2_mf_request_on[idx] = on ? gpcv2_mf_request_on[idx] | mask : + gpcv2_mf_request_on[idx] & ~mask; + spin_unlock_irqrestore(&gpcv2_lock, flags); + + return 0; +} + +void imx_gpcv2_enable_rbc(bool enable) +{ + u32 val; + + /* + * need to mask all interrupts in GPC before + * operating RBC configurations + */ + imx_gpcv2_mask_all(); + + /* configure RBC enable bit */ + val = readl_relaxed(gpc_base + GPC_SLPCR); + val &= ~BM_SLPCR_RBC_EN; + val |= enable ? BM_SLPCR_RBC_EN : 0; + writel_relaxed(val, gpc_base + GPC_SLPCR); + + /* configure RBC count */ + val = readl_relaxed(gpc_base + GPC_SLPCR); + val &= ~BM_SLPCR_REG_BYPASS_COUNT; + val |= enable ? BM_SLPCR_REG_BYPASS_COUNT : 0; + writel(val, gpc_base + GPC_SLPCR); + + /* + * need to delay at least 2 cycles of CKIL(32K) + * due to hardware design requirement, which is + * ~61us, here we use 65us for safe + */ + udelay(65); + + /* restore GPC interrupt mask settings */ + imx_gpcv2_restore_all(); +} + + +void imx_gpcv2_pre_suspend(bool arm_power_off) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + if (arm_power_off) { + imx_gpcv2_set_lpm_mode(STOP_POWER_OFF); + /* enable core0 power down/up with low power mode */ + imx_gpcv2_set_cpu_power_gate_by_lpm(0, true); + /* enable plat power down with low power mode */ + imx_gpcv2_set_plat_power_gate_by_lpm(true); + + /* + * To avoid confuse, we use slot 0~4 for power down, + * slot 5~9 for power up. + * + * Power down slot sequence: + * Slot0 -> CORE0 + * Slot1 -> Mega/Fast MIX + * Slot2 -> SCU + * + * Power up slot sequence: + * Slot5 -> Mega/Fast MIX + * Slot6 -> SCU + * Slot7 -> CORE0 + */ + imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false); + imx_gpcv2_set_slot_ack(2, SCU_A7, false, true); + + if ((!imx_src_is_m4_enabled()) || + (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop())) + imx_gpcv2_mf_mix_off();; + + imx_gpcv2_set_slot_ack(6, SCU_A7, true, false); + imx_gpcv2_set_slot_ack(6, CORE0_A7, true, true); + + /* enable core0, scu */ + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0); + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_SCU); + } else { + imx_gpcv2_set_lpm_mode(STOP_POWER_ON); + } + + for (i = 0; i < IMR_NUM; i++) { + gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); + writel_relaxed(~gpcv2_wake_irqs[i], reg_imr1 + i * 4); + } +} + +void imx_gpcv2_enable_wakeup_for_m4(void) +{ + void __iomem *reg_imr2 = gpc_base + GPC_IMR1_M4; + u32 i; + + for (i = 0; i < IMR_NUM; i++) { + gpcv2_saved_imrs_m4[i] = readl_relaxed(reg_imr2 + i * 4); + writel_relaxed(~gpcv2_wake_irqs[i], reg_imr2 + i * 4); + } +} + +void imx_gpcv2_disable_wakeup_for_m4(void) +{ + void __iomem *reg_imr2 = gpc_base + GPC_IMR1_M4; + u32 i; + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpcv2_saved_imrs_m4[i], reg_imr2 + i * 4); +} + +void imx_gpcv2_post_resume(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i, val; + + /* only external IRQs to wake up LPM and core 0/1 */ + val = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC); + val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP; + writel_relaxed(val, gpc_base + GPC_LPCR_A7_BSC); + /* mask m4 dsm trigger if M4 NOT enabled */ + if (!imx_src_is_m4_enabled()) + writel_relaxed(readl_relaxed(gpc_base + GPC_LPCR_M4) | + BM_LPCR_M4_MASK_DSM_TRIGGER, gpc_base + GPC_LPCR_M4); + /* set mega/fast mix in A7 domain */ + writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_MAPPING); + /* set SCU timing */ + writel_relaxed((0x59 << 10) | 0x5B | (0x2 << 20), + gpc_base + GPC_PGC_SCU_TIMING); + + /* set C0/C1 power up timming per design requirement */ + val = readl_relaxed(gpc_base + GPC_PGC_C0_PUPSCR); + val &= ~BM_GPC_PGC_CORE_PUPSCR; + val |= (0x1A << 7); + writel_relaxed(val, gpc_base + GPC_PGC_C0_PUPSCR); + + val = readl_relaxed(gpc_base + GPC_PGC_C1_PUPSCR); + val &= ~BM_GPC_PGC_CORE_PUPSCR; + val |= (0x1A << 7); + writel_relaxed(val, gpc_base + GPC_PGC_C1_PUPSCR); + + val = readl_relaxed(gpc_base + GPC_SLPCR); + val &= ~(BM_SLPCR_EN_DSM); + if (!imx_src_is_m4_enabled()) + val &= ~(BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | + BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY); + val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE; + writel_relaxed(val, gpc_base + GPC_SLPCR); + + if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { + /* disable memory low power mode */ + val = readl_relaxed(gpc_base + GPC_MLPCR); + val |= BM_GPC_MLPCR_MEMLP_CTL_DIS; + writel_relaxed(val, gpc_base + GPC_MLPCR); + } + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4); + + imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); + imx_gpcv2_set_cpu_power_gate_by_lpm(0, false); + imx_gpcv2_set_plat_power_gate_by_lpm(false); + + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_SCU); + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_FM); + for (i = 0; i < MAX_SLOT_NUMBER; i++){ + if (i == 1 || i == 5) /* skip slts m4 uses */ + continue; + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + i * 0x4); + } + writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | + BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, + gpc_base + GPC_PGC_ACK_SEL_A7); + + /* disable RBC */ + imx_gpcv2_enable_rbc(false); +} + +static struct irq_chip imx_gpcv2_chip = { + .name = "GPCV2", + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = imx_gpcv2_irq_mask, + .irq_unmask = imx_gpcv2_irq_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_wake = imx_gpcv2_irq_set_wake, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif +}; + +static int imx_gpcv2_domain_xlate(struct irq_domain *domain, + struct device_node *controller, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (irq_domain_get_of_node(domain) != controller) + return -EINVAL; /* Shouldn't happen, really... */ + if (intsize != 3) + return -EINVAL; /* Not GIC compliant */ + if (intspec[0] != 0) + return -EINVAL; /* No PPI should point to this domain */ + + *out_hwirq = intspec[1]; + *out_type = intspec[2]; + return 0; +} + +static int imx_gpcv2_domain_alloc(struct irq_domain *domain, + unsigned int irq, + unsigned int nr_irqs, void *data) +{ + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; + irq_hw_number_t hwirq; + int i; + + if (fwspec->param_count != 3) + return -EINVAL; /* Not GIC compliant */ + if (fwspec->param[0] != 0) + return -EINVAL; /* No PPI should point to this domain */ + + hwirq = fwspec->param[1]; + if (hwirq >= GPC_MAX_IRQS) + return -EINVAL; /* Can't deal with this */ + + for (i = 0; i < nr_irqs; i++) + irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i, + &imx_gpcv2_chip, NULL); + + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count = 3; + parent_fwspec.param[0] = 0; + parent_fwspec.param[1] = hwirq; + parent_fwspec.param[2] = fwspec->param[2]; + + return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, + &parent_fwspec); +} + +static struct irq_domain_ops imx_gpcv2_domain_ops = { + .xlate = imx_gpcv2_domain_xlate, + .alloc = imx_gpcv2_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int __init imx_gpcv2_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + int i, val; + + if (!parent) { + pr_err("%s: no parent, giving up\n", node->full_name); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("%s: unable to obtain parent domain\n", node->full_name); + return -ENXIO; + } + + gpc_base = of_iomap(node, 0); + if (WARN_ON(!gpc_base)) + return -ENOMEM; + + domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS, + node, &imx_gpcv2_domain_ops, + NULL); + if (!domain) { + iounmap(gpc_base); + return -ENOMEM; + } + + /* Initially mask all interrupts */ + for (i = 0; i < IMR_NUM; i++) { + writel_relaxed(~0, gpc_base + GPC_IMR1_CORE0 + i * 4); + writel_relaxed(~0, gpc_base + GPC_IMR1_CORE1 + i * 4); + } + /* + * Due to hardware design requirement, need to make sure GPR + * interrupt(#32) is unmasked during RUN mode to avoid entering + * DSM by mistake. + */ + writel_relaxed(~0x1, gpc_base + GPC_IMR1_CORE0); + + /* Read supported wakeup source in M/F domain */ + if (cpu_is_imx7d()) { + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0, + &gpcv2_mf_irqs[0]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1, + &gpcv2_mf_irqs[1]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 2, + &gpcv2_mf_irqs[2]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 3, + &gpcv2_mf_irqs[3]); + if (!(gpcv2_mf_irqs[0] | gpcv2_mf_irqs[1] | + gpcv2_mf_irqs[2] | gpcv2_mf_irqs[3])) + pr_info("No wakeup source in Mega/Fast domain found!\n"); + } + + /* only external IRQs to wake up LPM and core 0/1 */ + val = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC); + val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP; + writel_relaxed(val, gpc_base + GPC_LPCR_A7_BSC); + /* mask m4 dsm trigger if M4 NOT enabled */ + if (!imx_src_is_m4_enabled()) + writel_relaxed(readl_relaxed(gpc_base + GPC_LPCR_M4) | + BM_LPCR_M4_MASK_DSM_TRIGGER, gpc_base + GPC_LPCR_M4); + /* set mega/fast mix in A7 domain */ + writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_MAPPING); + /* set SCU timing */ + writel_relaxed((0x59 << 10) | 0x5B | (0x2 << 20), + gpc_base + GPC_PGC_SCU_TIMING); + + /* set C0/C1 power up timming per design requirement */ + val = readl_relaxed(gpc_base + GPC_PGC_C0_PUPSCR); + val &= ~BM_GPC_PGC_CORE_PUPSCR; + val |= (0x1A << 7); + writel_relaxed(val, gpc_base + GPC_PGC_C0_PUPSCR); + + val = readl_relaxed(gpc_base + GPC_PGC_C1_PUPSCR); + val &= ~BM_GPC_PGC_CORE_PUPSCR; + val |= (0x1A << 7); + writel_relaxed(val, gpc_base + GPC_PGC_C1_PUPSCR); + + writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | + BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, + gpc_base + GPC_PGC_ACK_SEL_A7); + + val = readl_relaxed(gpc_base + GPC_SLPCR); + val &= ~(BM_SLPCR_EN_DSM); + if (!imx_src_is_m4_enabled()) + val &= ~(BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | + BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY); + val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE; + writel_relaxed(val, gpc_base + GPC_SLPCR); + + if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { + /* disable memory low power mode */ + val = readl_relaxed(gpc_base + GPC_MLPCR); + val |= BM_GPC_MLPCR_MEMLP_CTL_DIS; + writel_relaxed(val, gpc_base + GPC_MLPCR); + } + + /* disable RBC */ + imx_gpcv2_enable_rbc(false); + + /* + * Clear the OF_POPULATED flag set in of_irq_init so that + * later the GPC power domain driver will not be skipped. + */ + of_node_clear_flag(node, OF_POPULATED); + + return 0; +} + +/* + * We cannot use the IRQCHIP_DECLARE macro that lives in + * drivers/irqchip, so we're forced to roll our own. Not very nice. + */ +OF_DECLARE_2(irqchip, imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_init); + +void __init imx_gpcv2_check_dt(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc"); + if (WARN_ON(!np)) + return; + + if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) { + pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); + + /* map GPC, so that at least CPUidle and WARs keep working */ + gpc_base = of_iomap(np, 0); + } +} diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h index 92c5a9c9f94b..eb05e8592729 100644 --- a/arch/arm/mach-imx/hardware.h +++ b/arch/arm/mach-imx/hardware.h @@ -81,13 +81,16 @@ * CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000 * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000 * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000 + * mx7d: + * CCM 0x30380000+0x010000 -> 0xf5380000+0x010000 + * ANATOP 0x30360000+0x010000 -> 0xf5360000+0x010000 + * UART1 0x30860000+0x010000 -> 0xf5860000+0x010000 */ #define IMX_IO_P2V(x) ( \ - (((x) & 0x80000000) >> 7) | \ (0xf4000000 + \ - (((x) & 0x50000000) >> 6) + \ - (((x) & 0x0b000000) >> 4) + \ - (((x) & 0x000fffff)))) + (((x) & 0x50000000) >> 4) + \ + (((x) & 0x0a000000) >> 4) + \ + (((x) & 0x00ffffff)))) #define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x)) @@ -99,6 +102,9 @@ #include "mx2x.h" #include "mx21.h" #include "mx27.h" +#include "mx6.h" +#include "mx7.h" +#include "mx7ulp.h" #define imx_map_entry(soc, name, _type) { \ .virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR), \ diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 766dbdb2ae27..c19cfc3166ae 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S @@ -21,6 +21,17 @@ diag_reg_offset: ENTRY(v7_secondary_startup) ARM_BE8(setend be) @ go BE8 if entered LE + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =0xf00 + orr r1, r1, #0xff + mov r0, r0, lsr #4 + and r0, r0, r1 + /* 0xc07 is cortex A7's ID */ + ldr r1, =0xc00 + orr r1, r1, #0x7 + cmp r0, r1 + beq secondary_startup + set_diag_reg b secondary_startup ENDPROC(v7_secondary_startup) diff --git a/arch/arm/mach-imx/imx6sl_low_power_idle.S b/arch/arm/mach-imx/imx6sl_low_power_idle.S new file mode 100644 index 000000000000..978f8d1cc234 --- /dev/null +++ b/arch/arm/mach-imx/imx6sl_low_power_idle.S @@ -0,0 +1,776 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the license, or + * (at your option) any later version. + * + * This program is distributed in teh hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x0 +#define PM_INFO_TTBR_OFFSET 0x4 +#define PM_INFO_MMDC_V_OFFSET 0x8 +#define PM_INFO_IOMUXC_V_OFFSET 0xc +#define PM_INFO_CCM_V_OFFSET 0x10 +#define PM_INFO_L2_V_OFFSET 0x14 +#define PM_INFO_ANATOP_V_OFFSET 0x18 +#define PM_INFO_IO_NUM_OFFSET 0x1c +#define PM_INFO_IO_VAL_OFFSET 0x20 + +#define MX6Q_MMDC_MAPSR 0x404 +#define MX6Q_MMDC_MPDGCTRL0 0x83c + +.global mx6sl_lpm_wfi_start +.global mx6sl_lpm_wfi_end + + .macro pll_do_wait_lock +1: + ldr r7, [r10, r8] + ands r7, #0x80000000 + beq 1b + + .endm + + .macro ccm_do_wait +2: + ldr r7, [r10, #0x48] + cmp r7, #0x0 + bne 2b + + .endm + + .macro ccm_enter_idle + + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + /* + * if in audio_bus_freq_mode, skip to + * audio_mode low power setting. + */ + cmp r1, #0x1 + beq audio_mode + /* + * Now set DDR rate to 1MHz. + * DDR is from bypassed PLL2 on periph2_clk2 path. + * Set the periph2_clk2_podf to divide by 8. + */ + ldr r6, [r10, #0x14] + orr r6, r6, #0x07 + str r6, [r10, #0x14] + + /* Now set MMDC PODF to divide by 3. */ + ldr r6, [r10, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x10 + str r6, [r10, #0x14] + + ccm_do_wait + + /* Set the AHB to 3MHz. AXI to 3MHz. */ + ldr r6, [r10, #0x14] + /*r12 stores the origin AHB podf value */ + mov r12, r6 + orr r6, r6, #0x1c00 + orr r6, r6, #0x70000 + str r6, [r10, #0x14] + + ccm_do_wait + + /* Now set ARM to 24MHz. + * Move ARM to be sourced from step_clk + * after setting step_clk to 24MHz. + */ + ldr r6, [r10, #0x0c] + bic r6, r6, #0x100 + str r6, [r10, #0xc] + /*Now pll1_sw_clk to step_clk */ + ldr r6, [r10, #0x0c] + orr r6, r6, #0x4 + str r6, [r10, #0x0c] + + /* Bypass PLL1 and power it down */ + ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] + ldr r6, =(1 << 16) + orr r6, r6, #0x1000 + str r6, [r10, #0x04] + + /* + * Set the ARM PODF to divide by 8. + * IPG is at 1.5MHz here, we need ARM to + * run at the 12:5 ratio (WAIT mode issue). + */ + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + ldr r11, [r10, #0x10] + ldr r6, =0x07 + str r6, [r10, #0x10] + + ccm_do_wait + + b ccm_idle_done + +audio_mode: + /* + * MMDC is sourced from pll2_200M. + * Set the mmdc_podf to div by 8 + */ + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + ldr r6, [r10, #0x14] + orr r6, r6, #0x38 + str r6, [r10, #0x14] + + ccm_do_wait + + /* + * ARM is sourced from pll2_pfd2_400M here. + * switch ARM to bypassed PLL1 + */ + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + ldr r6, [r10, #0x0c] + bic r6, r6, #0x4 + str r6, [r10, #0xc] + + /* + * set the arm_podf to divide by 3 + * as IPG is at 4MHz, we cannot run + * arm clk above 9.6MHz when system + * enter WAIT mode + */ + ldr r11, [r10, #0x10] + ldr r6, =0x2 + str r6, [r10, #0x10] + + ccm_do_wait + +ccm_idle_done: + + .endm + + .macro ccm_exit_idle + + /* + * If in audio_bus_freq_mode, skip to + * audio_mode ccm restore. + */ + cmp r1, #0x1 + beq audio_ccm_restore + + ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] + /* Power up PLL1 and un-bypass it. */ + ldr r6, =(1 << 12) + str r6, [r10, #0x08] + + /* Wait for PLL1 to relock */ + ldr r8, =0x0 + pll_do_wait_lock + + ldr r6, =(1 << 16) + str r6, [r10, #0x08] + + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + /* Set PLL1_sw_clk back to PLL1 */ + ldr r6, [r10, #0x0c] + bic r6, r6, #0x4 + str r6, [r10, #0x0c] + + /* Restore AHB/AXI back */ + str r12, [r10, #0x14] + + ccm_do_wait + + /* restore mmdc back to 24MHz*/ + ldr r6, [r10, #0x14] + bic r6, r6, #0x3f + str r6, [r10, #0x14] + + ccm_do_wait + b ccm_exit_done + +audio_ccm_restore: + /* move arm clk back to pll2_pfd2_400M */ + ldr r6, [r10, #0xc] + orr r6, r6, #0x4 + str r6, [r10, #0xc] + + /* restore mmdc podf */ + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + ldr r6, [r10, #0x14] + bic r6, r6, #0x38 + orr r6, #0x8 + str r6, [r10, #0x14] + + ccm_do_wait + +ccm_exit_done: + + .endm + + .macro check_pll_state + + ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] + /* + * Check whether any PLL is enabled, as only when + * there is no PLLs enabled, 2p5 can be off and + * only enable the weak one. PLL1 will be powered + * down late, so no need to check PLL1 state. + */ + + /* sys PLL2 */ + ldr r6, [r10, #0x30] + ands r6, r6, #(1 << 31) + bne 1f + + /* usb PLL3 */ + ldr r6, [r10, #0x10] + ands r6, r6, #(1 << 31) + bne 1f + + /* audio PLL4 */ + ldr r6, [r10, #0x70] + ands r6, r6, #(1 << 31) + bne 1f + + /* video PLL5 */ + ldr r6, [r10, #0xa0] + ands r6, r6, #(1 << 31) + bne 1f + + /* enet PLL6 */ + ldr r6, [r10, #0xe0] + ands r6, r6, #(1 << 31) + bne 1f + + /* usb host PLL7 */ + ldr r6, [r10, #0x20] + ands r6, r6, #(1 << 31) + bne 1f + + ldr r4, =0x1 + b check_done +1: + ldr r4, =0x0 + +check_done: + .endm + + .macro anatop_enter_idle + + ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] + cmp r4, #0x0 + beq anatop_enter_done + + /* Disable 1p1 brown out. */ + ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] + ldr r6, [r10, #0x110] + bic r6, r6, #0x2 + str r6, [r10, #0x110] + /* + * Set the OSC bias current to -37.5% + * to drop the power on VDDHIGH. + */ + ldr r6, [r10, #0x150] + orr r6, r6, #0xc000 + str r6, [r10, #0x150] + + /* + * if the usb VBUS wakeup is enabled, skip + * disable main 2p5. + */ + cmp r2, #0x1 + beq anatop_enter_done + + /* Enable the week 2p5 */ + ldr r6, [r10, #0x130] + orr r6, r6, #0x40000 + str r6, [r10, #0x130] + + /* Disable main 2p5. */ + ldr r6, [r10, #0x130] + bic r6, r6, #0x1 + str r6, [r10, #0x130] + + /* + * Cannot diable regular bandgap + * in LDO-enable mode. The bandgap + * is required for ARM-LDO to regulate + * the voltage. + */ + ldr r6, [r10, #0x140] + and r6, r6, #0x1f + cmp r6, #0x1f + bne anatop_enter_done + + /* Enable low power bandgap */ + ldr r6, [r10, #0x260] + orr r6, r6, #0x20 + str r6, [r10, #0x260] + + /* + * Turn off the bias current + * from the regular bandgap. + */ + ldr r6, [r10, #0x260] + orr r6, r6, #0x80 + str r6, [r10, #0x260] + + /* + * Clear the REFTTOP+SELFBIASOFF, + * self_bais circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r6, [r10, #0x150] + bic r6, r6, #0x8 + str r6, [r10, #0x150] + + /* Power down the regular bandgap */ + ldr r6, [r10, #0x150] + orr r6, r6, #0x1 + str r6, [r10, #0x150] +anatop_enter_done: + + .endm + + .macro anatop_exit_idle + + ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] + cmp r4, #0x0 + beq skip_anatop_restore + + cmp r2, #0x1 + beq ldo2p5_not_disabled + /* + * Regular bandgap will not be disabled + * in LDO-enabled mode as it is required + * for ARM-LDO to reguulate the voltage. + */ + ldr r6, [r10, #0x140] + and r6, r6, #0x1f + cmp r6, #0x1f + bne skip_bandgap_restore + + /* Power up the regular bandgap */ + ldr r6, [r10, #0x150] + bic r6, r6, #0x1 + str r6, [r10, #0x150] + + /* wait for bandgap stable */ +3: + ldr r6, [r10, #0x150] + and r6, r6, #0x80 + cmp r6, #0x80 + bne 3b + + /* now disable bandgap self-bias circuit */ + ldr r6, [r10, #0x150] + orr r6, r6, #0x8 + str r6, [r10, #0x150] + + /* Turn on the bias current + * from the regular bandgap. + */ + ldr r6, [r10, #0x260] + bic r6, r6, #0x80 + str r6, [r10, #0x260] + + /* Disable the low power bandgap */ + ldr r6, [r10, #0x260] + bic r6, r6, #0x20 + str r6, [r10, #0x260] + +skip_bandgap_restore: + /* Enable main 2p5. */ + ldr r6, [r10, #0x130] + orr r6, r6, #0x1 + str r6, [r10, #0x130] + + /* Ensure the 2p5 is up */ +5: + ldr r6, [r10, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne 5b + + /* Disable the weak 2p5 */ + ldr r6, [r10, #0x130] + bic r6, r6, #0x40000 + str r6, [r10, #0x130] + +ldo2p5_not_disabled: + /* + * Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r10, #0x150] + bic r6, r6, #0xc000 + str r6, [r10, #0x150] + + /* Enable 1p1 brown out, */ + ldr r6, [r10, #0x110] + orr r6, r6, #0x2 + str r6, [r10, #0x110] + +skip_anatop_restore: + + .endm + + .macro disable_l1_dcache + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + + dsb + isb + + .endm + + .macro mmdc_enter_dvfs_mode + + /* disable automatic power saving. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + /* disable power down timer */ + ldr r7, [r10, #0x04] + bic r7, r7, #0xff00 + str r7, [r10, #0x04] + + /* Make the DDR explicitly enter self-refresh. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] + +poll_dvfs_set: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + beq poll_dvfs_set + + /* set SBS step-by step mode */ + ldr r7, [r10, #0x410] + orr r7, r7, #0x100 + str r7, [r10, #0x410] + + .endm + + .macro resume_mmdc + /* restore MMDC IO */ + ldr r10, [r0, #PM_INFO_IOMUXC_V_OFFSET] + + ldr r6, [r0, #PM_INFO_IO_NUM_OFFSET] + ldr r7, =PM_INFO_IO_VAL_OFFSET + add r7, r7, r0 +6: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 6b + + /* + * Need to reset the FIFO to avoid MMDC lockup + * caused because of floating/changing the + * configuration of many DDR IO pads. + */ + ldr r10, [r0, #PM_INFO_MMDC_V_OFFSET] + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +7: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 7b + + /* reset FIFO a second time */ + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +8: + ldr r6, [r10, r7] + ands r6, r6, #(1 <<31) + bne 8b + + ldr r10, [r0, #PM_INFO_MMDC_V_OFFSET] + /* Let DDR out of self-refresh */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +9: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + bne 9b + + /* enable power down timer */ + ldr r7, [r10, #0x04] + orr r7, r7, #0x5500 + str r7, [r10, #0x04] + + /* enable DDR auto power saving */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + /* Clear SBS - unblock DDR accesses */ + ldr r7, [r10, #0x410] + bic r7, r7, #0x100 + str r7, [r10, #0x410] + + .endm + + .macro tlb_set_to_ocram + + /* save ttbr */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_TTBR_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * we need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to the IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is transslated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Disable Branch Prediction, Z bit in SCTLR */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + dsb + isb + + /* store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + /* Read TTBCR and set PD0=1, N=1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* Flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro tlb_back_to_ddr + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N=0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + /* Flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0 ,r6, c1, c0, 0 + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + /* Restore ttbr */ + ldr r7, [r0, #PM_INFO_TTBR_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + +.extern iram_tlb_phys_addr + +/* + * imx6sl_low_power_wfi code + * r0: wfi code base address + * r1: audio_bus_freq mode stat + * r2: vbus_ldo status + * r4: used for store the PLLs state + * r11: used for saving the ARM_PODF origin value + * r12: used for saving AHB_PODF origin value + */ + .align 3 +ENTRY(imx6sl_low_power_idle) + +mx6sl_lpm_wfi_start: + push {r4-r12} + + tlb_set_to_ocram + disable_l1_dcache + +#ifdef CONFIG_CACHE_L2X0 + /* sync L2 */ + ldr r10, [r0, #PM_INFO_L2_V_OFFSET] + /* Wait for background operations to complete. */ +wait_for_l2_idle: + ldr r6, [r10, #0x730] + cmp r6, #0x0 + bne wait_for_l2_idle + + mov r6, #0x0 + str r6, [r10, #0x730] + /* disable L2 */ + str r6, [r10, #0x100] + + dsb + isb +#endif + + /* make sure MMDC in self-refresh */ + ldr r10, [r0, #PM_INFO_MMDC_V_OFFSET] + mmdc_enter_dvfs_mode + /* save DDR IO settings and set to LPM mode*/ + ldr r10, [r0, #PM_INFO_IOMUXC_V_OFFSET] + ldr r6, =0x0 + ldr r7, [r0, #PM_INFO_IO_NUM_OFFSET] + ldr r8, =PM_INFO_IO_VAL_OFFSET + add r8, r8, r0 + + /* imx6sl's last 3 IOs need special setting */ + sub r7, r7, #0x3 +save_and_set_mmdc_io_lpm: + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + subs r7, r7, #0x1 + bne save_and_set_mmdc_io_lpm + ldr r6, =0x1000 + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r5, [r8], #0x4 + str r6, [r10, r9] + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + ldr r6, =0x80000 + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + + + /* check the PLLs lock state */ + check_pll_state + + ccm_enter_idle + /* if in audio low power mode, no + * need to do anatop setting. + */ + cmp r1, #0x1 + beq do_wfi + anatop_enter_idle +do_wfi: + wfi + /* + * Add these nops so that the + * prefetcher will not try to get + * any instrutions from DDR. + * The prefetch depth is about 23 + * on A9, so adding 25 nops. + */ + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + /* + * restore the ARM PODF first to speed + * up the restore procedure + */ + ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] + /* Restore arm_clk_podf */ + str r11, [r10, #0x10] + ccm_do_wait + + /* + * if in audio low power mode, skip + * restore the anatop setting. + */ + cmp r1, #0x1 + beq skip_analog_restore + anatop_exit_idle + +skip_analog_restore: + ccm_exit_idle + resume_mmdc + + /* enable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + +#ifdef CONFIG_CACHE_L2X0 + ldr r10, [r0, #PM_INFO_L2_V_OFFSET] + mov r7, #0x1 + /* enable L2 */ + str r7, [r10, #0x100] +#endif + tlb_back_to_ddr + + /* Restore register */ + pop {r4 - r12} + mov pc, lr + + /* + * Add ltorg here to ensure that all + * literals are stored here and are + * within the text space. + */ + .ltorg +mx6sl_lpm_wfi_end: diff --git a/arch/arm/mach-imx/imx6sll_low_power_idle.S b/arch/arm/mach-imx/imx6sll_low_power_idle.S new file mode 100644 index 000000000000..a7e206ecbb42 --- /dev/null +++ b/arch/arm/mach-imx/imx6sll_low_power_idle.S @@ -0,0 +1,780 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define PM_INFO_PBASE_OFFSET 0x0 +#define PM_INFO_RESUME_ADDR_OFFSET 0x4 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x8 +#define PM_INFO_PM_INFO_TTBR_OFFSET 0xc +#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 +#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 +#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x18 +#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x1c +#define PM_INFO_MX6Q_CCM_P_OFFSET 0x20 +#define PM_INFO_MX6Q_CCM_V_OFFSET 0x24 +#define PM_INFO_MX6Q_GPC_P_OFFSET 0x28 +#define PM_INFO_MX6Q_GPC_V_OFFSET 0x2c +#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x30 +#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x34 +#define PM_INFO_MX6Q_SRC_P_OFFSET 0x38 +#define PM_INFO_MX6Q_SRC_V_OFFSET 0x3c +#define PM_INFO_MX6Q_L2_P_OFFSET 0x40 +#define PM_INFO_MX6Q_L2_V_OFFSET 0x44 +#define PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET 0x48 + +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x4c +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x50 + +#define MX6Q_MMDC_MAPSR 0x404 +#define MX6Q_MMDC_MPDGCTRL0 0x83c +#define MX6Q_SRC_GPR1 0x20 +#define MX6Q_SRC_GPR2 0x24 +#define MX6Q_GPC_IMR1 0x08 +#define MX6Q_GPC_IMR2 0x0c +#define MX6Q_GPC_IMR3 0x10 +#define MX6Q_GPC_IMR4 0x14 +#define MX6Q_CCM_CCR 0x0 + +.globl mx6sll_lpm_wfi_start +.globl mx6sll_lpm_wfi_end + + .macro pll_do_wait_lock +1: + ldr r7, [r10, r8] + ands r7, #0x80000000 + beq 1b + + .endm + + .macro ccm_do_wait +2: + ldr r7, [r10, #0x48] + cmp r7, #0x0 + bne 2b + + .endm + + .macro ccm_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + + /* set ahb to 3MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x1c00 + str r7, [r10, #0x14] + + /* set perclk to 6MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + orr r7, r7, #0x3 + str r7, [r10, #0x1c] + + /* set mmdc to 1MHz, periph2_clk2 need to be @8MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x2 + orr r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + ccm_do_wait + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* + * disable pll2, suppose when system enter low + * power idle mode, only 396MHz pfd needs pll2, + * now we switch arm clock to OSC, we can disable + * pll2 now, gate pll2_pfd2 first. + */ + ldr r7, [r10, #0x100] + orr r7, #0x800000 + str r7, [r10, #0x100] + + ldr r7, [r10, #0x30] + orr r7, r7, #0x1000 + bic r7, r7, #0x2000 + str r7, [r10, #0x30] + + .endm + + .macro ccm_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* enable pll2 and pll2_pfd2 */ + ldr r7, [r10, #0x30] + bic r7, r7, #0x1000 + orr r7, r7, #0x2000 + str r7, [r10, #0x30] + + ldr r8, =0x30 + pll_do_wait_lock + + ldr r7, [r10, #0x100] + bic r7, #0x800000 + str r7, [r10, #0x100] + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_CCM_P_OFFSET] + + /* set perclk back to 24MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + str r7, [r10, #0x1c] + + /* set mmdc back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x7 + bic r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + /* set ahb div back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x1c00 + str r7, [r10, #0x14] + + ccm_do_wait + + .endm + + .macro anatop_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* + * check whether any PLL is enabled, as only when + * there is no PLLs enabled, 2P5 and 1P1 can be + * off and only enable weak ones. + */ + + /* arm pll1 */ + ldr r7, [r10, #0] + ands r7, r7, #(1 << 31) + bne 10f + + /* sys pll2 */ + ldr r7, [r10, #0x30] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb pll3 */ + ldr r7, [r10, #0x10] + ands r7, r7, #(1 << 31) + bne 10f + + /* audio pll4 */ + ldr r7, [r10, #0x70] + ands r7, r7, #(1 << 31) + bne 10f + + /* vidio pll5 */ + ldr r7, [r10, #0xa0] + ands r7, r7, #(1 << 31) + bne 10f + + /* enet pll6 */ + ldr r7, [r10, #0xe0] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb host pll7 */ + ldr r7, [r10, #0x20] + ands r7, r7, #(1 << 31) + bne 10f + + /* enable weak 2P5 and turn off regular 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x40000 + str r7, [r10, #0x130] + bic r7, r7, #0x1 + str r7, [r10, #0x130] + + /* enable weak 1p1 and turn off regular 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x40000 + str r7, [r10, #0x110] + bic r7, r7, #0x1 + str r7, [r10, #0x110] + + /* low power band gap enable */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x20 + str r7, [r10, #0x270] + + /* turn off the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x80 + str r7, [r10, #0x270] + + /* + * clear the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn off regular bandgap */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1 + str r7, [r10, #0x150] + +10: + /* switch to RC-OSC */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x40000000 + str r7, [r10, #0x150] + + /* lower OSC current by 37.5% */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* disconnect vdd_high_in and vdd_snvs_in */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1000 + str r7, [r10, #0x150] + + .endm + + .macro anatop_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* increase OSC current to normal */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* turn on XTAL-OSC and detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x40000000 + orr r7, r7, #0x10000 + str r7, [r10, #0x150] + + /* wait for XTAL stable */ +14: + ldr r7, [r10, #0x150] + ands r7, r7, #0x8000 + beq 14b + + /* switch to XTAL-OSC */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x10000 + str r7, [r10, #0x150] +15: + /* check whether we need to enable 2P5/1P1 */ + ldr r7, [r10, #0x110] + ands r7, r7, #0x40000 + beq 11f + + /* turn on regular bandgap and wait for stable */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x1 + str r7, [r10, #0x150] +13: + ldr r7, [r10, #0x150] + ands r7, #0x80 + beq 13b + + /* + * set the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn on the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x80 + str r7, [r10, #0x270] + + /* low power band gap disable */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x20 + str r7, [r10, #0x270] +12: + /* enable regular 2P5 and turn off weak 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x1 + str r7, [r10, #0x130] + + /* Ensure the 2P5 is up. */ +3: + ldr r7, [r10, #0x130] + ands r7, r7, #0x20000 + beq 3b + ldr r7, [r10, #0x130] + bic r7, r7, #0x40000 + str r7, [r10, #0x130] + + /* enable regular 1p1 and turn off weak 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x1 + str r7, [r10, #0x110] +4: + ldr r7, [r10, #0x110] + ands r7, r7, #0x20000 + beq 4b + ldr r7, [r10, #0x110] + bic r7, r7, #0x40000 + str r7, [r10, #0x110] +11: + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro mmdc_enter_dvfs_mode + + /* disable automatic power savings. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + /* make the DDR explicitly enter self-refresh. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +5: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + beq 5b + + .endm + + .macro resume_mmdc + + /* restore MMDC IO */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] + + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +6: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 6b + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] + + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +7: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 7b + + /* reset FIFO a second time */ + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +8: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 8b + + /* let DDR out of self-refresh */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +9: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + bne 9b + + /* enable DDR auto power saving */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + .endm + + .macro tlb_set_to_ocram + + /* save ttbr */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro tlb_back_to_ddr + + /* Restore the TTBCR */ + + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* restore ttbr */ + ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + +.extern iram_tlb_phys_addr + +/* imx6sx_low_power_idle */ + + .align 3 +ENTRY(imx6sll_low_power_idle) +mx6sll_lpm_wfi_start: + push {r4 - r10} + + /* get necessary info from pm_info */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r5, =imx6sll_low_power_idle + ldr r6, =wakeup + sub r6, r6, r5 + add r8, r1, r2 + add r3, r8, r6 + + /* store physical resume addr and pm_info address. */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] + str r3, [r10, #0x20] + str r1, [r10, #0x24] + + /* save disagnostic register */ + mrc p15, 0, r7, c15, c0, 1 + str r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET] + + /* set ARM power to be gated */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x1 + str r7, [r10, #0x2a0] + + disable_l1_dcache + +#ifdef CONFIG_CACHE_L2X0 + /* sync L2 */ + ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + + /* Wait for background operations to complete. */ +wait_for_l2_to_idle: + ldr r7, [r10, #0x730] + cmp r7, #0x0 + bne wait_for_l2_to_idle + + mov r7, #0x0 + str r7, [r10, #0x730] + /* disable L2 */ + str r7, [r10, #0x100] + + dsb + isb +#endif + + tlb_set_to_ocram + + /* make sure MMDC in self-refresh */ + ldr r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + mmdc_enter_dvfs_mode + + /* save DDR IO settings */ + ldr r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldr r6, =0x0 + ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET + add r8, r8, r0 +save_and_set_mmdc_io_lpm: + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + subs r7, r7, #0x1 + bne save_and_set_mmdc_io_lpm + + mov r5, #0x0 + ccm_enter_idle + anatop_enter_idle + + /* + * mask all GPC interrupts before + * enabling the RBC counters to + * avoid the counter starting too + * early if an interupt is already + * pending. + */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r4, [r10, #MX6Q_GPC_IMR1] + ldr r5, [r10, #MX6Q_GPC_IMR2] + ldr r6, [r10, #MX6Q_GPC_IMR3] + ldr r7, [r10, #MX6Q_GPC_IMR4] + + ldr r3, =0xffffffff + str r3, [r10, #MX6Q_GPC_IMR1] + str r3, [r10, #MX6Q_GPC_IMR2] + str r3, [r10, #MX6Q_GPC_IMR3] + str r3, [r10, #MX6Q_GPC_IMR4] + + /* + * enable the RBC bypass counter here + * to hold off the interrupts. RBC counter + * = 4 (120us). With this setting, the latency + * from wakeup interrupt to ARM power up + * is ~130uS. + */ + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldr r3, [r10, #MX6Q_CCM_CCR] + bic r3, r3, #(0x3f << 21) + orr r3, r3, #(0x4 << 21) + str r3, [r10, #MX6Q_CCM_CCR] + + /* enable the counter. */ + ldr r3, [r10, #MX6Q_CCM_CCR] + orr r3, r3, #(0x1 << 27) + str r3, [r10, #MX6Q_CCM_CCR] + + /* unmask all the GPC interrupts. */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + str r4, [r10, #MX6Q_GPC_IMR1] + str r5, [r10, #MX6Q_GPC_IMR2] + str r6, [r10, #MX6Q_GPC_IMR3] + str r7, [r10, #MX6Q_GPC_IMR4] + + /* + * now delay for a short while (3usec) + * ARM is at 24MHz at this point + * so a short loop should be enough. + * this delay is required to ensure that + * the RBC counter can start counting in + * case an interrupt is already pending + * or in case an interrupt arrives just + * as ARM is about to assert DSM_request. + */ + ldr r4, =50 +rbc_loop: + subs r4, r4, #0x1 + bne rbc_loop + + wfi + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + mov r5, #0x0 + anatop_exit_idle + ccm_exit_idle + resume_mmdc + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + /* enable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + +#ifdef CONFIG_CACHE_L2X0 + ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + mov r7, #0x1 + /* enable L2 */ + str r7, [r10, #0x100] +#endif + + tlb_back_to_ddr + + /* Restore registers */ + pop {r4 - r10} + mov pc, lr + +wakeup: + + /* invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 6 + /* enable the Icache and branch prediction */ + mov r1, #0x1800 + mcr p15, 0, r1, c1, c0, 0 + isb + /* restore disagnostic register */ + ldr r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET] + mcr p15, 0, r7, c15, c0, 1 + + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + /* clear core0's entry and parameter */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] + mov r7, #0x0 + str r7, [r10, #MX6Q_SRC_GPR1] + str r7, [r10, #MX6Q_SRC_GPR2] + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + mov r5, #0x1 + anatop_exit_idle + ccm_exit_idle + resume_mmdc + + /* Restore registers */ + mov pc, lr + .ltorg +mx6sll_lpm_wfi_end: diff --git a/arch/arm/mach-imx/imx6sx_low_power_idle.S b/arch/arm/mach-imx/imx6sx_low_power_idle.S new file mode 100644 index 000000000000..7ddda1cd1a8f --- /dev/null +++ b/arch/arm/mach-imx/imx6sx_low_power_idle.S @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define PM_INFO_PBASE_OFFSET 0x0 +#define PM_INFO_RESUME_ADDR_OFFSET 0x4 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x8 +#define PM_INFO_PM_INFO_TTBR_OFFSET 0xc +#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 +#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 +#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x18 +#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x1c +#define PM_INFO_MX6Q_CCM_P_OFFSET 0x20 +#define PM_INFO_MX6Q_CCM_V_OFFSET 0x24 +#define PM_INFO_MX6Q_GPC_P_OFFSET 0x28 +#define PM_INFO_MX6Q_GPC_V_OFFSET 0x2c +#define PM_INFO_MX6Q_L2_P_OFFSET 0x30 +#define PM_INFO_MX6Q_L2_V_OFFSET 0x34 +#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x38 +#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x3c +#define PM_INFO_MX6Q_SRC_P_OFFSET 0x40 +#define PM_INFO_MX6Q_SRC_V_OFFSET 0x44 +#define PM_INFO_MX6Q_SEMA4_P_OFFSET 0x48 +#define PM_INFO_MX6Q_SEMA4_V_OFFSET 0x4c +#define PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET 0x50 +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x54 +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x58 + +#define MX6Q_MMDC_MAPSR 0x404 +#define MX6Q_MMDC_MPDGCTRL0 0x83c +#define MX6Q_SRC_GPR1 0x20 +#define MX6Q_SRC_GPR2 0x24 +#define MX6Q_GPC_IMR1 0x08 +#define MX6Q_GPC_IMR2 0x0c +#define MX6Q_GPC_IMR3 0x10 +#define MX6Q_GPC_IMR4 0x14 +#define MX6Q_CCM_CCR 0x0 + +.globl mx6sx_lpm_wfi_start +.globl mx6sx_lpm_wfi_end + + .macro pll_do_wait_lock +1: + ldr r7, [r10, r8] + ands r7, #0x80000000 + beq 1b + + .endm + + .macro ccm_do_wait +2: + ldr r7, [r10, #0x48] + cmp r7, #0x0 + bne 2b + + .endm + + .macro ccm_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + + /* set ahb to 3MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x1c00 + str r7, [r10, #0x14] + + /* set perclk to 6MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + orr r7, r7, #0x3 + str r7, [r10, #0x1c] + + /* set mmdc to 1MHz, periph2_clk2 need to be @8MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x2 + orr r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + ccm_do_wait + + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + + /* set pll1_sw to from pll1 main */ + ldr r7, [r10, #0xc] + bic r7, r7, #0x4 + str r7, [r10, #0xc] + + /* set step from osc */ + ldr r7, [r10, #0xc] + bic r7, r7, #0x100 + str r7, [r10, #0xc] + + /* set pll1_sw to from step */ + ldr r7, [r10, #0xc] + orr r7, r7, #0x4 + str r7, [r10, #0xc] + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* Disable PLL1 bypass output */ + ldr r7, [r10] + bic r7, r7, #0x12000 + str r7, [r10] + + /* + * disable pll2, suppose when system enter low + * power idle mode, only 396MHz pfd needs pll2, + * now we switch arm clock to OSC, we can disable + * pll2 now, gate pll2_pfd2 first. + */ + ldr r7, [r10, #0x100] + orr r7, #0x800000 + str r7, [r10, #0x100] + + ldr r7, [r10, #0x30] + orr r7, r7, #0x1000 + bic r7, r7, #0x2000 + str r7, [r10, #0x30] + + .endm + + .macro ccm_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* enable pll2 and pll2_pfd2 */ + ldr r7, [r10, #0x30] + bic r7, r7, #0x1000 + orr r7, r7, #0x2000 + str r7, [r10, #0x30] + + ldr r8, =0x30 + pll_do_wait_lock + + ldr r7, [r10, #0x100] + bic r7, #0x800000 + str r7, [r10, #0x100] + + /* enable PLL1 bypass output */ + ldr r7, [r10] + orr r7, r7, #0x12000 + str r7, [r10] + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_CCM_P_OFFSET] + + /* set perclk back to 24MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + str r7, [r10, #0x1c] + + /* set mmdc back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x7 + bic r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + /* set ahb div back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x1c00 + str r7, [r10, #0x14] + + ccm_do_wait + + /* set pll1_sw to from pll1 main */ + ldr r7, [r10, #0xc] + bic r7, r7, #0x4 + str r7, [r10, #0xc] + + /* set step from pll2_pfd2 */ + ldr r7, [r10, #0xc] + orr r7, r7, #0x100 + str r7, [r10, #0xc] + + /* set pll1_sw to from step */ + ldr r7, [r10, #0xc] + orr r7, r7, #0x4 + str r7, [r10, #0xc] + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + .endm + + .macro anatop_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* + * check whether any PLL is enabled, as only when + * there is no PLLs enabled, 2P5 and 1P1 can be + * off and only enable weak ones. + */ + + /* arm pll1 */ + ldr r7, [r10, #0] + ands r7, r7, #(1 << 31) + bne 10f + + /* sys pll2 */ + ldr r7, [r10, #0x30] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb pll3 */ + ldr r7, [r10, #0x10] + ands r7, r7, #(1 << 31) + bne 10f + + /* audio pll4 */ + ldr r7, [r10, #0x70] + ands r7, r7, #(1 << 31) + bne 10f + + /* vidio pll5 */ + ldr r7, [r10, #0xa0] + ands r7, r7, #(1 << 31) + bne 10f + + /* enet pll6 */ + ldr r7, [r10, #0xe0] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb host pll7 */ + ldr r7, [r10, #0x20] + ands r7, r7, #(1 << 31) + bne 10f + + /* enable weak 2P5 and turn off regular 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x40000 + str r7, [r10, #0x130] + bic r7, r7, #0x1 + str r7, [r10, #0x130] + + /* enable weak 1p1 and turn off regular 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x40000 + str r7, [r10, #0x110] + bic r7, r7, #0x1 + str r7, [r10, #0x110] + + /* check whether ARM LDO is bypassed */ + ldr r7, [r10, #0x140] + and r7, r7, #0x1f + cmp r7, #0x1f + bne 10f + + /* low power band gap enable */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x20 + str r7, [r10, #0x270] + + /* turn off the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x80 + str r7, [r10, #0x270] + + /* + * clear the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn off regular bandgap */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1 + str r7, [r10, #0x150] + + /* only switch to RC-OSC clk after TO1.2 */ + ldr r7, [r10, #0x260] + and r7, r7, #0x3 + cmp r7, #0x2 + blt 10f + + /* switch to RC-OSC */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x40000000 + str r7, [r10, #0x150] +10: + /* lower OSC current by 37.5% */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x6000 + str r7, [r10, #0x150] + + .endm + + .macro anatop_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* increase OSC current to normal */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* only switch to RC-OSC after TO1.2 */ + ldr r7, [r10, #0x260] + and r7, r7, #0x3 + cmp r7, #0x2 + blt 15f + + /* turn on XTAL-OSC and detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x40000000 + orr r7, r7, #0x10000 + str r7, [r10, #0x150] + + /* wait for XTAL stable */ +14: + ldr r7, [r10, #0x150] + ands r7, r7, #0x8000 + beq 14b + + /* switch to XTAL-OSC */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x10000 + str r7, [r10, #0x150] +15: + /* check whether we need to enable 2P5/1P1 */ + ldr r7, [r10, #0x110] + ands r7, r7, #0x40000 + beq 11f + + /* check whether ARM LDO is bypassed */ + ldr r7, [r10, #0x140] + and r7, r7, #0x1f + cmp r7, #0x1f + bne 12f + + /* turn on regular bandgap and wait for stable */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x1 + str r7, [r10, #0x150] +13: + ldr r7, [r10, #0x150] + ands r7, #0x80 + beq 13b + + /* + * set the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn on the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x80 + str r7, [r10, #0x270] + + /* low power band gap disable */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x20 + str r7, [r10, #0x270] +12: + /* enable regular 2P5 and turn off weak 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x1 + str r7, [r10, #0x130] + + /* Ensure the 2P5 is up. */ +3: + ldr r7, [r10, #0x130] + ands r7, r7, #0x20000 + beq 3b + ldr r7, [r10, #0x130] + bic r7, r7, #0x40000 + str r7, [r10, #0x130] + + /* enable regular 1p1 and turn off weak 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x1 + str r7, [r10, #0x110] +4: + ldr r7, [r10, #0x110] + ands r7, r7, #0x20000 + beq 4b + ldr r7, [r10, #0x110] + bic r7, r7, #0x40000 + str r7, [r10, #0x110] +11: + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro mmdc_enter_dvfs_mode + + /* disable automatic power savings. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + /* disable power down timer */ + ldr r7, [r10, #0x4] + bic r7, r7, #0xff00 + str r7, [r10, #0x4] + + /* make the DDR explicitly enter self-refresh. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +5: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + beq 5b + + .endm + + .macro resume_mmdc + + /* restore MMDC IO */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] + + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +6: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 6b + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] + + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +7: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 7b + + /* reset FIFO a second time */ + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +8: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 8b + + /* let DDR out of self-refresh */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +9: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + bne 9b + + /* enable power down timer */ + ldr r7, [r10, #0x4] + orr r7, r7, #0x5500 + str r7, [r10, #0x4] + + /* enable DDR auto power saving */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + .endm + + .macro sema4_lock + + /* lock share memory sema4 */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_SEMA4_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_SEMA4_P_OFFSET] + ldrb r6, =0x1 +16: + ldrb r7, [r10, #0x6] + cmp r7, #0x0 + bne 16b + strb r6, [r10, #0x6] + + .endm + + .macro sema4_unlock + + /* unlock share memory sema4 */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_SEMA4_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_SEMA4_P_OFFSET] + ldrb r6, =0x0 + strb r6, [r10, #0x6] + + .endm + + .macro tlb_set_to_ocram + + /* save ttbr */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro tlb_back_to_ddr + + /* Restore the TTBCR */ + + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* restore ttbr */ + ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + +.extern iram_tlb_phys_addr + +/* imx6sx_low_power_idle */ + + .align 3 +ENTRY(imx6sx_low_power_idle) +mx6sx_lpm_wfi_start: + push {r4 - r10} + + /* get necessary info from pm_info */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r5, =imx6sx_low_power_idle + ldr r6, =wakeup + sub r6, r6, r5 + add r8, r1, r2 + add r3, r8, r6 + + /* store physical resume addr and pm_info address. */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] + str r3, [r10, #0x20] + str r1, [r10, #0x24] + + /* save disagnostic register */ + mrc p15, 0, r7, c15, c0, 1 + str r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET] + + /* set ARM power to be gated */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x1 + str r7, [r10, #0x2a0] + + disable_l1_dcache + +#ifdef CONFIG_CACHE_L2X0 + /* sync L2 */ + ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + + /* Wait for background operations to complete. */ +wait_for_l2_to_idle: + ldr r7, [r10, #0x730] + cmp r7, #0x0 + bne wait_for_l2_to_idle + + mov r7, #0x0 + str r7, [r10, #0x730] + /* disable L2 */ + str r7, [r10, #0x100] + + dsb + isb +#endif + + tlb_set_to_ocram + + /* make sure MMDC in self-refresh */ + ldr r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + mmdc_enter_dvfs_mode + + /* save DDR IO settings */ + ldr r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldr r6, =0x0 + ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET + add r8, r8, r0 +save_and_set_mmdc_io_lpm: + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + subs r7, r7, #0x1 + bne save_and_set_mmdc_io_lpm + + mov r5, #0x0 + sema4_lock + ccm_enter_idle + anatop_enter_idle + sema4_unlock + + /* + * mask all GPC interrupts before + * enabling the RBC counters to + * avoid the counter starting too + * early if an interupt is already + * pending. + */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r4, [r10, #MX6Q_GPC_IMR1] + ldr r5, [r10, #MX6Q_GPC_IMR2] + ldr r6, [r10, #MX6Q_GPC_IMR3] + ldr r7, [r10, #MX6Q_GPC_IMR4] + + ldr r3, =0xffffffff + str r3, [r10, #MX6Q_GPC_IMR1] + str r3, [r10, #MX6Q_GPC_IMR2] + str r3, [r10, #MX6Q_GPC_IMR3] + str r3, [r10, #MX6Q_GPC_IMR4] + + /* + * enable the RBC bypass counter here + * to hold off the interrupts. RBC counter + * = 4 (120us). With this setting, the latency + * from wakeup interrupt to ARM power up + * is ~130uS. + */ + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldr r3, [r10, #MX6Q_CCM_CCR] + bic r3, r3, #(0x3f << 21) + orr r3, r3, #(0x4 << 21) + str r3, [r10, #MX6Q_CCM_CCR] + + /* enable the counter. */ + ldr r3, [r10, #MX6Q_CCM_CCR] + orr r3, r3, #(0x1 << 27) + str r3, [r10, #MX6Q_CCM_CCR] + + /* unmask all the GPC interrupts. */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + str r4, [r10, #MX6Q_GPC_IMR1] + str r5, [r10, #MX6Q_GPC_IMR2] + str r6, [r10, #MX6Q_GPC_IMR3] + str r7, [r10, #MX6Q_GPC_IMR4] + + /* + * now delay for a short while (3usec) + * ARM is at 24MHz at this point + * so a short loop should be enough. + * this delay is required to ensure that + * the RBC counter can start counting in + * case an interrupt is already pending + * or in case an interrupt arrives just + * as ARM is about to assert DSM_request. + */ + ldr r4, =50 +rbc_loop: + subs r4, r4, #0x1 + bne rbc_loop + + wfi + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + mov r5, #0x0 + sema4_lock + anatop_exit_idle + ccm_exit_idle + sema4_unlock + resume_mmdc + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + /* enable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + +#ifdef CONFIG_CACHE_L2X0 + ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + mov r7, #0x1 + /* enable L2 */ + str r7, [r10, #0x100] +#endif + + tlb_back_to_ddr + + /* Restore registers */ + pop {r4 - r10} + mov pc, lr + +wakeup: + + /* invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 6 + /* enable the Icache and branch prediction */ + mov r1, #0x1800 + mcr p15, 0, r1, c1, c0, 0 + isb + /* restore disagnostic register */ + ldr r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET] + mcr p15, 0, r7, c15, c0, 1 + + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + /* clear core0's entry and parameter */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] + mov r7, #0x0 + str r7, [r10, #MX6Q_SRC_GPR1] + str r7, [r10, #MX6Q_SRC_GPR2] + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + mov r5, #0x1 + sema4_lock + anatop_exit_idle + ccm_exit_idle + sema4_unlock + resume_mmdc + + /* Restore registers */ + mov pc, lr + .ltorg +mx6sx_lpm_wfi_end: diff --git a/arch/arm/mach-imx/imx6ul_low_power_idle.S b/arch/arm/mach-imx/imx6ul_low_power_idle.S new file mode 100644 index 000000000000..26bb83da1a7d --- /dev/null +++ b/arch/arm/mach-imx/imx6ul_low_power_idle.S @@ -0,0 +1,821 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define PM_INFO_PBASE_OFFSET 0x0 +#define PM_INFO_RESUME_ADDR_OFFSET 0x4 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x8 +#define PM_INFO_PM_INFO_TTBR_OFFSET 0xc +#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 +#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 +#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x18 +#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x1c +#define PM_INFO_MX6Q_CCM_P_OFFSET 0x20 +#define PM_INFO_MX6Q_CCM_V_OFFSET 0x24 +#define PM_INFO_MX6Q_GPC_P_OFFSET 0x28 +#define PM_INFO_MX6Q_GPC_V_OFFSET 0x2c +#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x30 +#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x34 +#define PM_INFO_MX6Q_SRC_P_OFFSET 0x38 +#define PM_INFO_MX6Q_SRC_V_OFFSET 0x3c +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x40 +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x44 + +#define MX6Q_MMDC_MAPSR 0x404 +#define MX6Q_MMDC_MPDGCTRL0 0x83c +#define MX6Q_SRC_GPR1 0x20 +#define MX6Q_SRC_GPR2 0x24 +#define MX6Q_GPC_IMR1 0x08 +#define MX6Q_GPC_IMR2 0x0c +#define MX6Q_GPC_IMR3 0x10 +#define MX6Q_GPC_IMR4 0x14 +#define MX6Q_CCM_CCR 0x0 + +.globl mx6ul_lpm_wfi_start +.globl mx6ul_lpm_wfi_end + + .macro pll_do_wait_lock +1: + ldr r7, [r10, r8] + ands r7, #0x80000000 + beq 1b + + .endm + + .macro ccm_do_wait +2: + ldr r7, [r10, #0x48] + cmp r7, #0x0 + bne 2b + + .endm + + .macro ccm_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + + /* set ahb to 3MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x1c00 + str r7, [r10, #0x14] + + /* set perclk to 6MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + orr r7, r7, #0x3 + str r7, [r10, #0x1c] + + /* set mmdc to 1MHz, periph2_clk2 need to be @8MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x2 + orr r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + ccm_do_wait + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* bypass PLL1 output to OSC */ + ldr r7, [r10] + orr r7, r7, #(0x1 << 16) + str r7, [r10] + + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + + /* set pll1_sw to from pll1 main */ + ldr r7, [r10, #0xc] + bic r7, r7, #0x4 + str r7, [r10, #0xc] + + /* set step from osc */ + ldr r7, [r10, #0xc] + bic r7, r7, #0x100 + str r7, [r10, #0xc] + + /* set pll1_sw to from step */ + ldr r7, [r10, #0xc] + orr r7, r7, #0x4 + str r7, [r10, #0xc] + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* Disable PLL1 bypass output */ + ldr r7, [r10] + bic r7, r7, #0x12000 + str r7, [r10] + + /* + * disable pll2, suppose when system enter low + * power idle mode, only 396MHz pfd needs pll2, + * now we switch arm clock to OSC, we can disable + * pll2 now, gate pll2_pfd2 first. + */ + ldr r7, [r10, #0x100] + orr r7, #0x800000 + str r7, [r10, #0x100] + + ldr r7, [r10, #0x30] + orr r7, r7, #0x1000 + bic r7, r7, #0x2000 + str r7, [r10, #0x30] + + .endm + + .macro ccm_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* enable pll2 and pll2_pfd2 */ + ldr r7, [r10, #0x30] + bic r7, r7, #0x1000 + orr r7, r7, #0x2000 + str r7, [r10, #0x30] + + ldr r8, =0x30 + pll_do_wait_lock + + ldr r7, [r10, #0x100] + bic r7, #0x800000 + str r7, [r10, #0x100] + + /* enable PLL1 bypass output */ + ldr r7, [r10] + orr r7, r7, #0x12000 + str r7, [r10] + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_CCM_P_OFFSET] + + /* set perclk back to 24MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + str r7, [r10, #0x1c] + + /* set mmdc back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x7 + bic r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + /* set ahb div back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x1c00 + str r7, [r10, #0x14] + + ccm_do_wait + + /* set pll1_sw to from pll1 main */ + ldr r7, [r10, #0xc] + bic r7, r7, #0x4 + str r7, [r10, #0xc] + + /* set step from pll2_pfd2 */ + ldr r7, [r10, #0xc] + orr r7, r7, #0x100 + str r7, [r10, #0xc] + + /* set pll1_sw to from step */ + ldr r7, [r10, #0xc] + orr r7, r7, #0x4 + str r7, [r10, #0xc] + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* Unbypass PLL1 */ + ldr r7, [r10] + bic r7, r7, #(0x1 << 16) + str r7, [r10] + + .endm + + .macro anatop_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* + * check whether any PLL is enabled, as only when + * there is no PLLs enabled, 2P5 and 1P1 can be + * off and only enable weak ones. + */ + + /* arm pll1 */ + ldr r7, [r10, #0] + ands r7, r7, #(1 << 31) + bne 10f + + /* sys pll2 */ + ldr r7, [r10, #0x30] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb pll3 */ + ldr r7, [r10, #0x10] + ands r7, r7, #(1 << 31) + bne 10f + + /* audio pll4 */ + ldr r7, [r10, #0x70] + ands r7, r7, #(1 << 31) + bne 10f + + /* vidio pll5 */ + ldr r7, [r10, #0xa0] + ands r7, r7, #(1 << 31) + bne 10f + + /* enet pll6 */ + ldr r7, [r10, #0xe0] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb host pll7 */ + ldr r7, [r10, #0x20] + ands r7, r7, #(1 << 31) + bne 10f + + /* enable weak 2P5 and turn off regular 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x40000 + str r7, [r10, #0x130] + bic r7, r7, #0x1 + str r7, [r10, #0x130] + + /* enable weak 1p1 and turn off regular 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x40000 + str r7, [r10, #0x110] + bic r7, r7, #0x1 + str r7, [r10, #0x110] + + /* check whether ARM LDO is bypassed */ + ldr r7, [r10, #0x140] + and r7, r7, #0x1f + cmp r7, #0x1f + bne 10f + + /* low power band gap enable */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x20 + str r7, [r10, #0x270] + + /* turn off the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x80 + str r7, [r10, #0x270] + + /* + * clear the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn off regular bandgap */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1 + str r7, [r10, #0x150] + + /* switch to RC-OSC */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x40000000 + str r7, [r10, #0x150] +10: + /* lower OSC current by 37.5% */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* disconnect vdd_high_in and vdd_snvs_in */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1000 + str r7, [r10, #0x150] + + .endm + + .macro anatop_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* increase OSC current to normal */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* turn on XTAL-OSC and detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x40000000 + orr r7, r7, #0x10000 + str r7, [r10, #0x150] + + /* wait for XTAL stable */ +14: + ldr r7, [r10, #0x150] + ands r7, r7, #0x8000 + beq 14b + + /* switch to XTAL-OSC */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x10000 + str r7, [r10, #0x150] +15: + /* check whether we need to enable 2P5/1P1 */ + ldr r7, [r10, #0x110] + ands r7, r7, #0x40000 + beq 11f + + /* check whether ARM LDO is bypassed */ + ldr r7, [r10, #0x140] + and r7, r7, #0x1f + cmp r7, #0x1f + bne 12f + + /* turn on regular bandgap and wait for stable */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x1 + str r7, [r10, #0x150] +13: + ldr r7, [r10, #0x150] + ands r7, #0x80 + beq 13b + + /* + * set the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn on the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x80 + str r7, [r10, #0x270] + + /* low power band gap disable */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x20 + str r7, [r10, #0x270] +12: + /* enable regular 2P5 and turn off weak 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x1 + str r7, [r10, #0x130] + + /* Ensure the 2P5 is up. */ +3: + ldr r7, [r10, #0x130] + ands r7, r7, #0x20000 + beq 3b + ldr r7, [r10, #0x130] + bic r7, r7, #0x40000 + str r7, [r10, #0x130] + + /* enable regular 1p1 and turn off weak 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x1 + str r7, [r10, #0x110] +4: + ldr r7, [r10, #0x110] + ands r7, r7, #0x20000 + beq 4b + ldr r7, [r10, #0x110] + bic r7, r7, #0x40000 + str r7, [r10, #0x110] +11: + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro mmdc_enter_dvfs_mode + + /* disable automatic power savings. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + /* disable power down timer */ + ldr r7, [r10, #0x4] + bic r7, r7, #0xff00 + str r7, [r10, #0x4] + + /* make the DDR explicitly enter self-refresh. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +5: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + beq 5b + + .endm + + .macro resume_mmdc + + /* restore MMDC IO */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] + + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +6: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 6b + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] + + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +7: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 7b + + /* reset FIFO a second time */ + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +8: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 8b + + /* let DDR out of self-refresh */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +9: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + bne 9b + + /* enable power down timer */ + ldr r7, [r10, #0x4] + orr r7, r7, #0x5500 + str r7, [r10, #0x4] + + /* enable DDR auto power saving */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + .endm + + .macro tlb_set_to_ocram + + /* save ttbr */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro tlb_back_to_ddr + + /* Restore the TTBCR */ + + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* restore ttbr */ + ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + +.extern iram_tlb_phys_addr + +/* imx6ul_low_power_idle */ + + .align 3 +ENTRY(imx6ul_low_power_idle) +mx6ul_lpm_wfi_start: + push {r4 - r10} + + /* get necessary info from pm_info */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r5, =imx6ul_low_power_idle + ldr r6, =wakeup + sub r6, r6, r5 + add r8, r1, r2 + add r3, r8, r6 + + /* store physical resume addr and pm_info address. */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] + str r3, [r10, #0x20] + str r1, [r10, #0x24] + + /* set ARM power to be gated */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x1 + str r7, [r10, #0x2a0] + + disable_l1_dcache + + tlb_set_to_ocram + + /* make sure MMDC in self-refresh */ + ldr r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + mmdc_enter_dvfs_mode + + /* save DDR IO settings */ + ldr r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldr r6, =0x0 + ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET + add r8, r8, r0 +save_and_set_mmdc_io_lpm: + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + subs r7, r7, #0x1 + bne save_and_set_mmdc_io_lpm + + mov r5, #0x0 + ccm_enter_idle + anatop_enter_idle + + /* + * mask all GPC interrupts before + * enabling the RBC counters to + * avoid the counter starting too + * early if an interupt is already + * pending. + */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r4, [r10, #MX6Q_GPC_IMR1] + ldr r5, [r10, #MX6Q_GPC_IMR2] + ldr r6, [r10, #MX6Q_GPC_IMR3] + ldr r7, [r10, #MX6Q_GPC_IMR4] + + ldr r3, =0xffffffff + str r3, [r10, #MX6Q_GPC_IMR1] + str r3, [r10, #MX6Q_GPC_IMR2] + str r3, [r10, #MX6Q_GPC_IMR3] + str r3, [r10, #MX6Q_GPC_IMR4] + + /* + * enable the RBC bypass counter here + * to hold off the interrupts. RBC counter + * = 4 (120us). With this setting, the latency + * from wakeup interrupt to ARM power up + * is ~130uS. + */ + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldr r3, [r10, #MX6Q_CCM_CCR] + bic r3, r3, #(0x3f << 21) + orr r3, r3, #(0x4 << 21) + str r3, [r10, #MX6Q_CCM_CCR] + + /* enable the counter. */ + ldr r3, [r10, #MX6Q_CCM_CCR] + orr r3, r3, #(0x1 << 27) + str r3, [r10, #MX6Q_CCM_CCR] + + /* unmask all the GPC interrupts. */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + str r4, [r10, #MX6Q_GPC_IMR1] + str r5, [r10, #MX6Q_GPC_IMR2] + str r6, [r10, #MX6Q_GPC_IMR3] + str r7, [r10, #MX6Q_GPC_IMR4] + + /* + * now delay for a short while (3usec) + * ARM is at 24MHz at this point + * so a short loop should be enough. + * this delay is required to ensure that + * the RBC counter can start counting in + * case an interrupt is already pending + * or in case an interrupt arrives just + * as ARM is about to assert DSM_request. + */ + ldr r4, =50 +rbc_loop: + subs r4, r4, #0x1 + bne rbc_loop + + wfi + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + mov r5, #0x0 + anatop_exit_idle + ccm_exit_idle + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + resume_mmdc + /* enable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + + tlb_back_to_ddr + + /* Restore registers */ + pop {r4 - r10} + mov pc, lr + +wakeup: + /* invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 6 + /* enable the Icache and branch prediction */ + mov r1, #0x1800 + mcr p15, 0, r1, c1, c0, 0 + isb + + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + /* clear core0's entry and parameter */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] + mov r7, #0x0 + str r7, [r10, #MX6Q_SRC_GPR1] + str r7, [r10, #MX6Q_SRC_GPR2] + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + mov r5, #0x1 + anatop_exit_idle + ccm_exit_idle + resume_mmdc + + /* Restore registers */ + mov pc, lr + .ltorg +mx6ul_lpm_wfi_end: diff --git a/arch/arm/mach-imx/imx6ull_low_power_idle.S b/arch/arm/mach-imx/imx6ull_low_power_idle.S new file mode 100644 index 000000000000..76ceac7fae26 --- /dev/null +++ b/arch/arm/mach-imx/imx6ull_low_power_idle.S @@ -0,0 +1,764 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define PM_INFO_PBASE_OFFSET 0x0 +#define PM_INFO_RESUME_ADDR_OFFSET 0x4 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x8 +#define PM_INFO_PM_INFO_TTBR_OFFSET 0xc +#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 +#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 +#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x18 +#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x1c +#define PM_INFO_MX6Q_CCM_P_OFFSET 0x20 +#define PM_INFO_MX6Q_CCM_V_OFFSET 0x24 +#define PM_INFO_MX6Q_GPC_P_OFFSET 0x28 +#define PM_INFO_MX6Q_GPC_V_OFFSET 0x2c +#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x30 +#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x34 +#define PM_INFO_MX6Q_SRC_P_OFFSET 0x38 +#define PM_INFO_MX6Q_SRC_V_OFFSET 0x3c +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x40 +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x44 + +#define MX6Q_MMDC_MAPSR 0x404 +#define MX6Q_MMDC_MPDGCTRL0 0x83c +#define MX6Q_SRC_GPR1 0x20 +#define MX6Q_SRC_GPR2 0x24 +#define MX6Q_GPC_IMR1 0x08 +#define MX6Q_GPC_IMR2 0x0c +#define MX6Q_GPC_IMR3 0x10 +#define MX6Q_GPC_IMR4 0x14 +#define MX6Q_CCM_CCR 0x0 + +.globl mx6ull_lpm_wfi_start +.globl mx6ull_lpm_wfi_end + + .macro pll_do_wait_lock +1: + ldr r7, [r10, r8] + ands r7, #0x80000000 + beq 1b + + .endm + + .macro ccm_do_wait +2: + ldr r7, [r10, #0x48] + cmp r7, #0x0 + bne 2b + + .endm + + .macro ccm_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + + /* set ahb to 3MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x1c00 + str r7, [r10, #0x14] + + /* set perclk to 6MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + orr r7, r7, #0x3 + str r7, [r10, #0x1c] + + /* set mmdc to 1MHz, periph2_clk2 need to be @8MHz */ + ldr r7, [r10, #0x14] + orr r7, r7, #0x2 + orr r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + ccm_do_wait + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* + * disable pll2, suppose when system enter low + * power idle mode, only 396MHz pfd needs pll2, + * now we switch arm clock to OSC, we can disable + * pll2 now, gate pll2_pfd2 first. + */ + ldr r7, [r10, #0x100] + orr r7, #0x800000 + str r7, [r10, #0x100] + + ldr r7, [r10, #0x30] + orr r7, r7, #0x1000 + bic r7, r7, #0x2000 + str r7, [r10, #0x30] + + .endm + + .macro ccm_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* enable pll2 and pll2_pfd2 */ + ldr r7, [r10, #0x30] + bic r7, r7, #0x1000 + orr r7, r7, #0x2000 + str r7, [r10, #0x30] + + ldr r8, =0x30 + pll_do_wait_lock + + ldr r7, [r10, #0x100] + bic r7, #0x800000 + str r7, [r10, #0x100] + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_CCM_P_OFFSET] + + /* set perclk back to 24MHz */ + ldr r7, [r10, #0x1c] + bic r7, r7, #0x3f + str r7, [r10, #0x1c] + + /* set mmdc back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x7 + bic r7, r7, #(0x7 << 3) + str r7, [r10, #0x14] + + /* set ahb div back to 24MHz */ + ldr r7, [r10, #0x14] + bic r7, r7, #0x1c00 + str r7, [r10, #0x14] + + ccm_do_wait + + .endm + + .macro anatop_enter_idle + + ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + + /* + * check whether any PLL is enabled, as only when + * there is no PLLs enabled, 2P5 and 1P1 can be + * off and only enable weak ones. + */ + + /* arm pll1 */ + ldr r7, [r10, #0] + ands r7, r7, #(1 << 31) + bne 10f + + /* sys pll2 */ + ldr r7, [r10, #0x30] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb pll3 */ + ldr r7, [r10, #0x10] + ands r7, r7, #(1 << 31) + bne 10f + + /* audio pll4 */ + ldr r7, [r10, #0x70] + ands r7, r7, #(1 << 31) + bne 10f + + /* vidio pll5 */ + ldr r7, [r10, #0xa0] + ands r7, r7, #(1 << 31) + bne 10f + + /* enet pll6 */ + ldr r7, [r10, #0xe0] + ands r7, r7, #(1 << 31) + bne 10f + + /* usb host pll7 */ + ldr r7, [r10, #0x20] + ands r7, r7, #(1 << 31) + bne 10f + + /* enable weak 2P5 and turn off regular 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x40000 + str r7, [r10, #0x130] + bic r7, r7, #0x1 + str r7, [r10, #0x130] + + /* enable weak 1p1 and turn off regular 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x40000 + str r7, [r10, #0x110] + bic r7, r7, #0x1 + str r7, [r10, #0x110] + + /* check whether ARM LDO is bypassed */ + ldr r7, [r10, #0x140] + and r7, r7, #0x1f + cmp r7, #0x1f + bne 10f + + /* low power band gap enable */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x20 + str r7, [r10, #0x270] + + /* turn off the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x80 + str r7, [r10, #0x270] + + /* + * clear the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn off regular bandgap */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1 + str r7, [r10, #0x150] + +10: + /* switch to RC-OSC */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x40000000 + str r7, [r10, #0x150] + + /* lower OSC current by 37.5% */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* disconnect vdd_high_in and vdd_snvs_in */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x1000 + str r7, [r10, #0x150] + + .endm + + .macro anatop_exit_idle + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + + /* increase OSC current to normal */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x6000 + str r7, [r10, #0x150] + + /* turn on XTAL-OSC and detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x40000000 + orr r7, r7, #0x10000 + str r7, [r10, #0x150] + + /* wait for XTAL stable */ +14: + ldr r7, [r10, #0x150] + ands r7, r7, #0x8000 + beq 14b + + /* switch to XTAL-OSC */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x10 + str r7, [r10, #0x270] + + /* turn off XTAL-OSC detector */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x10000 + str r7, [r10, #0x150] +15: + /* check whether we need to enable 2P5/1P1 */ + ldr r7, [r10, #0x110] + ands r7, r7, #0x40000 + beq 11f + + /* check whether ARM LDO is bypassed */ + ldr r7, [r10, #0x140] + and r7, r7, #0x1f + cmp r7, #0x1f + bne 12f + + /* turn on regular bandgap and wait for stable */ + ldr r7, [r10, #0x150] + bic r7, r7, #0x1 + str r7, [r10, #0x150] +13: + ldr r7, [r10, #0x150] + ands r7, #0x80 + beq 13b + + /* + * set the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + */ + ldr r7, [r10, #0x150] + orr r7, r7, #0x8 + str r7, [r10, #0x150] + + /* turn on the bias current from the regular bandgap */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x80 + str r7, [r10, #0x270] + + /* low power band gap disable */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x20 + str r7, [r10, #0x270] +12: + /* enable regular 2P5 and turn off weak 2P5 */ + ldr r7, [r10, #0x130] + orr r7, r7, #0x1 + str r7, [r10, #0x130] + + /* Ensure the 2P5 is up. */ +3: + ldr r7, [r10, #0x130] + ands r7, r7, #0x20000 + beq 3b + ldr r7, [r10, #0x130] + bic r7, r7, #0x40000 + str r7, [r10, #0x130] + + /* enable regular 1p1 and turn off weak 1P1 */ + ldr r7, [r10, #0x110] + orr r7, r7, #0x1 + str r7, [r10, #0x110] +4: + ldr r7, [r10, #0x110] + ands r7, r7, #0x20000 + beq 4b + ldr r7, [r10, #0x110] + bic r7, r7, #0x40000 + str r7, [r10, #0x110] +11: + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro mmdc_enter_dvfs_mode + + /* disable automatic power savings. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + /* disable power down timer */ + ldr r7, [r10, #0x4] + bic r7, r7, #0xff00 + str r7, [r10, #0x4] + + /* make the DDR explicitly enter self-refresh. */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +5: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + beq 5b + + .endm + + .macro resume_mmdc + + /* restore MMDC IO */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] + + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +6: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 6b + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] + + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +7: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 7b + + /* reset FIFO a second time */ + ldr r6, [r10, r7] + orr r6, r6, #(1 << 31) + str r6, [r10, r7] +8: + ldr r6, [r10, r7] + ands r6, r6, #(1 << 31) + bne 8b + + /* let DDR out of self-refresh */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 21) + str r7, [r10, #MX6Q_MMDC_MAPSR] +9: + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + bne 9b + + /* enable power down timer */ + ldr r7, [r10, #0x4] + orr r7, r7, #0x5500 + str r7, [r10, #0x4] + + /* enable DDR auto power saving */ + ldr r7, [r10, #MX6Q_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r10, #MX6Q_MMDC_MAPSR] + + .endm + + .macro tlb_set_to_ocram + + /* save ttbr */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro tlb_back_to_ddr + + /* Restore the TTBCR */ + + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* restore ttbr */ + ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + +.extern iram_tlb_phys_addr + +/* imx6ull_low_power_idle */ + + .align 3 +ENTRY(imx6ull_low_power_idle) +mx6ull_lpm_wfi_start: + push {r4 - r10} + + /* get necessary info from pm_info */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r5, =imx6ull_low_power_idle + ldr r6, =wakeup + sub r6, r6, r5 + add r8, r1, r2 + add r3, r8, r6 + + /* store physical resume addr and pm_info address. */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] + str r3, [r10, #0x20] + str r1, [r10, #0x24] + + /* set ARM power to be gated */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x1 + str r7, [r10, #0x2a0] + + disable_l1_dcache + + tlb_set_to_ocram + + /* make sure MMDC in self-refresh */ + ldr r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + mmdc_enter_dvfs_mode + + /* save DDR IO settings */ + ldr r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldr r6, =0x0 + ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET + add r8, r8, r0 +save_and_set_mmdc_io_lpm: + ldr r9, [r8], #0x4 + ldr r5, [r10, r9] + str r6, [r10, r9] + str r5, [r8], #0x4 + subs r7, r7, #0x1 + bne save_and_set_mmdc_io_lpm + + mov r5, #0x0 + ccm_enter_idle + anatop_enter_idle + + /* + * mask all GPC interrupts before + * enabling the RBC counters to + * avoid the counter starting too + * early if an interupt is already + * pending. + */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r4, [r10, #MX6Q_GPC_IMR1] + ldr r5, [r10, #MX6Q_GPC_IMR2] + ldr r6, [r10, #MX6Q_GPC_IMR3] + ldr r7, [r10, #MX6Q_GPC_IMR4] + + ldr r3, =0xffffffff + str r3, [r10, #MX6Q_GPC_IMR1] + str r3, [r10, #MX6Q_GPC_IMR2] + str r3, [r10, #MX6Q_GPC_IMR3] + str r3, [r10, #MX6Q_GPC_IMR4] + + /* + * enable the RBC bypass counter here + * to hold off the interrupts. RBC counter + * = 4 (120us). With this setting, the latency + * from wakeup interrupt to ARM power up + * is ~130uS. + */ + ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] + ldr r3, [r10, #MX6Q_CCM_CCR] + bic r3, r3, #(0x3f << 21) + orr r3, r3, #(0x4 << 21) + str r3, [r10, #MX6Q_CCM_CCR] + + /* enable the counter. */ + ldr r3, [r10, #MX6Q_CCM_CCR] + orr r3, r3, #(0x1 << 27) + str r3, [r10, #MX6Q_CCM_CCR] + + /* unmask all the GPC interrupts. */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + str r4, [r10, #MX6Q_GPC_IMR1] + str r5, [r10, #MX6Q_GPC_IMR2] + str r6, [r10, #MX6Q_GPC_IMR3] + str r7, [r10, #MX6Q_GPC_IMR4] + + /* + * now delay for a short while (3usec) + * ARM is at 24MHz at this point + * so a short loop should be enough. + * this delay is required to ensure that + * the RBC counter can start counting in + * case an interrupt is already pending + * or in case an interrupt arrives just + * as ARM is about to assert DSM_request. + */ + ldr r4, =50 +rbc_loop: + subs r4, r4, #0x1 + bne rbc_loop + + wfi + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + mov r5, #0x0 + anatop_exit_idle + ccm_exit_idle + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + resume_mmdc + /* enable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + + tlb_back_to_ddr + + /* Restore registers */ + pop {r4 - r10} + mov pc, lr + +wakeup: + /* invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 6 + /* enable the Icache and branch prediction */ + mov r1, #0x1800 + mcr p15, 0, r1, c1, c0, 0 + isb + + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + /* clear core0's entry and parameter */ + ldr r10, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] + mov r7, #0x0 + str r7, [r10, #MX6Q_SRC_GPR1] + str r7, [r10, #MX6Q_SRC_GPR2] + + /* clear ARM power gate setting */ + ldr r10, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] + ldr r7, =0x0 + str r7, [r10, #0x2a0] + + mov r5, #0x1 + anatop_exit_idle + ccm_exit_idle + resume_mmdc + + /* Restore registers */ + mov pc, lr + .ltorg +mx6ull_lpm_wfi_end: diff --git a/arch/arm/mach-imx/imx7d_low_power_idle.S b/arch/arm/mach-imx/imx7d_low_power_idle.S new file mode 100644 index 000000000000..cad438ec7f97 --- /dev/null +++ b/arch/arm/mach-imx/imx7d_low_power_idle.S @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define PM_INFO_VBASE_OFFSET 0x0 +#define PM_INFO_PBASE_OFFSET 0x4 +#define PM_INFO_RESUME_ADDR_OFFSET 0x8 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0xc +#define PM_INFO_PM_INFO_TTBR_OFFSET 0x10 +#define PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET 0x14 +#define PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET 0x18 +#define PM_INFO_VAL_OFFSET 0x1c +#define PM_INFO_FLAG0_OFFSET 0x20 +#define PM_INFO_FLAG1_OFFSET 0x24 +#define PM_INFO_MX7D_DDRC_P_OFFSET 0x28 +#define PM_INFO_MX7D_DDRC_V_OFFSET 0x2c +#define PM_INFO_MX7D_CCM_P_OFFSET 0x30 +#define PM_INFO_MX7D_CCM_V_OFFSET 0x34 +#define PM_INFO_MX7D_ANATOP_P_OFFSET 0x38 +#define PM_INFO_MX7D_ANATOP_V_OFFSET 0x3c +#define PM_INFO_MX7D_SRC_P_OFFSET 0x40 +#define PM_INFO_MX7D_SRC_V_OFFSET 0x44 +#define PM_INFO_MX7D_IOMUXC_GPR_P_OFFSET 0x48 +#define PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET 0x4c +#define PM_INFO_MX7D_GPC_P_OFFSET 0x50 +#define PM_INFO_MX7D_GPC_V_OFFSET 0x54 +#define PM_INFO_MX7D_GIC_DIST_P_OFFSET 0x58 +#define PM_INFO_MX7D_GIC_DIST_V_OFFSET 0x5c + +#define MX7D_SRC_GPR1 0x74 +#define MX7D_SRC_GPR2 0x78 +#define MX7D_SRC_GPR3 0x7c +#define MX7D_SRC_GPR4 0x80 +#define MX7D_GPC_IMR1 0x30 +#define MX7D_GPC_IMR2 0x34 +#define MX7D_GPC_IMR3 0x38 +#define MX7D_GPC_IMR4 0x3c +#define DDRC_STAT 0x4 +#define DDRC_PWRCTL 0x30 +#define DDRC_DBG1 0x304 +#define DDRC_DBGCAM 0x308 +#define DDRC_PSTAT 0x3fc +#define DDRC_PCTRL_0 0x490 + +/* + * imx_pen_lock + * + * The reference link of Peterson's algorithm: + * http://en.wikipedia.org/wiki/Peterson's_algorithm + * + * val1 = r1 = !turn (inverted from Peterson's algorithm) + * on cpu 0: + * r2 = flag[0] (in flag0) + * r3 = flag[1] (in flag1) + * on cpu1: + * r2 = flag[1] (in flag1) + * r3 = flag[0] (in flag0) + * + */ + .macro imx_pen_lock + + mov r8, r0 + mrc p15, 0, r5, c0, c0, 5 + and r5, r5, #3 + add r6, r8, #PM_INFO_VAL_OFFSET + cmp r5, #0 + addeq r7, r8, #PM_INFO_FLAG0_OFFSET + addeq r8, r8, #PM_INFO_FLAG1_OFFSET + addne r7, r8, #PM_INFO_FLAG1_OFFSET + addne r8, r8, #PM_INFO_FLAG0_OFFSET + + mov r9, #1 + str r9, [r7] + dsb + str r5, [r6] +1: + dsb + ldr r9, [r8] + cmp r9, #1 + ldreq r9, [r6] + cmpeq r9, r5 + beq 1b + + .endm + + .macro imx_pen_unlock + + dsb + mrc p15, 0, r6, c0, c0, 5 + and r6, r6, #3 + cmp r6, #0 + addeq r7, r0, #PM_INFO_FLAG0_OFFSET + addne r7, r0, #PM_INFO_FLAG1_OFFSET + mov r9, #0 + str r9, [r7] + + .endm + + .macro disable_l1_dcache + + push {r0 - r12, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r12, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r12, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r12, lr} + +#ifdef CONFIG_SMP + clrex + + /* Turn off SMP bit. */ + mrc p15, 0, r8, c1, c0, 1 + bic r8, r8, #0x40 + mcr p15, 0, r8, c1, c0, 1 + + isb + dsb +#endif + + .endm + + .macro tlb_set_to_ocram + + /* save ttbr */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro tlb_back_to_ddr + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* restore ttbr */ + ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + + /* r10 must be DDRC base address */ + .macro ddrc_enter_self_refresh + + ldr r10, [r0, #PM_INFO_MX7D_DDRC_V_OFFSET] + + /* disable port */ + ldr r7, =0x0 + str r7, [r10, #DDRC_PCTRL_0] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r10, #DDRC_PWRCTL] + + /* wait rw port_busy clear */ + ldr r6, =(0x1 << 16) + orr r6, r6, #0x1 +2: + ldr r7, [r10, #DDRC_PSTAT] + ands r7, r7, r6 + bne 2b + + ldr r7, =0x1 + str r7, [r10, #DDRC_DBG1] + + ldr r6, =0x36000000 +11: + ldr r7, [r10, #DDRC_DBGCAM] + and r7, r7, r6 + cmp r7, r6 + bne 11b + + /* enter self-refresh bit 5 */ + ldr r7, =(0x1 << 5) + str r7, [r10, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +3: + ldr r7, [r10, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 3b +4: + ldr r7, [r10, #DDRC_STAT] + ands r7, r7, #0x20 + beq 4b + + /* disable dram clk */ + ldr r7, [r10, #DDRC_PWRCTL] + orr r7, r7, #(1 << 3) + str r7, [r10, #DDRC_PWRCTL] + + /* + * TO1.1 adds feature of DDR pads power down, + * although TO1.0 has no such function, but it is + * NOT harmful to program GPR registers for TO1.0, + * it can avoid the logic of version check in idle + * thread. + */ + ldr r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET] + ldr r7, =0xf0000 + str r7, [r10] + + /* delay 20us, measured by gpio */ + ldr r7, =20 +12: + subs r7, r7, #0x1 + bne 12b + + .endm + + /* r10 must be DDRC base address */ + .macro ddrc_exit_self_refresh + + cmp r5, #0x1 + ldreq r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_P_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET] + + ldr r7, =0x0 + str r7, [r10] + + ldr r7, =20 +13: + subs r7, r7, #0x1 + bne 13b + + cmp r5, #0x1 + ldreq r10, [r0, #PM_INFO_MX7D_DDRC_P_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7D_DDRC_V_OFFSET] + + ldr r7, =0x0 + str r7, [r10, #DDRC_DBG1] + + ldr r6, =0x30000000 +14: + ldr r7, [r10, #DDRC_DBGCAM] + and r7, r7, r6 + cmp r7, r6 + bne 14b + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r10, #DDRC_PWRCTL] + + /* wait until self-refresh mode exited */ +5: + ldr r7, [r10, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + beq 5b + + /* enable auto self-refresh */ + ldr r7, [r10, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r10, #DDRC_PWRCTL] + + ldr r7, =0x1 + str r7, [r10, #DDRC_PCTRL_0] + + .endm + + .macro pll_do_wait_lock +6: + ldr r7, [r10, r8] + ands r7, #0x80000000 + beq 6b + + .endm + + .macro ccm_enter_idle + + ldr r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET] + + /* ungate pfd1 332m for lower axi */ + ldr r7, =0x8000 + str r7, [r10, #0xc8] + + ldr r10, [r0, #PM_INFO_MX7D_CCM_V_OFFSET] + + /* switch ARM CLK to OSC */ + ldr r8, =0x8000 + ldr r7, [r10, r8] + bic r7, r7, #0x7000000 + str r7, [r10, r8] + + /* lower AXI clk from 24MHz to 3MHz */ + ldr r8, =0x8800 + ldr r7, [r10, r8] + orr r7, r7, #0x7 + str r7, [r10, r8] + + /* lower AHB clk from 24MHz to 3MHz */ + ldr r8, =0x9000 + ldr r7, [r10, r8] + orr r7, r7, #0x7 + str r7, [r10, r8] + + /* gate dram clk */ + ldr r8, =0x9880 + ldr r7, [r10, r8] + bic r7, r7, #0x10000000 + str r7, [r10, r8] + + ldr r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET] + + /* gate pfd1 332m */ + ldr r7, =0x8000 + str r7, [r10, #0xc4] + + /* gate system pll pfd div 1 */ + ldr r7, =0x10 + str r7, [r10, #0xb4] + /* power down ARM, 480 and DRAM PLL */ + ldr r7, =0x1000 + str r7, [r10, #0x64] + str r7, [r10, #0xb4] + ldr r7, =0x100000 + str r7, [r10, #0x74] + + .endm + + .macro ccm_exit_idle + + cmp r5, #0x1 + ldreq r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET] + + /* power up ARM, 480 and DRAM PLL */ + ldr r7, =0x1000 + str r7, [r10, #0x68] + ldr r8, =0x60 + pll_do_wait_lock + + ldr r7, =0x1000 + str r7, [r10, #0xb8] + ldr r8, =0xb0 + pll_do_wait_lock + + ldr r7, =0x100000 + str r7, [r10, #0x78] + ldr r8, =0x70 + pll_do_wait_lock + + /* ungate pfd1 332m for lower axi */ + ldr r7, =0x8000 + str r7, [r10, #0xc8] + + /* ungate system pll pfd div 1 */ + ldr r7, =0x10 + str r7, [r10, #0xb8] + + cmp r5, #0x1 + ldreq r10, [r0, #PM_INFO_MX7D_CCM_P_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7D_CCM_V_OFFSET] + + /* switch ARM CLK to PLL */ + ldr r8, =0x8000 + ldr r7, [r10, r8] + orr r7, r7, #0x1000000 + str r7, [r10, r8] + + /* restore AXI clk from 3MHz to 24MHz */ + ldr r8, =0x8800 + ldr r7, [r10, r8] + bic r7, r7, #0x7 + str r7, [r10, r8] + + /* restore AHB clk from 3MHz to 24MHz */ + ldr r8, =0x9000 + ldr r7, [r10, r8] + bic r7, r7, #0x7 + str r7, [r10, r8] + + /* ungate dram clk */ + ldr r8, =0x9880 + ldr r7, [r10, r8] + orr r7, r7, #0x10000000 + str r7, [r10, r8] + + cmp r5, #0x1 + ldreq r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET] + + /* gate pfd1 332m for lower axi */ + ldr r7, =0x8000 + str r7, [r10, #0xc4] + + .endm + + .macro anatop_enter_idle + + ldr r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET] + + /* XTAL to RC-OSC switch */ + ldr r7, [r10] + orr r7, r7, #0x1000 + str r7, [r10] + /* power down XTAL */ + ldr r7, [r10] + orr r7, r7, #0x1 + str r7, [r10] + + /* enable weak 1P0A */ + ldr r7, [r10, #0x200] + orr r7, r7, #0x40000 + str r7, [r10, #0x200] + + /* disable LDO 1P0A */ + ldr r7, [r10, #0x200] + bic r7, r7, #0x1 + str r7, [r10, #0x200] + + /* disable LDO 1P0D */ + ldr r7, [r10, #0x210] + bic r7, r7, #0x1 + str r7, [r10, #0x210] + + /* disable LDO 1P2 */ + ldr r7, [r10, #0x220] + bic r7, r7, #0x1 + str r7, [r10, #0x220] + + /* switch to low power bandgap */ + ldr r7, [r10, #0x270] + orr r7, r7, #0x400 + str r7, [r10, #0x270] + /* power down normal bandgap */ + orr r7, r7, #0x1 + str r7, [r10, #0x270] + + .endm + + .macro anatop_exit_idle + + cmp r5, #0x1 + ldreq r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET] + + /* power on normal bandgap */ + ldr r7, [r10, #0x270] + bic r7, r7, #0x1 + str r7, [r10, #0x270] + /* switch to normal bandgap */ + bic r7, r7, #0x400 + str r7, [r10, #0x270] + + /* enable LDO 1P2 */ + ldr r7, [r10, #0x220] + orr r7, r7, #0x1 + str r7, [r10, #0x220] +7: + ldr r7, [r10, #0x220] + ands r7, #0x20000 + beq 7b + + /* enable LDO 1P0D */ + ldr r7, [r10, #0x210] + orr r7, r7, #0x1 + str r7, [r10, #0x210] +8: + ldr r7, [r10, #0x210] + ands r7, #0x20000 + beq 8b + + /* enable LDO 1P0A */ + ldr r7, [r10, #0x200] + orr r7, r7, #0x1 + str r7, [r10, #0x200] +9: + ldr r7, [r10, #0x200] + ands r7, #0x20000 + beq 9b + /* disable weak 1P0A */ + ldr r7, [r10, #0x200] + bic r7, r7, #0x40000 + str r7, [r10, #0x200] + + /* power up XTAL and wait */ + ldr r7, [r10] + bic r7, r7, #0x1 + str r7, [r10] +10: + ldr r7, [r10] + ands r7, r7, #0x4 + beq 10b + /* RC-OSC to XTAL switch */ + ldr r7, [r10] + bic r7, r7, #0x1000 + str r7, [r10] + + .endm + +.extern iram_tlb_phys_addr + + .align 3 +ENTRY(imx7d_low_power_idle) + push {r0 - r12} + + /* get necessary info from pm_info */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r5, =imx7d_low_power_idle + ldr r6, =wakeup + sub r6, r6, r5 + add r8, r1, r2 + add r3, r8, r6 + + /* r11 is cpu id */ + mrc p15, 0, r11, c0, c0, 5 + and r11, r11, #3 + cmp r11, #0x0 + ldreq r6, =MX7D_SRC_GPR1 + ldreq r7, =MX7D_SRC_GPR2 + ldrne r6, =MX7D_SRC_GPR3 + ldrne r7, =MX7D_SRC_GPR4 + /* store physical resume addr and pm_info address. */ + ldr r10, [r0, #PM_INFO_MX7D_SRC_V_OFFSET] + str r3, [r10, r6] + str r1, [r10, r7] + + disable_l1_dcache + + tlb_set_to_ocram + + /* check last to sleep */ + ldr r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET] + ldr r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET] + cmp r6, r7 + bne lpi_enter_done + + ddrc_enter_self_refresh + ccm_enter_idle + anatop_enter_idle + + ldr r10, [r0, #PM_INFO_MX7D_GIC_DIST_V_OFFSET] + ldr r7, =0x0 + ldr r8, =0x1000 + str r7, [r10, r8] + + ldr r10, [r0, #PM_INFO_MX7D_GPC_V_OFFSET] + ldr r4, [r10, #MX7D_GPC_IMR1] + ldr r5, [r10, #MX7D_GPC_IMR2] + ldr r6, [r10, #MX7D_GPC_IMR3] + ldr r7, [r10, #MX7D_GPC_IMR4] + + ldr r8, =0xffffffff + str r8, [r10, #MX7D_GPC_IMR1] + str r8, [r10, #MX7D_GPC_IMR2] + str r8, [r10, #MX7D_GPC_IMR3] + str r8, [r10, #MX7D_GPC_IMR4] + + /* + * enable the RBC bypass counter here + * to hold off the interrupts. RBC counter + * = 8 (2ms). With this setting, the latency + * from wakeup interrupt to ARM power up + * is ~2ms. + */ + ldr r8, [r10, #0x14] + orr r8, r8, #(0x3f << 24) + str r8, [r10, #0x14] + + /* enable the counter. */ + ldr r8, [r10, #0x14] + orr r8, r8, #(0x1 << 30) + str r8, [r10, #0x14] + + /* unmask all the GPC interrupts. */ + str r4, [r10, #MX7D_GPC_IMR1] + str r5, [r10, #MX7D_GPC_IMR2] + str r6, [r10, #MX7D_GPC_IMR3] + str r7, [r10, #MX7D_GPC_IMR4] + + /* + * now delay for a short while (30usec) + * ARM is at 24MHz at this point + * so a short loop should be enough. + * this delay is required to ensure that + * the RBC counter can start counting in + * case an interrupt is already pending + * or in case an interrupt arrives just + * as ARM is about to assert DSM_request. + */ + ldr r4, =5 +rbc_loop: + subs r4, r4, #0x1 + bne rbc_loop + +lpi_enter_done: + + imx_pen_unlock + + wfi + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + imx_pen_lock + + /* check first to wake */ + ldr r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET] + ldr r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET] + cmp r6, r7 + bne skip_lpi_flow + + ldr r5, =0x0 + anatop_exit_idle + ccm_exit_idle + ddrc_exit_self_refresh + + ldr r10, [r0, #PM_INFO_MX7D_GIC_DIST_V_OFFSET] + ldr r7, =0x1 + ldr r8, =0x1000 + str r7, [r10, r8] + +skip_lpi_flow: + tlb_back_to_ddr + +#ifdef CONFIG_SMP + /* Turn on SMP bit. */ + mrc p15, 0, r7, c1, c0, 1 + orr r7, r7, #0x40 + mcr p15, 0, r7, c1, c0, 1 + + isb +#endif + + /* enable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + orr r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + /* Restore registers */ + pop {r0 - r12} + mov pc, lr + +wakeup: + + /* invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 0 + mcr p15, 0, r1, c7, c5, 6 + /* enable the Icache and branch prediction */ + mov r1, #0x1800 + mcr p15, 0, r1, c1, c0, 0 + isb + + imx_pen_lock + + /* check first to wake */ + ldr r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET] + ldr r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET] + cmp r6, r7 + bne wakeup_skip_lpi_flow + + ldr r5, =0x1 + anatop_exit_idle + ccm_exit_idle + ddrc_exit_self_refresh + +wakeup_skip_lpi_flow: + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + + /* Restore registers */ + mov pc, lr + .ltorg +ENDPROC(imx7d_low_power_idle) diff --git a/arch/arm/mach-imx/lpddr2_freq_imx6.S b/arch/arm/mach-imx/lpddr2_freq_imx6.S new file mode 100644 index 000000000000..21179fb2cb72 --- /dev/null +++ b/arch/arm/mach-imx/lpddr2_freq_imx6.S @@ -0,0 +1,618 @@ +/* + * Copyright (C) 2012-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include "hardware.h" + +#define PL310_AUX_CTRL 0x104 +#define PL310_DCACHE_LOCKDOWN_BASE 0x900 +#define PL310_AUX_16WAY_BIT 0x10000 +#define PL310_LOCKDOWN_NBREGS 8 +#define PL310_LOCKDOWN_SZREG 4 +#define PL310_8WAYS_MASK 0x00FF +#define PL310_16WAYS_UPPERMASK 0xFF00 + +.globl imx6_lpddr2_freq_change_start +.globl imx6_lpddr2_freq_change_end + + .macro mx6sl_switch_to_24MHz + + /* + * Set MMDC clock to be sourced from PLL3. + * Ensure first periph2_clk2 is sourced from PLL3. + * Set the PERIPH2_CLK2_PODF to divide by 2. + */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x7 + orr r6, r6, #0x1 + str r6, [r2, #0x14] + + /* Select PLL3 to source MMDC. */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* Swtich periph2_clk_sel to run from PLL3. */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch1: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch1 + + /* + * Need to clock gate the 528 PFDs before + * powering down PLL2. + * Only the PLL2_PFD2_400M should be ON + * at this time, so only clock gate that one. + */ + ldr r6, [r3, #0x100] + orr r6, r6, #0x800000 + str r6, [r3, #0x100] + + /* + * Set PLL2 to bypass state. We should be here + * only if MMDC is not sourced from PLL2. + */ + ldr r6, [r3, #0x30] + orr r6, r6, #0x10000 + str r6, [r3, #0x30] + + ldr r6, [r3, #0x30] + orr r6, r6, #0x1000 + str r6, [r3, #0x30] + + /* Ensure pre_periph2_clk_mux is set to pll2 */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x600000 + str r6, [r2, #0x18] + + /* Set MMDC clock to be sourced from the bypassed PLL2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch2: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch2 + + /* + * Now move MMDC back to periph2_clk2 source. + * after selecting PLL2 as the option. + * Select PLL2 as the source. + */ + ldr r6, [r2, #0x18] + orr r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* set periph2_clk2_podf to divide by 1. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x7 + str r6, [r2, #0x14] + + /* Now move periph2_clk to periph2_clk2 source */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch3: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch3 + + /* Now set the MMDC PODF back to 1.*/ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + str r6, [r2, #0x14] + +mmdc_podf0: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf0 + + .endm + + .macro ddr_switch_400MHz + + /* Set MMDC divider first, in case PLL3 is at 480MHz. */ + ldr r6, [r3, #0x10] + and r6, r6, #0x10000 + cmp r6, #0x10000 + beq pll3_in_bypass + + /* Set MMDC divder to divide by 2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x8 + str r6, [r2, #0x14] + +mmdc_podf: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf + +pll3_in_bypass: + /* + * Check if we are switching between + * 400Mhz <-> 100MHz.If so, we should + * try to source MMDC from PLL2_200M. + */ + cmp r1, #0 + beq not_low_bus_freq + + /* Ensure that MMDC is sourced from PLL2 mux first. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch4: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch4 + +not_low_bus_freq: + /* Now ensure periph2_clk2_sel mux is set to PLL3 */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* Now switch MMDC to PLL3. */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch5: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch5 + + /* + * Check if PLL2 is already unlocked. + * If so do nothing with PLL2. + */ + cmp r1, #0 + beq pll2_already_on + + /* Now power up PLL2 and unbypass it. */ + ldr r6, [r3, #0x30] + bic r6, r6, #0x1000 + str r6, [r3, #0x30] + + /* Make sure PLL2 has locked.*/ +wait_for_pll_lock: + ldr r6, [r3, #0x30] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock + + ldr r6, [r3, #0x30] + bic r6, r6, #0x10000 + str r6, [r3, #0x30] + + /* + * Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r3, #0x100] + bic r6, r6, #0x800000 + str r6, [r3, #0x100] + +pll2_already_on: + /* + * Now switch MMDC clk back to pll2_mux option. + * Ensure pre_periph2_clk2 is set to pll2_pfd_400M. + * If switching to audio DDR freq, set the + * pre_periph2_clk2 to PLL2_PFD_200M + */ + ldr r6, =400000000 + cmp r6, r0 + bne use_pll2_pfd_200M + + ldr r6, [r2, #0x18] + bic r6, r6, #0x600000 + orr r6, r6, #0x200000 + str r6, [r2, #0x18] + ldr r6, =400000000 + b cont2 + +use_pll2_pfd_200M: + ldr r6, [r2, #0x18] + orr r6, r6, #0x600000 + str r6, [r2, #0x18] + ldr r6, =200000000 + +cont2: + ldr r4, [r2, #0x14] + bic r4, r4, #0x4000000 + str r4, [r2, #0x14] + +periph2_clk_switch6: + ldr r4, [r2, #0x48] + cmp r4, #0 + bne periph2_clk_switch6 + +change_divider_only: + /* + * Calculate the MMDC divider + * based on the requested freq. + */ + ldr r4, =0 +Loop2: + sub r6, r6, r0 + cmp r6, r0 + blt Div_Found + add r4, r4, #1 + bgt Loop2 + + /* Shift divider into correct offset. */ + lsl r4, r4, #3 +Div_Found: + /* Set the MMDC PODF. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, r4 + str r6, [r2, #0x14] + +mmdc_podf1: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf1 + + .endm + + .macro mmdc_clk_lower_100MHz + + /* + * Prior to reducing the DDR frequency (at 528/400 MHz), + * read the Measure unit count bits (MU_UNIT_DEL_NUM) + */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r4, =0x3FF + and r6, r6, r4 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* + * Bypass the automatic measure unit when below 100 MHz + * by setting the Measure unit bypass enable bit (MU_BYP_EN) + */ + ldr r6, [r8, r5] + orr r6, r6, #0x400 + str r6, [r8, r5] + /* + * Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r8, r5] + ldr r4, =0x3FF + bic r6, r6, r4 + orr r6, r6, r7 + str r6, [r8, r5] + + .endm + + .macro mmdc_clk_above_100MHz + + /* Make sure that the PHY measurement unit is NOT in bypass mode */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + bic r6, r6, #0x400 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure1: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1 + .endm + +/* + * mx6_lpddr2_freq_change + * + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + * r0 : DDR freq. + * r1: low_bus_freq_mode flag + */ + .align 3 +ENTRY(mx6_lpddr2_freq_change) +imx6_lpddr2_freq_change_start: + push {r4-r10} + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + +#ifdef CONFIG_CACHE_L2X0 + /* + * Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. + */ + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + + /* Wait for background operations to complete. */ +wait_for_l2_to_idle: + ldr r6, [r7, #0x730] + cmp r6, #0x0 + bne wait_for_l2_to_idle + + mov r6, #0x0 + str r6, [r7, #0x730] + + /* + * The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + ldr r3, [r7, #PL310_AUX_CTRL] + tst r3, #PL310_AUX_16WAY_BIT + mov r3, #PL310_8WAYS_MASK + orrne r3, #PL310_16WAYS_UPPERMASK + mov r6, #PL310_LOCKDOWN_NBREGS + add r5, r7, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r3, [r5], #PL310_LOCKDOWN_SZREG + str r3, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + + ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) + ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) + ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) + + /* Disable Automatic power savings. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x01 + str r6, [r8, #0x404] + + /* MMDC0_MDPDC disable power down timer */ + ldr r6, [r8, #0x4] + bic r6, r6, #0xff00 + str r6, [r8, #0x4] + + /* Delay for a while */ + ldr r10, =10 +delay1: + ldr r7, =0 +cont1: + ldr r6, [r8, r7] + add r7, r7, #4 + cmp r7, #16 + bne cont1 + sub r10, r10, #1 + cmp r10, #0 + bgt delay1 + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_set_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r8, #0x410] + orr r6, r6, #0x100 + str r6, [r8, #0x410] + + ldr r10, =100000000 + cmp r0, r10 + bgt set_ddr_mu_above_100 + mmdc_clk_lower_100MHz + +set_ddr_mu_above_100: + ldr r10, =24000000 + cmp r0, r10 + beq set_to_24MHz + + ddr_switch_400MHz + + ldr r10,=100000000 + cmp r0, r10 + blt done + mmdc_clk_above_100MHz + + b done + +set_to_24MHz: + mx6sl_switch_to_24MHz + +done: + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x01 + str r6, [r8, #0x404] + + ldr r10, =24000000 + cmp r0, r10 + beq skip_power_down + + /* Enable MMDC power down timer. */ + ldr r6, [r8, #0x4] + orr r6, r6, #0x5500 + str r6, [r8, #0x4] + +skip_power_down: + /* clear SBS - unblock DDR accesses */ + ldr r6, [r8, #0x410] + bic r6, r6, #0x100 + str r6, [r8, #0x410] + +#ifdef CONFIG_CACHE_L2X0 + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + ldr r3, [r7, #PL310_AUX_CTRL] + tst r3, #PL310_AUX_16WAY_BIT + mov r6, #PL310_LOCKDOWN_NBREGS + mov r3, #0x00 /* 8 ways mask */ + orrne r3, #0x0000 /* 16 ways mask */ + add r5, r7, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r3, [r5], #PL310_LOCKDOWN_SZREG + str r3, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + pop {r4-r10} + + /* Restore registers */ + mov pc, lr + + /* + * Add ltorg here to ensure that all + * literals are stored here and are + * within the text space. + */ + .ltorg +imx6_lpddr2_freq_change_end: diff --git a/arch/arm/mach-imx/lpddr2_freq_imx6q.S b/arch/arm/mach-imx/lpddr2_freq_imx6q.S new file mode 100644 index 000000000000..6c9aac07df16 --- /dev/null +++ b/arch/arm/mach-imx/lpddr2_freq_imx6q.S @@ -0,0 +1,765 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include <asm/smp_scu.h> +#include "hardware.h" + +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1c +#define CCM_CDHIPR 0x48 + +.globl mx6q_lpddr2_freq_change_start +.globl mx6q_lpddr2_freq_change_end + + .macro wait_for_ccm_handshake + /* wait for div update */ +1: + ldr r9, [r2, #CCM_CDHIPR] + cmp r9, #0 + bne 1b + + .endm + + .macro set_mmdc_misc_ralat_2_cycles + + /* Set MMDCx_MISC[RALAT] = 2 cycles */ + ldr r6, [r8, #0x18] + bic r6, r6, #(0x7 << 6) + orr r6, r6, #(0x2 << 6) + str r6, [r8, #0x18] + + /* Check if lpddr2 channel 1 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq 1f + + ldr r6, [r4, #0x18] + bic r6, r6, #(0x7 << 6) + orr r6, r6, #(0x2 << 6) + str r6, [r4, #0x18] +1: + .endm + + .macro switch_to_400MHz + /* set the MMDC_DIV=1, AXI_DIV=2, AHB_DIV=3 */ + ldr r9, [r2, #CCM_CBCDR] + ldr r6, =0x3f1f00 + bic r9, r9, r6 + orr r9, r9, #(0x9 << 8) + orr r9, r9, #(1 << 16) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* check periph_clk_sel */ + ldr r9, [r2, #CCM_CBCDR] + and r9, r9, #(1 << 25) + cmp r9, #(1 << 25) + bne skip_periph_clk_switch_400m + + /* now switch periph_clk back. */ + ldr r9, [r2, #CCM_CBCDR] + bic r9, r9, #(1 << 25) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + +skip_periph_clk_switch_400m: + + .endm + + .macro switch_to_100MHz + /* set the MMDC_DIV=4, AXI_DIV=8, AHB_DIV=8 */ + ldr r9, [r2, #CCM_CBCDR] + ldr r6, =0x3f1f00 + bic r9, r9, r6 + orr r9, r9, #(0x1F << 16) + orr r9, r9, #(0x1D << 8) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* check if periph_clk_sel is already set. */ + ldr r9, [r2, #CCM_CBCDR] + and r9, r9, #(1 << 25) + cmp r9, #(1 << 25) + bne skip_periph_clk_switch_100m + + /* now switch periph_clk back. */ + ldr r9, [r2, #CCM_CBCDR] + bic r9, r9, #(1 << 25) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + +skip_periph_clk_switch_100m: + + .endm + + .macro switch_to_24MHz + /* + * change the freq now try setting DDR to 24MHz. + * source it from the periph_clk2 ensure the + * periph_clk2 is sourced from 24MHz and the + * divider is 1. + */ + + ldr r9, [r2, #CCM_CBCMR] + bic r9, r9, #(0x3 << 12) + orr r9, r9, #(1 << 12) + str r9, [r2, #CCM_CBCMR] + + ldr r9, [r2, #CCM_CBCDR] + bic r9, r9, #(0x7 << 27) + str r9, [r2, #CCM_CBCDR] + + /* now switch periph_clk to 24MHz. */ + ldr r9, [r2, #CCM_CBCDR] + orr r9, r9, #(1 << 25) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* change all the dividers to 1. */ + ldr r9, [r2, #CCM_CBCDR] + ldr r6, =0x3f1f00 + bic r9, r9, r6 + orr r9, r9, #(1 << 8) + str r9, [r2, #CCM_CBCDR] + + /* Wait for the divider to change. */ + wait_for_ccm_handshake + + .endm + + .macro switch_to_24MHZ_from_pll2 + /* Change DDR freq settings from pll2_pfd2 (div 2) */ + + ldr r9, [r2, #CCM_CBCMR] + bic r9, r9, #(0x3 << 18) + orr r9, r9, #(0x3 << 18) + str r9, [r2, #CCM_CBCMR] + + ldr r9, [r2, #CCM_CBCDR] + bic r9, r9, #(1 << 25) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + ldr r9, [r2, #CCM_CBCDR] + ldr r6, =0x3f1f00 + bic r9, r9, r6 + orr r9, r9, #(1 << 8) + orr r9, r9, #(0x7 << 19) + str r9, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro set_timings_below_100MHz_operation + set_mmdc_misc_ralat_2_cycles + + /* Adjust LPDDR2 timings for 24Mhz operation */ + ldr r5, =0x03162073 + str r5, [r8, #0xC] /* MMDC0_MDCFG0 */ + ldr r7, =0x00020482 + str r7, [r8, #0x10] /* MMDC0_MDCFG1 */ + ldr r9, =0x00000049 + str r9, [r8, #0x14] /* MMDC0_MDCFG2 */ + ldr r10, =0x00020333 + str r10, [r8, #0x38] /* MMDC0_MDCFG3LP */ + + /* Check if lpddr2 channel 1 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_below_100Mhz_ch1_timings + + str r5, [r4, #0xC] /* MMDC1_MDCFG0 */ + str r7, [r4, #0x10] /* MMDC1_MDCFG1 */ + str r9, [r4, #0x14] /* MMDC1_MDCFG2 */ + str r10, [r4, #0x38] /* MMDC1_MDCFG3LP */ + +skip_below_100Mhz_ch1_timings: + + .endm + + .macro restore_mmdc_settings_info + /* restore timing from mmdc_settings_info */ + ldr r6, [r1, #0x0] + ldr r7, [r1, #0x4] +1: + ldr r9, [r7], #0x4 + ldr r10, [r7], #0x4 + str r10, [r8, r9] + subs r6, r6, #0x1 + bne 1b + + /* Check if lpddr2 channel 1 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq 3f + + ldr r6, [r1, #0x0] + ldr r7, [r1, #0x4] +2: + ldr r9, [r7], #0x4 + ldr r10, [r7], #0x4 + str r10, [r4, r9] + subs r6, r6, #0x1 + bne 2b +3: + + .endm + + .macro mmdc_clk_lower_equal_100MHz + + ldr r10, =100000000 + cmp r0, r10 + beq set_timmings_100MHz + set_timings_below_100MHz_operation + b common_to_lower_equal_100MHz + +set_timmings_100MHz: + restore_mmdc_settings_info + set_mmdc_misc_ralat_2_cycles + +common_to_lower_equal_100MHz: + + /* if MMDC is not in 400MHz mode, skip double mu count */ + ldr r5, [r1, #0x8] + ldr r6, =400000000 + cmp r5, r6 + bne skip_lower_force_measure_ch1 + + /* + * Prior to reducing the DDR frequency (at 528/400 MHz), + * read the Measure unit count bits (MU_UNIT_DEL_NUM) + */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r9, =0x3FF + and r6, r6, r9 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* + * Bypass the automatic measure unit when below 100 MHz + * by setting the Measure unit bypass enable bit (MU_BYP_EN) + */ + ldr r6, [r8, r5] + orr r6, r6, #0x400 + str r6, [r8, r5] + /* + * Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r8, r5] + ldr r9, =0x3FF + bic r6, r6, r9 + orr r6, r6, r7 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_lower_force_measure_ch1 + + ldr r5, =0x8B8 + ldr r6, [r4, r5] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r9, =0x3FF + and r6, r6, r9 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* + * Bypass the automatic measure unit when below 100 MHz + * by setting the Measure unit bypass enable bit (MU_BYP_EN) + */ + ldr r6, [r4, r5] + orr r6, r6, #0x400 + str r6, [r4, r5] + /* + * Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r4, r5] + ldr r9, =0x3FF + bic r6, r6, r9 + orr r6, r6, r7 + str r6, [r4, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r4, r5] + orr r6, r6, #0x800 + str r6, [r4, r5] + /* Wait for FRC_MSR to clear. */ +force_measure_ch1: + ldr r6, [r4, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure_ch1 + +skip_lower_force_measure_ch1: + + .endm + + .macro mmdc_clk_above_100MHz + + restore_mmdc_settings_info + + /* Make sure that the PHY measurement unit is NOT in bypass mode */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + bic r6, r6, #0x400 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure1: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1 + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_above_force_measure_ch1 + + ldr r5, =0x8B8 + ldr r6, [r4, r5] + bic r6, r6, #0x400 + str r6, [r4, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r4, r5] + orr r6, r6, #0x800 + str r6, [r4, r5] + /* Wait for FRC_MSR to clear. */ +force_measure1_ch1: + ldr r6, [r4, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1_ch1 + +skip_above_force_measure_ch1: + + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r11, lr} + + ldr r7, =v7_flush_kern_cache_all + mov lr, pc + mov pc, r7 + pop {r0 - r11, lr} + + /* disable d-cache */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + dsb + isb + + push {r0 - r11, lr} + + ldr r7, =v7_flush_kern_cache_all + mov lr, pc + mov pc, r7 + pop {r0 - r11, lr} + + .endm + +/* + * mx6_lpddr2_freq_change + * + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + * r0 : DDR freq. + * r1 : mmdc_settings_info + */ + .align 3 +ENTRY(mx6q_lpddr2_freq_change) +mx6q_lpddr2_freq_change_start: + push {r2-r10} + + /* + * Need to flush and disable L1 before + * disabling L2, we need data to + * coherent. Flushing L1 pushes + * everyhting to L2. We sync L2 later, but + * it can still have dirty lines. + * While exiting, we need to enable L2 first + * and then L1. + */ + disable_l1_dcache + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + +#ifdef CONFIG_CACHE_L2X0 + /* + * Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. + */ + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + + /* Wait for background operations to complete. */ +wait_for_l2_to_idle: + ldr r6, [r7, #0x730] + cmp r6, #0x0 + bne wait_for_l2_to_idle + + mov r6, #0x0 + str r6, [r7, #0x730] + + /* + * The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + /* Disable L2. */ + str r6, [r7, #0x100] +#endif + + ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) + ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) + ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) + ldr r4, =IMX_IO_P2V(MX6Q_MMDC_P1_BASE_ADDR) + + /* Disable Automatic power savings. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x01 + str r6, [r8, #0x404] + + /* MMDC0_MDPDC disable power down timer */ + ldr r6, [r8, #0x4] + bic r6, r6, #0xff00 + str r6, [r8, #0x4] + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_psd_ch1 + + ldr r6, [r4, #0x404] + orr r6, r6, #0x01 + str r6, [r4, #0x404] + + ldr r6, [r4, #0x4] + bic r6, r6, #0xff00 + str r6, [r4, #0x4] + +skip_psd_ch1: + /* Delay for a while */ + ldr r10, =10 +delay1: + ldr r7, =0 +cont1: + ldr r6, [r8, r7] + add r7, r7, #4 + cmp r7, #16 + bne cont1 + sub r10, r10, #1 + cmp r10, #0 + bgt delay1 + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_set_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r8, #0x410] + orr r6, r6, #0x100 + str r6, [r8, #0x410] + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_sbs_ch1 + + ldr r6, [r4, #0x404] + orr r6, r6, #0x200000 + str r6, [r4, #0x404] + +poll_dvfs_set_2: + ldr r6, [r4, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_2 + + ldr r6, [r4, #0x410] + orr r6, r6, #0x100 + str r6, [r4, #0x410] + +skip_sbs_ch1: + ldr r10, =100000000 + cmp r0, r10 + bgt set_ddr_mu_above_100 + mmdc_clk_lower_equal_100MHz + +set_ddr_mu_above_100: + ldr r10, =24000000 + cmp r0, r10 + beq set_to_24MHz + + ldr r10, =100000000 + cmp r0, r10 + beq set_to_100MHz + + ldr r10, =400000000 + cmp r0, r10 + switch_to_400MHz + b done + +set_to_24MHz: +/* + switch_to_24MHZ_from_pll2 +*/ + switch_to_24MHz + b done + +set_to_100MHz: + switch_to_100MHz + +done: + + ldr r10,=100000000 + cmp r0, r10 + ble skip_mmdc_clk_check + mmdc_clk_above_100MHz + +skip_mmdc_clk_check: + + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x01 + str r6, [r8, #0x404] + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_enable_psd_ch1 + + ldr r6, [r4, #0x404] + bic r6, r6, #0x200000 + str r6, [r4, #0x404] + +poll_dvfs_clear_2: + ldr r6, [r4, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_2 + + ldr r6, [r4, #0x404] + bic r6, r6, #0x01 + str r6, [r4, #0x404] + +skip_enable_psd_ch1: + ldr r10, =24000000 + cmp r0, r10 + beq skip_power_down + + /* Enable MMDC power down timer. */ + ldr r6, [r8, #0x4] + orr r6, r6, #0x5500 + str r6, [r8, #0x4] + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_power_down + + ldr r6, [r4, #0x4] + orr r6, r6, #0x5500 + str r6, [r4, #0x4] + +skip_power_down: + /* clear SBS - unblock DDR accesses */ + ldr r6, [r8, #0x410] + bic r6, r6, #0x100 + str r6, [r8, #0x410] + + /* Check if lpddr2 channel 2 is enabled */ + ldr r6, [r8, #0x18] + ands r6, r6, #(1 << 2) + beq skip_disable_sbs_ch1 + + ldr r6, [r4, #0x410] + bic r6, r6, #0x100 + str r6, [r4, #0x410] + +skip_disable_sbs_ch1: +#ifdef CONFIG_CACHE_L2X0 + /* Enable L2. */ + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + ldr r6, =0x1 + str r6, [r7, #0x100] +#endif + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + pop {r2-r10} + + /* Restore registers */ + mov pc, lr + + /* + * Add ltorg here to ensure that all + * literals are stored here and are + * within the text space. + */ + .ltorg +mx6q_lpddr2_freq_change_end: diff --git a/arch/arm/mach-imx/lpddr2_freq_imx6sll.S b/arch/arm/mach-imx/lpddr2_freq_imx6sll.S new file mode 100644 index 000000000000..c67d9e2b82ef --- /dev/null +++ b/arch/arm/mach-imx/lpddr2_freq_imx6sll.S @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include "hardware.h" + +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1c +#define CCM_CDHIPR 0x48 + +#define L2_CACHE_SYNC 0x730 +#define PL310_AUX_CTRL 0x104 +#define PL310_DCACHE_LOCKDOWN_BASE 0x900 +#define PL310_AUX_16WAY_BIT 0x10000 +#define PL310_LOCKDOWN_NBREGS 8 +#define PL310_LOCKDOWN_SZREG 4 +#define PL310_8WAYS_MASK 0x00FF +#define PL310_16WAYS_UPPERMASK 0xFF00 + +#define MMDC0_MDPDC 0x4 +#define MMDC0_MAPSR 0x404 +#define MMDC0_MADPCR0 0x410 + +#define HIGH_BUS_MODE 0x0 + + .macro wait_for_ccm_handshake + +1: + ldr r8, [r2, #CCM_CDHIPR] + cmp r8, #0 + bne 1b + + .endm + + .macro switch_to_24MHz + + /* periph2_clk2 sel to OSC_CLK */ + ldr r8, [r2, #CCM_CBCMR] + orr r8, r8, #(1 << 20) + str r8, [r2, #CCM_CBCMR] + + /* periph2_clk2_podf to 0 */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #0x7 + str r8, [r2, #CCM_CBCDR] + + /* periph2_clk sel to periph2_clk2 */ + ldr r8, [r2, #CCM_CBCDR] + orr r8, r8, #(0x1 << 26) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* fabric_mmdc_podf to 0 */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro switch_to_100MHz + + /* check whether periph2_clk is from top path */ + ldr r8, [r2, #CCM_CBCDR] + ands r8, #(1 << 26) + beq skip_periph2_clk2_switch_100m + + /* now switch periph2_clk back. */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(1 << 26) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* + * on i.MX6SLL, pre_periph2_clk will be always from + * pll2_pfd2, so no need to set pre_periph2_clk + * parent, just set the mmdc divider directly. + */ +skip_periph2_clk2_switch_100m: + + /* fabric_mmdc_podf to 3 so that mmdc is 400 / 4 = 100MHz */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + orr r8, r8, #(0x3 << 3) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro switch_to_400MHz + + /* check whether periph2_clk is from top path */ + ldr r8, [r2, #CCM_CBCDR] + ands r8, #(1 << 26) + beq skip_periph2_clk2_switch_400m + + /* now switch periph2_clk back. */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(1 << 26) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* + * on i.MX6SLL, pre_periph2_clk will be always from + * pll2_pfd2, so no need to set pre_periph2_clk + * parent, just set the mmdc divider directly. + */ +skip_periph2_clk2_switch_400m: + + /* fabric_mmdc_podf to 0 */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro mmdc_clk_lower_100MHz + /* if MMDC is not in 400MHz mode, skip double mu count */ + cmp r1, #HIGH_BUS_MODE + bne 1f + + /* + * Prior to reducing the DDR frequency (at 528/400 MHz), + * read the Measure unit count bits (MU_UNIT_DEL_NUM) + */ + ldr r8, =0x8B8 + ldr r6, [r5, r8] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r4, =0x3FF + and r6, r6, r4 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* + * Bypass the automatic measure unit when below 100 MHz + * by setting the Measure unit bypass enable bit (MU_BYP_EN) + */ + ldr r6, [r5, r8] + orr r6, r6, #0x400 + str r6, [r5, r8] + /* + * Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r5, r8] + ldr r4, =0x3FF + bic r6, r6, r4 + orr r6, r6, r7 + str r6, [r5, r8] + + /* For freq lower than 100MHz, need to set RALAT to 2 */ + ldr r6, [r5, #0x18] + bic r6, r6, #(0x7 << 6) + orr r6, r6, #(0x2 << 6) + str r6, [r5, #0x18] +1: + .endm + + .macro mmdc_clk_above_100MHz + + /* Make sure that the PHY measurement unit is NOT in bypass mode */ + ldr r8, =0x8B8 + ldr r6, [r5, r8] + bic r6, r6, #0x400 + str r6, [r5, r8] + /* Now perform a Force Measurement. */ + ldr r6, [r5, r8] + orr r6, r6, #0x800 + str r6, [r5, r8] + /* Wait for FRC_MSR to clear. */ +force_measure1: + ldr r6, [r5, r8] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1 + + /* For freq higher than 100MHz, need to set RALAT to 5 */ + ldr r6, [r5, #0x18] + bic r6, r6, #(0x7 << 6) + orr r6, r6, #(0x5 << 6) + str r6, [r5, #0x18] + + .endm + + .align 3 +/* + * Below code can be used by i.MX6SLL when changing the + * frequency of MMDC. the MMDC is the same on these two SOCs. + */ +ENTRY(imx6sll_lpddr2_freq_change) + push {r2 - r8} + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + +#ifdef CONFIG_CACHE_L2X0 + /* + * Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. + */ + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + mov r6, #0x0 + str r6, [r7, #L2_CACHE_SYNC] + + /* + * The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + ldr r3, [r7, #PL310_AUX_CTRL] + tst r3, #PL310_AUX_16WAY_BIT + mov r3, #PL310_8WAYS_MASK + orrne r3, #PL310_16WAYS_UPPERMASK + mov r6, #PL310_LOCKDOWN_NBREGS + add r5, r7, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r3, [r5], #PL310_LOCKDOWN_SZREG + str r3, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + + ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) + ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) + ldr r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) + + /* Disable Automatic power savings. */ + ldr r6, [r5, #MMDC0_MAPSR] + orr r6, r6, #0x1 + str r6, [r5, #MMDC0_MAPSR] + + /* Delay for a while */ + ldr r8, =10 +delay: + ldr r7, =0 +cont: + ldr r6, [r5, r7] + add r7, r7, #4 + cmp r7, #16 + bne cont + sub r8, r8, #1 + cmp r8, #0 + bgt delay + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r5, #MMDC0_MAPSR] + orr r6, r6, #0x200000 + str r6, [r5, #MMDC0_MAPSR] + +poll_dvfs_set_1: + ldr r6, [r5, #MMDC0_MAPSR] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r5, #MMDC0_MADPCR0] + orr r6, r6, #0x100 + str r6, [r5, #MMDC0_MADPCR0] + + ldr r6, =100000000 + cmp r0, r6 + bgt set_ddr_mu_above_100 + mmdc_clk_lower_100MHz + +set_ddr_mu_above_100: + ldr r6, =24000000 + cmp r0, r6 + beq set_to_24MHz + + ldr r6, =100000000 + cmp r0, r6 + beq set_to_100MHz + + switch_to_400MHz + + mmdc_clk_above_100MHz + + b done + +set_to_24MHz: + switch_to_24MHz + b done +set_to_100MHz: + switch_to_100MHz +done: + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r5, #MMDC0_MAPSR] + bic r6, r6, #0x200000 + str r6, [r5, #MMDC0_MAPSR] + +poll_dvfs_clear_1: + ldr r6, [r5, #MMDC0_MAPSR] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r5, #MMDC0_MAPSR] + bic r6, r6, #0x1 + str r6, [r5, #MMDC0_MAPSR] + + /* clear SBS - unblock DDR accesses */ + ldr r6, [r5, #MMDC0_MADPCR0] + bic r6, r6, #0x100 + str r6, [r5, #MMDC0_MADPCR0] + + ldr r6, =0xa0000000 + str r6, [r5, #0x83c] + + +#ifdef CONFIG_CACHE_L2X0 + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + ldr r3, [r7, #PL310_AUX_CTRL] + tst r3, #PL310_AUX_16WAY_BIT + mov r6, #PL310_LOCKDOWN_NBREGS + mov r3, #0x00 /* 8 ways mask */ + orrne r3, #0x0000 /* 16 ways mask */ + add r5, r7, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r3, [r5], #PL310_LOCKDOWN_SZREG + str r3, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + /* Restore registers */ + pop {r2 - r8} + mov pc, lr diff --git a/arch/arm/mach-imx/lpddr2_freq_imx6sx.S b/arch/arm/mach-imx/lpddr2_freq_imx6sx.S new file mode 100644 index 000000000000..ba3488cad9d4 --- /dev/null +++ b/arch/arm/mach-imx/lpddr2_freq_imx6sx.S @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include "hardware.h" + +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1c +#define CCM_CDHIPR 0x48 + +#define L2_CACHE_SYNC 0x730 +#define PL310_AUX_CTRL 0x104 +#define PL310_DCACHE_LOCKDOWN_BASE 0x900 +#define PL310_AUX_16WAY_BIT 0x10000 +#define PL310_LOCKDOWN_NBREGS 8 +#define PL310_LOCKDOWN_SZREG 4 +#define PL310_8WAYS_MASK 0x00FF +#define PL310_16WAYS_UPPERMASK 0xFF00 + +#define MMDC0_MDPDC 0x4 +#define MMDC0_MAPSR 0x404 +#define MMDC0_MADPCR0 0x410 + +#define HIGH_BUS_MODE 0x0 + + /* Check if the cpu is cortex-a7 */ + .macro is_ca7 + + /* Read the primary cpu number is MPIDR */ + mrc p15, 0, r6, c0, c0, 0 + ldr r7, =0xfff0 + and r6, r6, r7 + ldr r7, =0xc070 + cmp r6, r7 + + .endm + + .macro wait_for_ccm_handshake + +1: + ldr r8, [r2, #CCM_CDHIPR] + cmp r8, #0 + bne 1b + + .endm + + .macro switch_to_24MHz + + /* periph2_clk2 sel to OSC_CLK */ + ldr r8, [r2, #CCM_CBCMR] + orr r8, r8, #(1 << 20) + str r8, [r2, #CCM_CBCMR] + + /* periph2_clk2_podf to 0 */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #0x7 + str r8, [r2, #CCM_CBCDR] + + /* periph2_clk sel to periph2_clk2 */ + ldr r8, [r2, #CCM_CBCDR] + orr r8, r8, #(0x1 << 26) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* fabric_mmdc_podf to 0 */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro switch_to_100MHz + + /* check whether periph2_clk is from top path */ + ldr r8, [r2, #CCM_CBCDR] + ands r8, #(1 << 26) + beq skip_periph2_clk2_switch_100m + + /* now switch periph2_clk back. */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(1 << 26) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* + * on i.MX6SX, pre_periph2_clk will be always from + * pll2_pfd2, so no need to set pre_periph2_clk + * parent, just set the mmdc divider directly. + */ +skip_periph2_clk2_switch_100m: + + /* fabric_mmdc_podf to 3 so that mmdc is 400 / 4 = 100MHz */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + orr r8, r8, #(0x3 << 3) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro switch_to_400MHz + + /* check whether periph2_clk is from top path */ + ldr r8, [r2, #CCM_CBCDR] + ands r8, #(1 << 26) + beq skip_periph2_clk2_switch_400m + + /* now switch periph2_clk back. */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(1 << 26) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + /* + * on i.MX6SX, pre_periph2_clk will be always from + * pll2_pfd2, so no need to set pre_periph2_clk + * parent, just set the mmdc divider directly. + */ +skip_periph2_clk2_switch_400m: + + /* fabric_mmdc_podf to 0 */ + ldr r8, [r2, #CCM_CBCDR] + bic r8, r8, #(0x7 << 3) + str r8, [r2, #CCM_CBCDR] + + wait_for_ccm_handshake + + .endm + + .macro mmdc_clk_lower_100MHz + /* if MMDC is not in 400MHz mode, skip double mu count */ + cmp r1, #HIGH_BUS_MODE + bne 1f + + /* + * Prior to reducing the DDR frequency (at 528/400 MHz), + * read the Measure unit count bits (MU_UNIT_DEL_NUM) + */ + ldr r8, =0x8B8 + ldr r6, [r5, r8] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r4, =0x3FF + and r6, r6, r4 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* + * Bypass the automatic measure unit when below 100 MHz + * by setting the Measure unit bypass enable bit (MU_BYP_EN) + */ + ldr r6, [r5, r8] + orr r6, r6, #0x400 + str r6, [r5, r8] + /* + * Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r5, r8] + ldr r4, =0x3FF + bic r6, r6, r4 + orr r6, r6, r7 + str r6, [r5, r8] + + /* For freq lower than 100MHz, need to set RALAT to 2 */ + ldr r6, [r5, #0x18] + bic r6, r6, #(0x7 << 6) + orr r6, r6, #(0x2 << 6) + str r6, [r5, #0x18] +1: + .endm + + .macro mmdc_clk_above_100MHz + + /* Make sure that the PHY measurement unit is NOT in bypass mode */ + ldr r8, =0x8B8 + ldr r6, [r5, r8] + bic r6, r6, #0x400 + str r6, [r5, r8] + /* Now perform a Force Measurement. */ + ldr r6, [r5, r8] + orr r6, r6, #0x800 + str r6, [r5, r8] + /* Wait for FRC_MSR to clear. */ +force_measure1: + ldr r6, [r5, r8] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1 + + /* For freq higher than 100MHz, need to set RALAT to 5 */ + ldr r6, [r5, #0x18] + bic r6, r6, #(0x7 << 6) + orr r6, r6, #(0x5 << 6) + str r6, [r5, #0x18] + + .endm + + .align 3 +/* + * Below code can be used by i.MX6SX and i.MX6UL when changing the + * frequency of MMDC. the MMDC is the same on these two SOCs. + */ +ENTRY(imx6_up_lpddr2_freq_change) + + push {r2 - r8} + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + is_ca7 + beq skip_disable_l2 + +#ifdef CONFIG_CACHE_L2X0 + /* + * Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. + */ + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + mov r6, #0x0 + str r6, [r7, #L2_CACHE_SYNC] + + /* + * The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + ldr r3, [r7, #PL310_AUX_CTRL] + tst r3, #PL310_AUX_16WAY_BIT + mov r3, #PL310_8WAYS_MASK + orrne r3, #PL310_16WAYS_UPPERMASK + mov r6, #PL310_LOCKDOWN_NBREGS + add r5, r7, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r3, [r5], #PL310_LOCKDOWN_SZREG + str r3, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + +skip_disable_l2: + ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) + ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) + ldr r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) + + /* Disable Automatic power savings. */ + ldr r6, [r5, #MMDC0_MAPSR] + orr r6, r6, #0x1 + str r6, [r5, #MMDC0_MAPSR] + + /* MMDC0_MDPDC disable power down timer */ + ldr r6, [r5, #MMDC0_MDPDC] + bic r6, r6, #0xff00 + str r6, [r5, #MMDC0_MDPDC] + + /* Delay for a while */ + ldr r8, =10 +delay: + ldr r7, =0 +cont: + ldr r6, [r5, r7] + add r7, r7, #4 + cmp r7, #16 + bne cont + sub r8, r8, #1 + cmp r8, #0 + bgt delay + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r5, #MMDC0_MAPSR] + orr r6, r6, #0x200000 + str r6, [r5, #MMDC0_MAPSR] + +poll_dvfs_set_1: + ldr r6, [r5, #MMDC0_MAPSR] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r5, #MMDC0_MADPCR0] + orr r6, r6, #0x100 + str r6, [r5, #MMDC0_MADPCR0] + + ldr r6, =100000000 + cmp r0, r6 + bgt set_ddr_mu_above_100 + mmdc_clk_lower_100MHz + +set_ddr_mu_above_100: + ldr r6, =24000000 + cmp r0, r6 + beq set_to_24MHz + + ldr r6, =100000000 + cmp r0, r6 + beq set_to_100MHz + + switch_to_400MHz + + mmdc_clk_above_100MHz + + b done + +set_to_24MHz: + switch_to_24MHz + b done +set_to_100MHz: + switch_to_100MHz +done: + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r5, #MMDC0_MAPSR] + bic r6, r6, #0x200000 + str r6, [r5, #MMDC0_MAPSR] + +poll_dvfs_clear_1: + ldr r6, [r5, #MMDC0_MAPSR] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r5, #MMDC0_MAPSR] + bic r6, r6, #0x1 + str r6, [r5, #MMDC0_MAPSR] + + ldr r6, =24000000 + cmp r0, r6 + beq skip_power_down + + /* Enable MMDC power down timer. */ + ldr r6, [r5, #MMDC0_MDPDC] + orr r6, r6, #0x5500 + str r6, [r5, #MMDC0_MDPDC] + +skip_power_down: + /* clear SBS - unblock DDR accesses */ + ldr r6, [r5, #MMDC0_MADPCR0] + bic r6, r6, #0x100 + str r6, [r5, #MMDC0_MADPCR0] + + is_ca7 + beq skip_enable_l2 + +#ifdef CONFIG_CACHE_L2X0 + ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) + ldr r3, [r7, #PL310_AUX_CTRL] + tst r3, #PL310_AUX_16WAY_BIT + mov r6, #PL310_LOCKDOWN_NBREGS + mov r3, #0x00 /* 8 ways mask */ + orrne r3, #0x0000 /* 16 ways mask */ + add r5, r7, #PL310_DCACHE_LOCKDOWN_BASE +1: /* lock Dcache and Icache */ + str r3, [r5], #PL310_LOCKDOWN_SZREG + str r3, [r5], #PL310_LOCKDOWN_SZREG + subs r6, r6, #1 + bne 1b +#endif + +skip_enable_l2: + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + /* Restore registers */ + pop {r2 - r8} + mov pc, lr diff --git a/arch/arm/mach-imx/lpddr3_freq_imx.S b/arch/arm/mach-imx/lpddr3_freq_imx.S new file mode 100644 index 000000000000..80fb1184fa54 --- /dev/null +++ b/arch/arm/mach-imx/lpddr3_freq_imx.S @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include "hardware.h" + +#define DDRC_MSTR 0x0 +#define DDRC_STAT 0x4 +#define DDRC_PWRCTL 0x30 +#define DDRC_RFSHTMG 0x64 +#define DDRC_DBG1 0x304 +#define DDRC_PSTAT 0x3fc +#define DDRC_PCTRL_0 0x490 +#define DDRC_DFIMISC 0x1b0 +#define DDRC_DBGCAM 0x308 +#define DDRC_SWCTL 0x320 +#define DDRC_SWSTAT 0x324 +#define DDRPHY_LP_CON0 0x18 +#define IOMUXC_GPR8 0x20 +#define DDRPHY_PHY_CON1 0x4 +#define DDRPHY_MDLL_CON0 0xb0 +#define DDRPHY_MDLL_CON1 0xb4 +#define DDRPHY_OFFSETD_CON0 0x50 +#define DDRPHY_OFFSETR_CON0 0x20 +#define DDRPHY_OFFSETR_CON1 0x24 +#define DDRPHY_OFFSETR_CON2 0x28 +#define DDRPHY_OFFSETW_CON0 0x30 +#define DDRPHY_OFFSETW_CON1 0x34 +#define DDRPHY_OFFSETW_CON2 0x38 +#define DDRPHY_RFSHTMG 0x64 +#define DDRPHY_CA_WLDSKEW_CON0 0x6c +#define DDRPHY_CA_DSKEW_CON0 0x7c +#define DDRPHY_CA_DSKEW_CON1 0x80 +#define DDRPHY_CA_DSKEW_CON2 0x84 + +#define ANADIG_DIGPROG 0x800 + + .align 3 + + .macro ddrc_prepare + + /* disable port */ + ldr r7, =0x0 + str r7, [r4, #DDRC_PCTRL_0] + + /* wait port busy done */ + ldr r6, =0x10001 +1: + ldr r7, [r4, #DDRC_PSTAT] + and r7, r7, r6 + cmp r7, #0 + bne 1b + + ldr r7, =0x20 + str r7, [r4, #DDRC_PWRCTL] + + ldr r6, =0x23 +2: + ldr r7, [r4, #DDRC_STAT] + and r7, r7, r6 + cmp r7, r6 + bne 2b + + ldr r7, =0x1 + str r7, [r4, #DDRC_DBG1] + + ldr r6, =0x30000000 +3: + ldr r7, [r4, #DDRC_DBGCAM] + and r7, r7, r6 + cmp r7, r6 + bne 3b + + ldr r7, =0x0 + str r7, [r4, #DDRC_SWCTL] + + ldr r7, =0x0 + str r7, [r4, #DDRC_DFIMISC] + + ldr r7, =0x1 + str r7, [r4, #DDRC_SWCTL] + + ldr r6, =0x1 +4: + ldr r7, [r4, #DDRC_SWSTAT] + and r7, r7, r6 + cmp r7, r6 + bne 4b + + .endm + + .macro ddrc_done + + ldr r7, =0x0 + str r7, [r4, #DDRC_PWRCTL] + + ldr r6, =0x3 +5: + ldr r7, [r4, #DDRC_STAT] + and r7, r7, r6 + cmp r7, r6 + beq 5b + + ldr r7, =0x0 + str r7, [r4, #DDRC_DBG1] + + ldr r7, =0x1 + str r7, [r4, #DDRC_PCTRL_0] + + /* enable auto self-refresh */ + ldr r7, [r4, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r4, #DDRC_PWRCTL] + + .endm + + .macro switch_to_below_100m + + /* LPDDR2 and LPDDR3 has different setting */ + ldr r8, [r4, #DDRC_MSTR] + ands r8, r8, #0x4 + bne 9f + + /* LPDDR3 */ + ldr r7, =0x00000100 + str r7, [r5, #DDRPHY_PHY_CON1] + b 10f +9: + /* LPDDR2 */ + ldr r7, =0x10010100 + str r7, [r5, #DDRPHY_PHY_CON1] +10: + ldr r6, =24000000 + cmp r0, r6 + beq 16f + + ldr r7, =0x0005000B + str r7, [r4, #DDRC_RFSHTMG] + b 6f +16: + ldr r7, =0x00010003 + str r7, [r4, #DDRC_RFSHTMG] + + /* dram alt sel set to OSC */ + ldr r7, =0x10000000 + ldr r8, =0xa080 + str r7, [r2, r8] + /* dram root set to from dram alt, div by 1 */ + ldr r7, =0x11000000 + ldr r8, =0x9880 + str r7, [r2, r8] + b 7f + +6: + /* dram alt sel set to pfd0_392m */ + ldr r7, =0x15000000 + ldr r8, =0xa080 + str r7, [r2, r8] + /* dram root set to from dram alt, div by 4 */ + ldr r7, =0x11000003 + ldr r8, =0x9880 + str r7, [r2, r8] +7: + ldr r7, =0x202ffd0 + str r7, [r5, #DDRPHY_MDLL_CON0] + + ldr r7, =0x7f + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r7, =0x7f7f7f7f + str r7, [r5, #DDRPHY_OFFSETR_CON0] + str r7, [r5, #DDRPHY_OFFSETR_CON1] + ldr r7, =0x7f + str r7, [r5, #DDRPHY_OFFSETR_CON2] + + ldr r7, =0x7f7f7f7f + str r7, [r5, #DDRPHY_OFFSETW_CON0] + str r7, [r5, #DDRPHY_OFFSETW_CON1] + ldr r7, =0x7f + str r7, [r5, #DDRPHY_OFFSETW_CON2] + + ldr r7, [r9, #ANADIG_DIGPROG] + and r7, r7, #0x11 + cmp r7, #0x11 + bne 11f + + ldr r7, =0x0 + str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0] + ldr r7, =0x60606060 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + ldr r7, =0x00006060 + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] + b 12f +11: + ldr r7, =0x0 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] +12: + ldr r7, =0x100007f + str r7, [r5, #DDRPHY_OFFSETD_CON0] + ldr r7, =0x7f + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + .endm + + .macro switch_to_533m + + ldr r7, =0x10210100 + str r7, [r5, #DDRPHY_PHY_CON1] + + ldr r7, =0x00200038 + str r7, [r4, #DDRC_RFSHTMG] + + /* dram root set to from dram main, div by 2 */ + ldr r7, =0x10000001 + ldr r8, =0x9880 + str r7, [r2, r8] + + ldr r7, =0x1010007e + str r7, [r5, #DDRPHY_MDLL_CON0] + + ldr r7, =0x10000008 + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r7, =0x08080808 + str r7, [r5, #DDRPHY_OFFSETR_CON0] + str r7, [r5, #DDRPHY_OFFSETR_CON1] + ldr r7, =0x8 + str r7, [r5, #DDRPHY_OFFSETR_CON2] + + ldr r7, =0x08080808 + str r7, [r5, #DDRPHY_OFFSETW_CON0] + str r7, [r5, #DDRPHY_OFFSETW_CON1] + ldr r7, =0x8 + str r7, [r5, #DDRPHY_OFFSETW_CON2] + + /* LPDDR2 and LPDDR3 has different setting */ + ldr r8, [r4, #DDRC_MSTR] + ands r8, r8, #0x4 + beq 15f + + ldr r7, [r9, #ANADIG_DIGPROG] + and r7, r7, #0x11 + cmp r7, #0x11 + bne 14f + + ldr r7, =0x08080808 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + ldr r7, =0x0a0a0808 + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] + ldr r7, =0x0a0a0a0a + str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0] + b 14f +15: + ldr r7, [r9, #ANADIG_DIGPROG] + and r7, r7, #0x11 + cmp r7, #0x11 + bne 13f + + ldr r7, =0x1c1c1c1c + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + ldr r7, =0x30301c1c + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] + ldr r7, =0x30303030 + str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0] + b 14f +13: + ldr r7, =0x08080808 + str r7, [r5, #DDRPHY_CA_DSKEW_CON0] + str r7, [r5, #DDRPHY_CA_DSKEW_CON1] + ldr r7, =0x0808 + str r7, [r5, #DDRPHY_CA_DSKEW_CON2] +14: + ldr r7, =0x11000008 + str r7, [r5, #DDRPHY_OFFSETD_CON0] + ldr r7, =0x10000008 + str r7, [r5, #DDRPHY_OFFSETD_CON0] + + ldr r6, =0x4 +8: + ldr r7, [r5, #DDRPHY_MDLL_CON1] + and r7, r7, r6 + cmp r7, r6 + bne 8b + + .endm + +ENTRY(imx_lpddr3_freq_change) + push {r2 - r9} + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + ldr r2, =IMX_IO_P2V(MX7D_CCM_BASE_ADDR) + ldr r3, =IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR) + ldr r4, =IMX_IO_P2V(MX7D_DDRC_BASE_ADDR) + ldr r5, =IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR) + ldr r9, =IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR) + + ddrc_prepare + + ldr r6, =100000000 + cmp r0, r6 + bgt set_to_533m + +set_to_below_100m: + switch_to_below_100m + b done + +set_to_533m: + switch_to_533m + b done + +done: + ddrc_done + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + /* Restore registers */ + pop {r2 - r9} + mov pc, lr +ENDPROC(imx_lpddr3_freq_change) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index edd26e0ffeec..730ce83eee0e 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -106,6 +106,18 @@ static int ar8031_phy_fixup(struct phy_device *dev) { u16 val; + /* Set RGMII IO voltage to 1.8V */ + phy_write(dev, 0x1d, 0x1f); + phy_write(dev, 0x1e, 0x8); + + /* disable phy AR8031 SmartEEE function. */ + phy_write(dev, 0xd, 0x3); + phy_write(dev, 0xe, 0x805d); + phy_write(dev, 0xd, 0x4003); + val = phy_read(dev, 0xe); + val &= ~(0x1 << 8); + phy_write(dev, 0xe, val); + /* To enable AR8031 output a 125MHz clk from CLK_25M */ phy_write(dev, 0xd, 0x7); phy_write(dev, 0xe, 0x8016); @@ -223,6 +235,58 @@ put_node: of_node_put(np); } +static void __init imx6q_csi_mux_init(void) +{ + /* + * MX6Q SabreSD board: + * IPU1 CSI0 connects to parallel interface. + * Set GPR1 bit 19 to 0x1. + * + * MX6DL SabreSD board: + * IPU1 CSI0 connects to parallel interface. + * Set GPR13 bit 0-2 to 0x4. + * IPU1 CSI1 connects to MIPI CSI2 virtual channel 1. + * Set GPR13 bit 3-5 to 0x1. + */ + struct regmap *gpr; + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) { + if (of_machine_is_compatible("fsl,imx6q-sabresd") || + of_machine_is_compatible("fsl,imx6q-sabreauto") || + of_machine_is_compatible("fsl,imx6qp-sabresd") || + of_machine_is_compatible("fsl,imx6qp-sabreauto")) + regmap_update_bits(gpr, IOMUXC_GPR1, 1 << 19, 1 << 19); + else if (of_machine_is_compatible("fsl,imx6dl-sabresd") || + of_machine_is_compatible("fsl,imx6dl-sabreauto")) + regmap_update_bits(gpr, IOMUXC_GPR13, 0x3F, 0x0C); + } else { + pr_err("%s(): failed to find fsl,imx6q-iomux-gpr regmap\n", + __func__); + } +} + +static void __init imx6q_enet_clk_sel(void) +{ + struct regmap *gpr; + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR5, + IMX6Q_GPR5_ENET_TX_CLK_SEL, IMX6Q_GPR5_ENET_TX_CLK_SEL); + else + pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); +} + +static inline void imx6q_enet_init(void) +{ + imx6_enet_mac_init("fsl,imx6q-fec", "fsl,imx6q-ocotp"); + imx6q_enet_phy_init(); + imx6q_1588_init(); + if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) + imx6q_enet_clk_sel(); +} + static void __init imx6q_axi_init(void) { struct regmap *gpr; @@ -260,7 +324,7 @@ static void __init imx6q_init_machine(void) { struct device *parent; - if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0) + if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) imx_print_silicon_rev("i.MX6QP", IMX_CHIP_REVISION_1_0); else imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", @@ -270,13 +334,12 @@ static void __init imx6q_init_machine(void) if (parent == NULL) pr_warn("failed to initialize soc device\n"); - imx6q_enet_phy_init(); - of_platform_default_populate(NULL, NULL, parent); imx_anatop_init(); + imx6q_enet_init(); + imx6q_csi_mux_init(); cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); - imx6q_1588_init(); imx6q_axi_init(); } @@ -300,6 +363,8 @@ static void __init imx6q_map_io(void) { debug_ll_io_init(); imx_scu_map_io(); + imx6_pm_map_io(); + imx_busfreq_map_io(); } static void __init imx6q_init_irq(void) diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index e00818abe54d..d1c6a9fa826a 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -16,7 +16,7 @@ #include "cpuidle.h" #include "hardware.h" -static void __init imx6sl_fec_init(void) +static void __init imx6sl_fec_clk_init(void) { struct regmap *gpr; @@ -32,6 +32,12 @@ static void __init imx6sl_fec_init(void) } } +static inline void imx6sl_fec_init(void) +{ + imx6sl_fec_clk_init(); + imx6_enet_mac_init("fsl,imx6sl-fec", "fsl,imx6sl-ocotp"); +} + static void __init imx6sl_init_late(void) { /* imx6sl reuses imx6q cpufreq driver */ @@ -41,7 +47,7 @@ static void __init imx6sl_init_late(void) if (IS_ENABLED(CONFIG_SOC_IMX6SL) && cpu_is_imx6sl()) imx6sl_cpuidle_init(); else if (IS_ENABLED(CONFIG_SOC_IMX6SLL)) - imx6sx_cpuidle_init(); + imx6sll_cpuidle_init(); } static void __init imx6sl_init_machine(void) @@ -54,6 +60,7 @@ static void __init imx6sl_init_machine(void) of_platform_default_populate(NULL, NULL, parent); + imx_anatop_init(); if (cpu_is_imx6sl()) imx6sl_fec_init(); imx_anatop_init(); @@ -73,6 +80,14 @@ static void __init imx6sl_init_irq(void) imx6_pm_ccm_init("fsl,imx6sll-ccm"); } +static void __init imx6sl_map_io(void) +{ + imx6_pm_map_io(); +#ifdef CONFIG_CPU_FREQ + imx_busfreq_map_io(); +#endif +} + static const char * const imx6sl_dt_compat[] __initconst = { "fsl,imx6sl", "fsl,imx6sll", @@ -82,6 +97,7 @@ static const char * const imx6sl_dt_compat[] __initconst = { DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, + .map_io = imx6sl_map_io, .init_irq = imx6sl_init_irq, .init_machine = imx6sl_init_machine, .init_late = imx6sl_init_late, diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index d5310bf307ff..118e9c9bb5a9 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -23,6 +23,14 @@ static int ar8031_phy_fixup(struct phy_device *dev) phy_write(dev, 0x1d, 0x1f); phy_write(dev, 0x1e, 0x8); + /* disable phy AR8031 SmartEEE function. */ + phy_write(dev, 0xd, 0x3); + phy_write(dev, 0xe, 0x805d); + phy_write(dev, 0xd, 0x4003); + val = phy_read(dev, 0xe); + val &= ~(0x1 << 8); + phy_write(dev, 0xe, val); + /* introduce tx clock delay */ phy_write(dev, 0x1d, 0x5); val = phy_read(dev, 0x1e); @@ -57,6 +65,7 @@ static void __init imx6sx_enet_clk_sel(void) static inline void imx6sx_enet_init(void) { + imx6_enet_mac_init("fsl,imx6sx-fec", "fsl,imx6sx-ocotp"); imx6sx_enet_phy_init(); imx6sx_enet_clk_sel(); } @@ -71,6 +80,7 @@ static void __init imx6sx_init_machine(void) of_platform_default_populate(NULL, NULL, parent); + imx_anatop_init(); imx6sx_enet_init(); imx_anatop_init(); imx6sx_pm_init(); @@ -86,6 +96,13 @@ static void __init imx6sx_init_irq(void) imx6_pm_ccm_init("fsl,imx6sx-ccm"); } +static void __init imx6sx_map_io(void) +{ + debug_ll_io_init(); + imx6_pm_map_io(); + imx_busfreq_map_io(); +} + static void __init imx6sx_init_late(void) { imx6sx_cpuidle_init(); @@ -102,6 +119,7 @@ static const char * const imx6sx_dt_compat[] __initconst = { DT_MACHINE_START(IMX6SX, "Freescale i.MX6 SoloX (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, + .map_io = imx6sx_map_io, .init_irq = imx6sx_init_irq, .init_machine = imx6sx_init_machine, .dt_compat = imx6sx_dt_compat, diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c index 311f5e4ff723..732f9419acd0 100644 --- a/arch/arm/mach-imx/mach-imx6ul.c +++ b/arch/arm/mach-imx/mach-imx6ul.c @@ -52,6 +52,7 @@ static inline void imx6ul_enet_init(void) { imx6ul_enet_clk_init(); imx6ul_enet_phy_init(); + imx6_enet_mac_init("fsl,imx6ul-fec", "fsl,imx6ul-ocotp"); } static void __init imx6ul_init_machine(void) @@ -63,6 +64,7 @@ static void __init imx6ul_init_machine(void) pr_warn("failed to initialize soc device\n"); of_platform_default_populate(NULL, NULL, parent); + imx_anatop_init(); imx6ul_enet_init(); imx_anatop_init(); imx6ul_pm_init(); @@ -78,12 +80,18 @@ static void __init imx6ul_init_irq(void) static void __init imx6ul_init_late(void) { - imx6sx_cpuidle_init(); + imx6ul_cpuidle_init(); if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); } +static void __init imx6ul_map_io(void) +{ + imx6_pm_map_io(); + imx_busfreq_map_io(); +} + static const char * const imx6ul_dt_compat[] __initconst = { "fsl,imx6ul", "fsl,imx6ull", @@ -91,6 +99,7 @@ static const char * const imx6ul_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)") + .map_io = imx6ul_map_io, .init_irq = imx6ul_init_irq, .init_machine = imx6ul_init_machine, .init_late = imx6ul_init_late, diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index ebb27592a9f7..7ad5e6f240dd 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -13,6 +13,13 @@ #include <asm/mach/map.h> #include "common.h" +#include "cpuidle.h" + +static struct property device_disabled = { + .name = "status", + .length = sizeof("disabled"), + .value = "disabled", +}; static int ar8031_phy_fixup(struct phy_device *dev) { @@ -57,6 +64,23 @@ static void __init imx7d_enet_phy_init(void) } } +static void __init imx7d_enet_mdio_fixup(void) +{ + struct regmap *gpr; + + /* The management data input/output (MDIO) bus where often high-speed, + * open-drain operation is required. i.MX7D TO1.0 ENET MDIO pin has no + * open drain as IC ticket number: TKT252980, i.MX7D TO1.1 fix the issue. + * GPR1[8:7] are reserved bits at TO1.0, there no need to add version check. + */ + gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR0, IMX7D_GPR0_ENET_MDIO_OPEN_DRAIN_MASK, + IMX7D_GPR0_ENET_MDIO_OPEN_DRAIN_MASK); + else + pr_err("failed to find fsl,imx7d-iomux-gpr regmap\n"); +} + static void __init imx7d_enet_clk_sel(void) { struct regmap *gpr; @@ -72,10 +96,23 @@ static void __init imx7d_enet_clk_sel(void) static inline void imx7d_enet_init(void) { + imx6_enet_mac_init("fsl,imx7d-fec", "fsl,imx7d-ocotp"); + imx7d_enet_mdio_fixup(); imx7d_enet_phy_init(); imx7d_enet_clk_sel(); } +static inline void imx7d_disable_arm_arch_timer(void) +{ + struct device_node *node; + + node = of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); + if (node) { + pr_info("disable arm arch timer for nosmp!\n"); + of_add_property(node, &device_disabled); + } +} + static void __init imx7d_init_machine(void) { struct device *parent; @@ -85,20 +122,35 @@ static void __init imx7d_init_machine(void) pr_warn("failed to initialize soc device\n"); imx_anatop_init(); + of_platform_default_populate(NULL, NULL, parent); + imx7d_pm_init(); + imx_anatop_init(); imx7d_enet_init(); } static void __init imx7d_init_late(void) { + imx7d_cpuidle_init(); if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); } static void __init imx7d_init_irq(void) { + imx_gpcv2_check_dt(); imx_init_revision_from_anatop(); imx_src_init(); irqchip_init(); +#ifndef CONFIG_SMP + imx7d_disable_arm_arch_timer(); +#endif +} + +static void __init imx7d_map_io(void) +{ + debug_ll_io_init(); + imx7_pm_map_io(); + imx_busfreq_map_io(); } static const char *const imx7d_dt_compat[] __initconst = { @@ -108,6 +160,8 @@ static const char *const imx7d_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") + .map_io = imx7d_map_io, + .smp = smp_ops(imx_smp_ops), .init_irq = imx7d_init_irq, .init_machine = imx7d_init_machine, .init_late = imx7d_init_late, diff --git a/arch/arm/mach-imx/mach-imx7ulp.c b/arch/arm/mach-imx/mach-imx7ulp.c index 11ac71aaf965..410f0d745c9d 100644 --- a/arch/arm/mach-imx/mach-imx7ulp.c +++ b/arch/arm/mach-imx/mach-imx7ulp.c @@ -10,6 +10,7 @@ #include <linux/of_platform.h> #include <linux/regmap.h> #include <asm/mach/arch.h> +#include <asm/mach/map.h> #include "common.h" #include "cpuidle.h" @@ -17,6 +18,15 @@ #define SIM_JTAG_ID_REG 0x8c +/* static IO mapping, and ioremap() could always share the same mapping. */ +static struct map_desc mx7ulp_io_desc[] __initdata = { + mx7ulp_aips_map_entry(1, MT_DEVICE), + mx7ulp_aips_map_entry(2, MT_DEVICE), + mx7ulp_aips_map_entry(3, MT_DEVICE), + mx7ulp_aips_map_entry(4, MT_DEVICE), + mx7ulp_aips_map_entry(5, MT_DEVICE), +}; + static void __init imx7ulp_set_revision(void) { struct regmap *sim; @@ -45,6 +55,9 @@ static void __init imx7ulp_set_revision(void) case 2: imx_set_soc_revision(IMX_CHIP_REVISION_2_1); break; + case 3: + imx_set_soc_revision(IMX_CHIP_REVISION_2_2); + break; default: imx_set_soc_revision(IMX_CHIP_REVISION_1_0); break; @@ -65,12 +78,23 @@ static const char *const imx7ulp_dt_compat[] __initconst = { NULL, }; +static void __init imx7ulp_map_io(void) +{ + iotable_init(mx7ulp_io_desc, ARRAY_SIZE(mx7ulp_io_desc)); + imx7ulp_pm_map_io(); +} + static void __init imx7ulp_init_late(void) { + if (IS_ENABLED(CONFIG_ARM_IMX7ULP_CPUFREQ)) + platform_device_register_simple("imx7ulp-cpufreq", -1, NULL, 0); + imx7ulp_cpuidle_init(); + imx7ulp_enable_nmi(); } DT_MACHINE_START(IMX7ulp, "Freescale i.MX7ULP (Device Tree)") + .map_io = imx7ulp_map_io, .init_machine = imx7ulp_init_machine, .dt_compat = imx7ulp_dt_compat, .init_late = imx7ulp_init_late, diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index 0dfd0ae7a63d..8599936fc001 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -59,6 +59,7 @@ #define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu) static int ddr_type; +static int lpddr2_2ch_mode; struct fsl_mmdc_devtype_data { unsigned int flags; @@ -575,6 +576,11 @@ int imx_mmdc_get_ddr_type(void) return ddr_type; } +int imx_mmdc_get_lpddr2_2ch_mode(void) +{ + return lpddr2_2ch_mode; +} + static struct platform_driver imx_mmdc_driver = { .driver = { .name = "imx-mmdc", diff --git a/arch/arm/mach-imx/mu.c b/arch/arm/mach-imx/mu.c new file mode 100644 index 000000000000..1a250b07b256 --- /dev/null +++ b/arch/arm/mach-imx/mu.c @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. + * + * 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/busfreq-imx.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> +#include "common.h" +#include "hardware.h" + +#define MU_ATR0_OFFSET 0x0 +#define MU_ARR0_OFFSET 0x10 +#define MU_ARR1_OFFSET 0x14 +#define MU_ASR 0x20 +#define MU_ACR 0x24 +#define MX7ULP_MU_TR0 0x20 +#define MX7ULP_MU_RR0 0x40 +#define MX7ULP_MU_RR1 0x44 +#define MX7ULP_MU_SR 0x60 +#define MX7ULP_MU_CR 0x64 + +#define MU_LPM_HANDSHAKE_INDEX 0 +#define MU_RPMSG_HANDSHAKE_INDEX 1 +#define MU_LPM_BUS_HIGH_READY_FOR_M4 0xFFFF6666 +#define MU_LPM_M4_FREQ_CHANGE_READY 0xFFFF7777 +#define MU_LPM_M4_REQUEST_HIGH_BUS 0x2222CCCC +#define MU_LPM_M4_RELEASE_HIGH_BUS 0x2222BBBB +#define MU_LPM_M4_WAKEUP_SRC_VAL 0x55555000 +#define MU_LPM_M4_WAKEUP_SRC_MASK 0xFFFFF000 +#define MU_LPM_M4_WAKEUP_IRQ_MASK 0xFF0 +#define MU_LPM_M4_WAKEUP_IRQ_SHIFT 0x4 +#define MU_LPM_M4_WAKEUP_ENABLE_MASK 0xF +#define MU_LPM_M4_WAKEUP_ENABLE_SHIFT 0x0 + +#define MU_LPM_M4_RUN_MODE 0x5A5A0001 +#define MU_LPM_M4_WAIT_MODE 0x5A5A0002 +#define MU_LPM_M4_STOP_MODE 0x5A5A0003 + +#define MAX_NUM 10 /* enlarge it if overflow happen */ + +static void __iomem *mu_base; +static u32 m4_message[MAX_NUM]; +static u32 in_idx, out_idx; +static struct delayed_work mu_work; +static u32 m4_wake_irqs[4]; +static bool m4_freq_low; +struct irq_domain *domain; +static bool m4_in_stop; +static struct clk *clk; +static DEFINE_SPINLOCK(mu_lock); + +void imx_mu_set_m4_run_mode(void) +{ + m4_in_stop = false; +} + +bool imx_mu_is_m4_in_stop(void) +{ + return m4_in_stop; +} + +bool imx_mu_is_m4_in_low_freq(void) +{ + return m4_freq_low; +} + +void imx_mu_enable_m4_irqs_in_gic(bool enable) +{ + int i, j; + + for (i = 0; i < 4; i++) { + if (m4_wake_irqs[i] == 0) + continue; + for (j = 0; j < 32; j++) { + if (m4_wake_irqs[i] & (1 << j)) { + if (enable) + enable_irq(irq_find_mapping( + domain, i * 32 + j)); + else + disable_irq(irq_find_mapping( + domain, i * 32 + j)); + } + } + } +} + +static irqreturn_t mcc_m4_dummy_isr(int irq, void *param) +{ + return IRQ_HANDLED; +} + +static int imx_mu_send_message(unsigned int index, unsigned int data) +{ + u32 val, ep; + int i, te_flag = 0; + unsigned long timeout = jiffies + msecs_to_jiffies(500); + + /* wait for transfer buffer empty, and no event pending */ + do { + if (cpu_is_imx7ulp()) + val = readl_relaxed(mu_base + MX7ULP_MU_SR); + else + val = readl_relaxed(mu_base + MU_ASR); + ep = val & BIT(4); + if (time_after(jiffies, timeout)) { + pr_err("Waiting MU transmit buffer empty timeout!\n"); + return -EIO; + } + } while (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4))); + + if (cpu_is_imx7ulp()) + writel_relaxed(data, mu_base + index * 0x4 + MX7ULP_MU_TR0); + else + writel_relaxed(data, mu_base + index * 0x4 + MU_ATR0_OFFSET); + + /* + * make a double check that TEn is not empty after write + */ + if (cpu_is_imx7ulp()) + val = readl_relaxed(mu_base + MX7ULP_MU_SR); + else + val = readl_relaxed(mu_base + MU_ASR); + ep = val & BIT(4); + if (((val & (1 << (20 + (3 - index)))) == 0) || (ep == BIT(4))) + return 0; + else + te_flag = 1; + + /* + * Make sure that TEn flag is changed, after the ATRn is filled up. + */ + for (i = 0; i < 100; i++) { + if (cpu_is_imx7ulp()) + val = readl_relaxed(mu_base + MX7ULP_MU_SR); + else + val = readl_relaxed(mu_base + MU_ASR); + ep = val & BIT(4); + if (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4))) { + /* + * BUG here. TEn flag is changes, after the + * ATRn is filled with MSG for a while. + */ + te_flag = 0; + break; + } else if (time_after(jiffies, timeout)) { + /* Can't see TEn 1->0, maybe already handled! */ + te_flag = 1; + break; + } + } + if (te_flag == 0) + pr_info("BUG: TEn is not changed immediately" + "when ATRn is filled up.\n"); + + return 0; +} + +static void mu_work_handler(struct work_struct *work) +{ + int ret; + u32 irq, enable, idx, mask, virq; + struct of_phandle_args args; + u32 message; + unsigned long flags; + + spin_lock_irqsave(&mu_lock, flags); + message = m4_message[out_idx % MAX_NUM]; + spin_unlock_irqrestore(&mu_lock, flags); + + pr_debug("receive M4 message 0x%x\n", message); + + switch (message) { + case MU_LPM_M4_RUN_MODE: + case MU_LPM_M4_WAIT_MODE: + m4_in_stop = false; + break; + case MU_LPM_M4_STOP_MODE: + m4_in_stop = true; + break; + case MU_LPM_M4_REQUEST_HIGH_BUS: + request_bus_freq(BUS_FREQ_HIGH); +#ifdef CONFIG_SOC_IMX6SX + if (cpu_is_imx6sx()) + imx6sx_set_m4_highfreq(true); +#endif + imx_mu_send_message(MU_LPM_HANDSHAKE_INDEX, + MU_LPM_BUS_HIGH_READY_FOR_M4); + m4_freq_low = false; + break; + case MU_LPM_M4_RELEASE_HIGH_BUS: + release_bus_freq(BUS_FREQ_HIGH); +#ifdef CONFIG_SOC_IMX6SX + if (cpu_is_imx6sx()) { + imx6sx_set_m4_highfreq(false); + imx_mu_send_message(MU_LPM_HANDSHAKE_INDEX, + MU_LPM_M4_FREQ_CHANGE_READY); + } +#endif + m4_freq_low = true; + break; + default: + if ((message & MU_LPM_M4_WAKEUP_SRC_MASK) == + MU_LPM_M4_WAKEUP_SRC_VAL) { + irq = (message & MU_LPM_M4_WAKEUP_IRQ_MASK) >> + MU_LPM_M4_WAKEUP_IRQ_SHIFT; + + enable = (message & MU_LPM_M4_WAKEUP_ENABLE_MASK) >> + MU_LPM_M4_WAKEUP_ENABLE_SHIFT; + + /* to hwirq start from 0 */ + irq -= 32; + + idx = irq / 32; + mask = 1 << irq % 32; + + args.np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-gpc"); + args.args_count = 3; + args.args[0] = 0; + args.args[1] = irq; + args.args[2] = IRQ_TYPE_LEVEL_HIGH; + + virq = irq_create_of_mapping(&args); + + if (enable && can_request_irq(virq, 0)) { + ret = request_irq(virq, mcc_m4_dummy_isr, + IRQF_NO_SUSPEND, "imx-m4-dummy", NULL); + if (ret) { + pr_err("%s: register interrupt %d failed, rc %d\n", + __func__, virq, ret); + break; + } + disable_irq(virq); + m4_wake_irqs[idx] = m4_wake_irqs[idx] | mask; + } + imx_gpc_add_m4_wake_up_irq(irq, enable); + } + break; + } + + spin_lock_irqsave(&mu_lock, flags); + m4_message[out_idx % MAX_NUM] = 0; + out_idx++; + spin_unlock_irqrestore(&mu_lock, flags); + + /* enable RIE3 interrupt */ + if (cpu_is_imx7ulp()) + writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) | BIT(27), + mu_base + MX7ULP_MU_CR); + else + writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(27), + mu_base + MU_ACR); +} + +int imx_mu_lpm_ready(bool ready) +{ + u32 val; + + if (cpu_is_imx7ulp()) { + val = readl_relaxed(mu_base + MX7ULP_MU_CR); + if (ready) + writel_relaxed(val | BIT(0), mu_base + MX7ULP_MU_CR); + else + writel_relaxed(val & ~BIT(0), mu_base + MX7ULP_MU_CR); + } else { + val = readl_relaxed(mu_base + MU_ACR); + if (ready) + writel_relaxed(val | BIT(0), mu_base + MU_ACR); + else + writel_relaxed(val & ~BIT(0), mu_base + MU_ACR); + } + return 0; +} + +static irqreturn_t imx_mu_isr(int irq, void *param) +{ + u32 irqs; + unsigned long flags; + + if (cpu_is_imx7ulp()) + irqs = readl_relaxed(mu_base + MX7ULP_MU_SR); + else + irqs = readl_relaxed(mu_base + MU_ASR); + + if (irqs & (1 << 27)) { + spin_lock_irqsave(&mu_lock, flags); + /* get message from receive buffer */ + if (cpu_is_imx7ulp()) + m4_message[in_idx % MAX_NUM] = readl_relaxed(mu_base + + MX7ULP_MU_RR0); + else + m4_message[in_idx % MAX_NUM] = readl_relaxed(mu_base + + MU_ARR0_OFFSET); + /* disable RIE3 interrupt */ + if (cpu_is_imx7ulp()) + writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) + & (~BIT(27)), mu_base + MX7ULP_MU_CR); + else + writel_relaxed(readl_relaxed(mu_base + MU_ACR) + & (~BIT(27)), mu_base + MU_ACR); + in_idx++; + if (in_idx == out_idx) { + spin_unlock_irqrestore(&mu_lock, flags); + pr_err("MU overflow!\n"); + return IRQ_HANDLED; + } + spin_unlock_irqrestore(&mu_lock, flags); + + schedule_delayed_work(&mu_work, 0); + } + + return IRQ_HANDLED; +} + +static int imx_mu_probe(struct platform_device *pdev) +{ + int ret; + u32 irq; + struct device_node *np; + struct device *dev = &pdev->dev; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu-lp"); + mu_base = of_iomap(np, 0); + WARN_ON(!mu_base); + + ret = of_device_is_compatible(np, "fsl,imx7ulp-mu-lp"); + if (ret) + irq = platform_get_irq(pdev, 1); + else + irq = platform_get_irq(pdev, 0); + ret = request_irq(irq, imx_mu_isr, + IRQF_NO_SUSPEND | IRQF_SHARED, "imx-mu-lp", dev); + if (ret) { + pr_err("%s: register interrupt %d failed, rc %d\n", + __func__, irq, ret); + return ret; + } + + ret = of_device_is_compatible(np, "fsl,imx7d-mu-lp"); + if (ret) { + clk = devm_clk_get(&pdev->dev, "mu"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, + "mu clock source missing or invalid\n"); + return PTR_ERR(clk); + } else { + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(&pdev->dev, + "unable to enable mu clock\n"); + return ret; + } + } + + /* MU always as a wakeup source for low power mode */ + imx_gpcv2_add_m4_wake_up_irq(irq_to_desc(irq)->irq_data.hwirq, + true); + } else { + /* MU always as a wakeup source for low power mode */ + imx_gpc_add_m4_wake_up_irq(irq_to_desc(irq)->irq_data.hwirq, true); + } + + INIT_DELAYED_WORK(&mu_work, mu_work_handler); + /* bit0 of MX7ULP_MU_CR used to let m4 to know MU is ready now */ + if (cpu_is_imx7ulp()) + writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) | + BIT(0) | BIT(26) | BIT(27), mu_base + MX7ULP_MU_CR); + else + writel_relaxed(readl_relaxed(mu_base + MU_ACR) | + BIT(26) | BIT(27), mu_base + MU_ACR); + + pr_info("MU is ready for cross core communication!\n"); + + return 0; +} + +static const struct of_device_id imx_mu_ids[] = { + { .compatible = "fsl,imx6sx-mu-lp" }, + { .compatible = "fsl,imx7d-mu-lp" }, + { .compatible = "fsl,imx7ulp-mu-lp" }, + { } +}; + +#ifdef CONFIG_PM_SLEEP +static int mu_suspend(struct device *dev) +{ + return 0; +} + +static int mu_resume(struct device *dev) +{ + if (!cpu_is_imx7ulp()) + return 0; + + writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) | + BIT(0) | BIT(26) | BIT(27), mu_base + MX7ULP_MU_CR); + + return 0; +} +#endif +static const struct dev_pm_ops mu_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(mu_suspend, mu_resume) +}; + +static struct platform_driver imx_mu_driver = { + .driver = { + .name = "imx-mu-lp", + .owner = THIS_MODULE, + .pm = &mu_pm_ops, + .of_match_table = imx_mu_ids, + }, + .probe = imx_mu_probe, +}; + +static int __init imx_mu_init(void) +{ + return platform_driver_register(&imx_mu_driver); +} +subsys_initcall(imx_mu_init); diff --git a/arch/arm/mach-imx/mx6.h b/arch/arm/mach-imx/mx6.h new file mode 100644 index 000000000000..06b8135a9954 --- /dev/null +++ b/arch/arm/mach-imx/mx6.h @@ -0,0 +1,51 @@ +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License version 2 as + * * published by the Free Software Foundation. + * */ + +#ifndef __ASM_ARCH_MXC_IOMAP_H__ +#define __ASM_ARCH_MXC_IOMAP_H__ + +#define MX6Q_IO_P2V(x) IMX_IO_P2V(x) +#define MX6Q_IO_ADDRESS(x) IOMEM(MX6Q_IO_P2V(x)) + +#define MX6Q_L2_BASE_ADDR 0x00a02000 +#define MX6Q_L2_SIZE 0x1000 +#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000 +#define MX6Q_IOMUXC_SIZE 0x4000 +#define MX6Q_SRC_BASE_ADDR 0x020d8000 +#define MX6Q_SRC_SIZE 0x4000 +#define MX6Q_CCM_BASE_ADDR 0x020c4000 +#define MX6Q_CCM_SIZE 0x4000 +#define MX6Q_ANATOP_BASE_ADDR 0x020c8000 +#define MX6Q_ANATOP_SIZE 0x1000 +#define MX6Q_GPC_BASE_ADDR 0x020dc000 +#define MX6Q_GPC_SIZE 0x4000 +#define MX6Q_SEMA4_BASE_ADDR 0x02290000 +#define MX6Q_SEMA4_SIZE 0x4000 +#define MX6Q_MMDC_P0_BASE_ADDR 0x021b0000 +#define MX6Q_MMDC_P0_SIZE 0x4000 +#define MX6Q_MMDC_P1_BASE_ADDR 0x021b4000 +#define MX6Q_MMDC_P1_SIZE 0x4000 +#define MX6Q_AIPS1_BASE_ADDR 0x02000000 +#define MX6Q_AIPS1_SIZE 0x100000 +#define MX6Q_AIPS2_BASE_ADDR 0x02100000 +#define MX6Q_AIPS2_SIZE 0x100000 +#define MX6Q_AIPS3_BASE_ADDR 0x02200000 +#define MX6Q_AIPS3_SIZE 0x100000 + +#define MX6SX_IRAM_TLB_BASE_ADDR 0x008f8000 +#define MX6Q_IRAM_TLB_BASE_ADDR 0x00900000 +#define MX6Q_IRAM_TLB_SIZE 0x4000 +#define TT_ATTRIB_NON_CACHEABLE_1M 0x802 +#define MX6_SUSPEND_IRAM_DATA_SIZE 256 +#define MX6SL_WFI_IRAM_DATA_SIZE 100 + +#define MX6_SUSPEND_IRAM_ADDR_OFFSET 0 +#define MX6_CPUIDLE_IRAM_ADDR_OFFSET 0x1000 +#endif diff --git a/arch/arm/mach-imx/mx7.h b/arch/arm/mach-imx/mx7.h new file mode 100644 index 000000000000..afbeaef12d07 --- /dev/null +++ b/arch/arm/mach-imx/mx7.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License version 2 as + * * published by the Free Software Foundation. + * */ + +#ifndef __ASM_ARCH_MX7_IOMAP_H__ +#define __ASM_ARCH_MX7_IOMAP_H__ + +#define MX7D_IO_P2V(x) IMX_IO_P2V(x) +#define MX7D_IO_ADDRESS(x) IOMEM(MX7D_IO_P2V(x)) + +#define MX7D_LPSR_BASE_ADDR 0x30270000 +#define MX7D_LPSR_SIZE 0x10000 +#define MX7D_CCM_BASE_ADDR 0x30380000 +#define MX7D_CCM_SIZE 0x10000 +#define MX7D_IOMUXC_BASE_ADDR 0x30330000 +#define MX7D_IOMUXC_SIZE 0x10000 +#define MX7D_IOMUXC_GPR_BASE_ADDR 0x30340000 +#define MX7D_IOMUXC_GPR_SIZE 0x10000 +#define MX7D_ANATOP_BASE_ADDR 0x30360000 +#define MX7D_ANATOP_SIZE 0x10000 +#define MX7D_SNVS_BASE_ADDR 0x30370000 +#define MX7D_SNVS_SIZE 0x10000 +#define MX7D_GPC_BASE_ADDR 0x303a0000 +#define MX7D_GPC_SIZE 0x10000 +#define MX7D_SRC_BASE_ADDR 0x30390000 +#define MX7D_SRC_SIZE 0x10000 +#define MX7D_DDRC_BASE_ADDR 0x307a0000 +#define MX7D_DDRC_SIZE 0x10000 +#define MX7D_DDRC_PHY_BASE_ADDR 0x30790000 +#define MX7D_DDRC_PHY_SIZE 0x10000 +#define MX7D_AIPS1_BASE_ADDR 0x30000000 +#define MX7D_AIPS1_SIZE 0x400000 +#define MX7D_AIPS2_BASE_ADDR 0x30400000 +#define MX7D_AIPS2_SIZE 0x400000 +#define MX7D_AIPS3_BASE_ADDR 0x30900000 +#define MX7D_AIPS3_SIZE 0x300000 +#define MX7D_GIC_BASE_ADDR 0x31000000 +#define MX7D_GIC_SIZE 0x100000 + +#define TT_ATTRIB_NON_CACHEABLE_1M 0x802 +#define MX7_IRAM_TLB_SIZE 0x4000 +#define MX7_SUSPEND_OCRAM_SIZE 0x1000 +#define MX7_CPUIDLE_OCRAM_ADDR_OFFSET 0x1000 +#define MX7_CPUIDLE_OCRAM_SIZE 0x1000 +#define MX7_BUSFREQ_OCRAM_ADDR_OFFSET 0x2000 +#define MX7_BUSFREQ_OCRAM_SIZE 0x1000 + +#endif diff --git a/arch/arm/mach-imx/mx7ulp.h b/arch/arm/mach-imx/mx7ulp.h new file mode 100644 index 000000000000..35638dfea68b --- /dev/null +++ b/arch/arm/mach-imx/mx7ulp.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright NXP 2017. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_MX7ULP_IOMAP_H__ +#define __ASM_ARCH_MX7ULP_IOMAP_H__ + +#define MX7ULP_IO_P2V(x) IMX_IO_P2V(x) +#define MX7ULP_IO_ADDRESS(x) IOMEM(MX7ULP_IO_P2V(x)) + +#define MX7ULP_AIPS1_BASE_ADDR 0x40000000 +#define MX7ULP_AIPS1_SIZE 0x100000 +#define MX7ULP_AIPS2_BASE_ADDR 0x40300000 +#define MX7ULP_AIPS2_SIZE 0x100000 +#define MX7ULP_AIPS3_BASE_ADDR 0x40400000 +#define MX7ULP_AIPS3_SIZE 0x100000 +#define MX7ULP_AIPS4_BASE_ADDR 0x40a00000 +#define MX7ULP_AIPS4_SIZE 0x100000 +#define MX7ULP_AIPS5_BASE_ADDR 0x41000000 +#define MX7ULP_AIPS5_SIZE 0x100000 +#define MX7ULP_GPIOC_BASE_ADDR 0x400f0000 +#define MX7ULP_GPIOC_SIZE 0x1000 +#define MX7ULP_PCC3_BASE_ADDR 0x40b30000 +#define MX7ULP_PCC3_SIZE 0x1000 +#define MX7ULP_SCG1_BASE_ADDR 0x403e0000 +#define MX7ULP_SCG1_SIZE 0x1000 +#define MX7ULP_PCC2_BASE_ADDR 0x403f0000 +#define MX7ULP_PCC2_SIZE 0x1000 +#define MX7ULP_SIM_BASE_ADDR 0x410a3000 +#define MX7ULP_SIM_SIZE 0x1000 +#define MX7ULP_PMC1_BASE_ADDR 0x40400000 +#define MX7ULP_PMC1_SIZE 0x1000 +#define MX7ULP_SMC1_BASE_ADDR 0x40410000 +#define MX7ULP_SMC1_SIZE 0x1000 +#define MX7ULP_MMDC_BASE_ADDR 0x40ab0000 +#define MX7ULP_MMDC_SIZE 0x1000 +#define MX7ULP_IOMUXC1_BASE_ADDR 0x40ac0000 +#define MX7ULP_IOMUXC1_BASE__SIZE 0x1000 +#define MX7ULP_MMDC_IO_BASE_ADDR 0x40ad0000 +#define MX7ULP_MMDC_IO_SIZE 0x1000 + +/* below is just used for static mapping of the AIPSx's memory region */ +#define MX7ULP_AIPS_VIRT_BASE(x) (0xf4000000 + ((x) * SZ_1M)) + +#define mx7ulp_aips_map_entry(index, _type) { \ + .virtual = MX7ULP_AIPS_VIRT_BASE(index), \ + .pfn = __phys_to_pfn(MX7ULP_AIPS ## index ## _BASE_ADDR), \ + .length = SZ_1M, \ + .type = _type, \ +} + +#define TT_ATTRIB_NON_CACHEABLE_1M 0x802 +#define MX7ULP_IRAM_TLB_SIZE 0x4000 +#define MX7ULP_SUSPEND_OCRAM_SIZE 0x1000 + +#endif diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 2bfd2d59b4a6..c311f9d48de2 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -33,7 +33,13 @@ #define MXC_CPU_IMX7D 0x72 #define MXC_CPU_IMX7ULP 0xff +#define IMX_DDR_TYPE_DDR3 0 #define IMX_DDR_TYPE_LPDDR2 1 +#define IMX_DDR_TYPE_LPDDR3 2 +#define IMX_MMDC_DDR_TYPE_LPDDR3 3 + +#define IMX_LPDDR2_1CH_MODE 0 +#define IMX_LPDDR2_2CH_MODE 1 #ifndef __ASSEMBLY__ extern unsigned int __mxc_cpu_type; @@ -85,11 +91,28 @@ static inline bool cpu_is_imx6q(void) return __mxc_cpu_type == MXC_CPU_IMX6Q; } +static inline bool cpu_is_imx6(void) +{ + return __mxc_cpu_type == MXC_CPU_IMX6Q || + __mxc_cpu_type == MXC_CPU_IMX6DL || + __mxc_cpu_type == MXC_CPU_IMX6SL || + __mxc_cpu_type == MXC_CPU_IMX6SX || + __mxc_cpu_type == MXC_CPU_IMX6UL || + __mxc_cpu_type == MXC_CPU_IMX6ULL || + __mxc_cpu_type == MXC_CPU_IMX6SLL || + __mxc_cpu_type == MXC_CPU_IMX6ULZ; +} + static inline bool cpu_is_imx7d(void) { return __mxc_cpu_type == MXC_CPU_IMX7D; } +static inline bool cpu_is_imx7ulp(void) +{ + return __mxc_cpu_type == MXC_CPU_IMX7ULP; +} + struct cpu_op { u32 cpu_rate; }; diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 2aa26928221d..90dccaa66c89 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -18,7 +18,7 @@ #include "hardware.h" u32 g_diag_reg; -static void __iomem *scu_base; +void __iomem *scu_base; static struct map_desc scu_io_desc __initdata = { /* .virtual and .pfn are run-time assigned */ @@ -47,15 +47,39 @@ static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle) return 0; } +#define MXC_ARCH_CA7 0xc07 +static unsigned long __mxc_arch_type; + +static inline bool arm_is_ca7(void) +{ + return __mxc_arch_type == MXC_ARCH_CA7; +} /* * Initialise the CPU possible map early - this describes the CPUs * which may be present or become present in the system. */ static void __init imx_smp_init_cpus(void) { + unsigned long arch_type; int i, ncores; - ncores = scu_get_core_count(scu_base); + asm volatile( + ".align 4\n" + "mrc p15, 0, %0, c0, c0, 0\n" + : "=r" (arch_type) + ); + /* MIDR[15:4] defines ARCH type */ + __mxc_arch_type = (arch_type >> 4) & 0xfff; + + if (arm_is_ca7()) { + unsigned long val; + + /* CA7 core number, [25:24] of CP15 L2CTLR */ + asm volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (val)); + ncores = ((val >> 24) & 0x3) + 1; + } else { + ncores = scu_get_core_count(scu_base); + } for (i = ncores; i < NR_CPUS; i++) set_cpu_possible(i, false); @@ -63,11 +87,15 @@ static void __init imx_smp_init_cpus(void) void imx_smp_prepare(void) { + if (arm_is_ca7()) + return; scu_enable(scu_base); } static void __init imx_smp_prepare_cpus(unsigned int max_cpus) { + if (arm_is_ca7()) + return; imx_smp_prepare(); /* diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index baf3b47601af..df767169ad2c 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011-2016 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. */ @@ -13,15 +13,21 @@ #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_fdt.h> #include <linux/of_platform.h> +#include <linux/psci.h> #include <linux/regmap.h> +#include <linux/slab.h> #include <linux/suspend.h> #include <asm/cacheflush.h> #include <asm/fncpy.h> +#include <asm/mach/map.h> #include <asm/proc-fns.h> #include <asm/suspend.h> #include <asm/tlb.h> +#include <uapi/linux/psci.h> + #include "common.h" #include "hardware.h" @@ -54,13 +60,215 @@ #define CGPR 0x64 #define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17) +#define CCGR4 0x78 +#define CCGR6 0x80 #define MX6Q_SUSPEND_OCRAM_SIZE 0x1000 -#define MX6_MAX_MMDC_IO_NUM 33 +#define MX6_MAX_MMDC_IO_NUM 36 +#define MX6_MAX_MMDC_NUM 36 + +#define ROMC_ROMPATCH0D 0xf0 +#define ROMC_ROMPATCHCNTL 0xf4 +#define ROMC_ROMPATCHENL 0xfc +#define ROMC_ROMPATCH0A 0x100 +#define BM_ROMPATCHCNTL_0D (0x1 << 0) +#define BM_ROMPATCHCNTL_DIS (0x1 << 29) +#define BM_ROMPATCHENL_0D (0x1 << 0) +#define ROM_ADDR_FOR_INTERNAL_RAM_BASE 0x10d7c + +#define UART_UCR1 0x80 +#define UART_UCR2 0x84 +#define UART_UCR3 0x88 +#define UART_UCR4 0x8c +#define UART_UFCR 0x90 +#define UART_UESC 0x9c +#define UART_UTIM 0xa0 +#define UART_UBIR 0xa4 +#define UART_UBMR 0xa8 +#define UART_UBRC 0xac +#define UART_UTS 0xb4 + +#define IOMUXC_GPR5_CLOCK_AFCG_X_BYPASS_MASK 0xf800 + +extern unsigned long iram_tlb_base_addr; +extern unsigned long iram_tlb_phys_addr; + +/* QSPI register layout */ +#define QSPI_MCR 0x00 +#define QSPI_IPCR 0x08 +#define QSPI_BUF0CR 0x10 +#define QSPI_BUF1CR 0x14 +#define QSPI_BUF2CR 0x18 +#define QSPI_BUF3CR 0x1c +#define QSPI_BFGENCR 0x20 +#define QSPI_BUF0IND 0x30 +#define QSPI_BUF1IND 0x34 +#define QSPI_BUF2IND 0x38 +#define QSPI_SFAR 0x100 +#define QSPI_SMPR 0x108 +#define QSPI_RBSR 0x10c +#define QSPI_RBCT 0x110 +#define QSPI_TBSR 0x150 +#define QSPI_TBDR 0x154 +#define QSPI_SFA1AD 0x180 +#define QSPI_SFA2AD 0x184 +#define QSPI_SFB1AD 0x188 +#define QSPI_SFB2AD 0x18c +#define QSPI_RBDR_BASE 0x200 +#define QSPI_LUTKEY 0x300 +#define QSPI_LCKCR 0x304 +#define QSPI_LUT_BASE 0x310 + +#define QSPI_RBDR_(x) (QSPI_RBDR_BASE + (x) * 4) +#define QSPI_LUT(x) (QSPI_LUT_BASE + (x) * 4) + +#define QSPI_LUTKEY_VALUE 0x5AF05AF0 +#define QSPI_LCKER_LOCK 0x1 +#define QSPI_LCKER_UNLOCK 0x2 + +enum qspi_regs_valuetype { + QSPI_PREDEFINED, + QSPI_RETRIEVED, +}; + +struct qspi_regs { + int offset; + unsigned int value; + enum qspi_regs_valuetype valuetype; +}; +struct qspi_regs qspi_regs_imx6sx[] = { + {QSPI_IPCR, 0, QSPI_RETRIEVED}, + {QSPI_BUF0CR, 0, QSPI_RETRIEVED}, + {QSPI_BUF1CR, 0, QSPI_RETRIEVED}, + {QSPI_BUF2CR, 0, QSPI_RETRIEVED}, + {QSPI_BUF3CR, 0, QSPI_RETRIEVED}, + {QSPI_BFGENCR, 0, QSPI_RETRIEVED}, + {QSPI_BUF0IND, 0, QSPI_RETRIEVED}, + {QSPI_BUF1IND, 0, QSPI_RETRIEVED}, + {QSPI_BUF2IND, 0, QSPI_RETRIEVED}, + {QSPI_SFAR, 0, QSPI_RETRIEVED}, + {QSPI_SMPR, 0, QSPI_RETRIEVED}, + {QSPI_RBSR, 0, QSPI_RETRIEVED}, + {QSPI_RBCT, 0, QSPI_RETRIEVED}, + {QSPI_TBSR, 0, QSPI_RETRIEVED}, + {QSPI_TBDR, 0, QSPI_RETRIEVED}, + {QSPI_SFA1AD, 0, QSPI_RETRIEVED}, + {QSPI_SFA2AD, 0, QSPI_RETRIEVED}, + {QSPI_SFB1AD, 0, QSPI_RETRIEVED}, + {QSPI_SFB2AD, 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(0), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(1), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(2), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(3), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(4), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(5), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(6), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(7), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(8), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(9), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(10), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(11), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(12), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(13), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(14), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(15), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(16), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(17), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(18), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(19), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(20), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(21), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(22), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(23), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(24), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(25), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(26), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(27), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(28), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(29), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(30), 0, QSPI_RETRIEVED}, + {QSPI_RBDR_(31), 0, QSPI_RETRIEVED}, + {QSPI_LUTKEY, QSPI_LUTKEY_VALUE, QSPI_PREDEFINED}, + {QSPI_LCKCR, QSPI_LCKER_UNLOCK, QSPI_PREDEFINED}, + {QSPI_LUT(0), 0, QSPI_RETRIEVED}, + {QSPI_LUT(1), 0, QSPI_RETRIEVED}, + {QSPI_LUT(2), 0, QSPI_RETRIEVED}, + {QSPI_LUT(3), 0, QSPI_RETRIEVED}, + {QSPI_LUT(4), 0, QSPI_RETRIEVED}, + {QSPI_LUT(5), 0, QSPI_RETRIEVED}, + {QSPI_LUT(6), 0, QSPI_RETRIEVED}, + {QSPI_LUT(7), 0, QSPI_RETRIEVED}, + {QSPI_LUT(8), 0, QSPI_RETRIEVED}, + {QSPI_LUT(9), 0, QSPI_RETRIEVED}, + {QSPI_LUT(10), 0, QSPI_RETRIEVED}, + {QSPI_LUT(11), 0, QSPI_RETRIEVED}, + {QSPI_LUT(12), 0, QSPI_RETRIEVED}, + {QSPI_LUT(13), 0, QSPI_RETRIEVED}, + {QSPI_LUT(14), 0, QSPI_RETRIEVED}, + {QSPI_LUT(15), 0, QSPI_RETRIEVED}, + {QSPI_LUT(16), 0, QSPI_RETRIEVED}, + {QSPI_LUT(17), 0, QSPI_RETRIEVED}, + {QSPI_LUT(18), 0, QSPI_RETRIEVED}, + {QSPI_LUT(19), 0, QSPI_RETRIEVED}, + {QSPI_LUT(20), 0, QSPI_RETRIEVED}, + {QSPI_LUT(21), 0, QSPI_RETRIEVED}, + {QSPI_LUT(22), 0, QSPI_RETRIEVED}, + {QSPI_LUT(23), 0, QSPI_RETRIEVED}, + {QSPI_LUT(24), 0, QSPI_RETRIEVED}, + {QSPI_LUT(25), 0, QSPI_RETRIEVED}, + {QSPI_LUT(26), 0, QSPI_RETRIEVED}, + {QSPI_LUT(27), 0, QSPI_RETRIEVED}, + {QSPI_LUT(28), 0, QSPI_RETRIEVED}, + {QSPI_LUT(29), 0, QSPI_RETRIEVED}, + {QSPI_LUT(30), 0, QSPI_RETRIEVED}, + {QSPI_LUT(31), 0, QSPI_RETRIEVED}, + {QSPI_LUT(32), 0, QSPI_RETRIEVED}, + {QSPI_LUT(33), 0, QSPI_RETRIEVED}, + {QSPI_LUT(34), 0, QSPI_RETRIEVED}, + {QSPI_LUT(35), 0, QSPI_RETRIEVED}, + {QSPI_LUT(36), 0, QSPI_RETRIEVED}, + {QSPI_LUT(37), 0, QSPI_RETRIEVED}, + {QSPI_LUT(38), 0, QSPI_RETRIEVED}, + {QSPI_LUT(39), 0, QSPI_RETRIEVED}, + {QSPI_LUT(40), 0, QSPI_RETRIEVED}, + {QSPI_LUT(41), 0, QSPI_RETRIEVED}, + {QSPI_LUT(42), 0, QSPI_RETRIEVED}, + {QSPI_LUT(43), 0, QSPI_RETRIEVED}, + {QSPI_LUT(44), 0, QSPI_RETRIEVED}, + {QSPI_LUT(45), 0, QSPI_RETRIEVED}, + {QSPI_LUT(46), 0, QSPI_RETRIEVED}, + {QSPI_LUT(47), 0, QSPI_RETRIEVED}, + {QSPI_LUT(48), 0, QSPI_RETRIEVED}, + {QSPI_LUT(49), 0, QSPI_RETRIEVED}, + {QSPI_LUT(50), 0, QSPI_RETRIEVED}, + {QSPI_LUT(51), 0, QSPI_RETRIEVED}, + {QSPI_LUT(52), 0, QSPI_RETRIEVED}, + {QSPI_LUT(53), 0, QSPI_RETRIEVED}, + {QSPI_LUT(54), 0, QSPI_RETRIEVED}, + {QSPI_LUT(55), 0, QSPI_RETRIEVED}, + {QSPI_LUT(56), 0, QSPI_RETRIEVED}, + {QSPI_LUT(57), 0, QSPI_RETRIEVED}, + {QSPI_LUT(58), 0, QSPI_RETRIEVED}, + {QSPI_LUT(59), 0, QSPI_RETRIEVED}, + {QSPI_LUT(60), 0, QSPI_RETRIEVED}, + {QSPI_LUT(61), 0, QSPI_RETRIEVED}, + {QSPI_LUT(62), 0, QSPI_RETRIEVED}, + {QSPI_LUT(63), 0, QSPI_RETRIEVED}, + {QSPI_LUTKEY, QSPI_LUTKEY_VALUE, QSPI_PREDEFINED}, + {QSPI_LCKCR, QSPI_LCKER_LOCK, QSPI_PREDEFINED}, + {QSPI_MCR, 0, QSPI_RETRIEVED}, +}; + +static unsigned int *ocram_saved_in_ddr; +static void __iomem *ocram_base; +static void __iomem *console_base; +static void __iomem *qspi_base; +static unsigned int ocram_size; static void __iomem *ccm_base; static void __iomem *suspend_ocram_base; static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); +struct regmap *romcp; /* * suspend ocram space layout: @@ -90,6 +298,8 @@ struct imx6_pm_socdata { const char *pl310_compat; const u32 mmdc_io_num; const u32 *mmdc_io_offset; + const u32 mmdc_num; + const u32 *mmdc_offset; }; static const u32 imx6q_mmdc_io_offset[] __initconst = { @@ -104,6 +314,18 @@ static const u32 imx6q_mmdc_io_offset[] __initconst = { 0x74c, /* GPR_ADDS */ }; +static const u32 imx6q_mmdc_io_lpddr2_offset[] __initconst = { + 0x5ac, 0x5b4, 0x528, 0x520, /* DQM0 ~ DQM3 */ + 0x514, 0x510, 0x5bc, 0x5c4, /* DQM4 ~ DQM7 */ + 0x784, 0x788, 0x794, 0x79c, /* GPR_B0DS ~ GPR_B3DS */ + 0x7a0, 0x7a4, 0x7a8, 0x748, /* GPR_B4DS ~ GPR_B7DS */ + 0x56c, 0x578, 0x588, 0x594, /* CAS, RAS, SDCLK_0, SDCLK_1 */ + 0x5a8, 0x5b0, 0x524, 0x51c, /* SDQS0 ~ SDQS3 */ + 0x518, 0x50c, 0x5b8, 0x5c0, /* SDQS4 ~ SDQS7 */ + 0x59c, 0x5a0, 0x750, 0x774, /* SODT0, SODT1, MODE_CTL, MODE */ + 0x74c, 0x590, 0x598, 0x57c, /* GRP_ADDS, SDCKE0, SDCKE1, RESET */ +}; + static const u32 imx6dl_mmdc_io_offset[] __initconst = { 0x470, 0x474, 0x478, 0x47c, /* DQM0 ~ DQM3 */ 0x480, 0x484, 0x488, 0x48c, /* DQM4 ~ DQM7 */ @@ -124,11 +346,25 @@ static const u32 imx6sl_mmdc_io_offset[] __initconst = { 0x330, 0x334, 0x320, /* SDCKE0, SDCKE1, RESET */ }; -static const u32 imx6sll_mmdc_io_offset[] __initconst = { - 0x294, 0x298, 0x29c, 0x2a0, /* DQM0 ~ DQM3 */ - 0x544, 0x54c, 0x554, 0x558, /* GPR_B0DS ~ GPR_B3DS */ - 0x530, 0x540, 0x2ac, 0x52c, /* MODE_CTL, MODE, SDCLK_0, GPR_ADDDS */ - 0x2a4, 0x2a8, /* SDCKE0, SDCKE1*/ +static const u32 imx6sx_mmdc_io_lpddr2_offset[] __initconst = { + 0x2ec, 0x2f0, 0x2f4, 0x2f8, /* DQM0 ~ DQM3 */ + 0x300, 0x2fc, 0x32c, 0x5f4, /* CAS, RAS, SDCLK_0, GPR_ADDS */ + 0x60c, 0x610, 0x61c, 0x620, /* GPR_B0DS ~ GPR_B3DS */ + 0x310, 0x314, 0x5f8, 0x608, /* SODT0, SODT1, MODE_CTL, MODE */ + 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ + 0x324, 0x328, 0x340, /* DRAM_SDCKE0 ~ 1, DRAM_RESET */ +}; + +static const u32 imx6sx_mmdc_lpddr2_offset[] __initconst = { + 0x01c, 0x85c, 0x800, 0x890, + 0x8b8, 0x81c, 0x820, 0x824, + 0x828, 0x82c, 0x830, 0x834, + 0x838, 0x848, 0x850, 0x8c0, + 0x83c, 0x840, 0x8b8, 0x00c, + 0x004, 0x010, 0x014, 0x018, + 0x02c, 0x030, 0x038, 0x008, + 0x040, 0x000, 0x020, 0x818, + 0x800, 0x004, 0x01c, }; static const u32 imx6sx_mmdc_io_offset[] __initconst = { @@ -139,6 +375,16 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ }; +static const u32 imx6sx_mmdc_offset[] __initconst = { + 0x800, 0x80c, 0x810, 0x83c, + 0x840, 0x848, 0x850, 0x81c, + 0x820, 0x824, 0x828, 0x8b8, + 0x004, 0x008, 0x00c, 0x010, + 0x014, 0x018, 0x01c, 0x02c, + 0x030, 0x040, 0x000, 0x01c, + 0x020, 0x818, 0x01c, +}; + static const u32 imx6ul_mmdc_io_offset[] __initconst = { 0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */ 0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */ @@ -146,6 +392,53 @@ static const u32 imx6ul_mmdc_io_offset[] __initconst = { 0x494, 0x4b0, /* MODE_CTL, MODE, */ }; +static const u32 imx6ul_mmdc_offset[] __initconst = { + 0x01c, 0x800, 0x80c, 0x83c, + 0x848, 0x850, 0x81c, 0x820, + 0x82c, 0x830, 0x8c0, 0x8b8, + 0x004, 0x008, 0x00c, 0x010, + 0x014, 0x018, 0x01c, 0x02c, + 0x030, 0x040, 0x000, 0x01c, + 0x020, 0x818, 0x01c, +}; + +static const u32 imx6ul_mmdc_io_lpddr2_offset[] __initconst = { + 0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */ + 0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */ + 0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */ + 0x494, 0x4b0, 0x274, 0x278, /* MODE_CTL, MODE, SDCKE0, SDCKE1 */ + 0x288, /* DRAM_RESET */ +}; + +static const u32 imx6ul_mmdc_lpddr2_offset[] __initconst = { + 0x01c, 0x85c, 0x800, 0x890, + 0x8b8, 0x81c, 0x820, 0x82c, + 0x830, 0x83c, 0x848, 0x850, + 0x8c0, 0x8b8, 0x004, 0x008, + 0x00c, 0x010, 0x038, 0x014, + 0x018, 0x01c, 0x02c, 0x030, + 0x040, 0x000, 0x020, 0x818, + 0x800, 0x004, 0x01c, +}; + +static const u32 imx6sll_mmdc_io_offset[] __initconst = { + 0x294, 0x298, 0x29c, 0x2a0, /* DQM0 ~ DQM3 */ + 0x544, 0x54c, 0x554, 0x558, /* GPR_B0DS ~ GPR_B3DS */ + 0x530, 0x540, 0x2ac, 0x52c, /* MODE_CTL, MODE, SDCLK_0, GPR_ADDDS */ + 0x2a4, 0x2a8, /* SDCKE0, SDCKE1*/ +}; + +static const u32 imx6sll_mmdc_lpddr3_offset[] __initconst = { + 0x01c, 0x85c, 0x800, 0x890, + 0x8b8, 0x81c, 0x820, 0x82c, + 0x830, 0x83c, 0x848, 0x850, + 0x8c0, 0x8b8, 0x004, 0x008, + 0x00c, 0x010, 0x038, 0x014, + 0x018, 0x01c, 0x02c, 0x030, + 0x040, 0x000, 0x020, 0x818, + 0x800, 0x004, 0x01c, +}; + static const struct imx6_pm_socdata imx6q_pm_data __initconst = { .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", @@ -154,6 +447,19 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = { .pl310_compat = "arm,pl310-cache", .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset), .mmdc_io_offset = imx6q_mmdc_io_offset, + .mmdc_num = 0, + .mmdc_offset = NULL, +}; + +static const struct imx6_pm_socdata imx6q_lpddr2_pm_data __initconst = { + .mmdc_compat = "fsl,imx6q-mmdc", + .src_compat = "fsl,imx6q-src", + .iomuxc_compat = "fsl,imx6q-iomuxc", + .gpc_compat = "fsl,imx6q-gpc", + .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_lpddr2_offset), + .mmdc_io_offset = imx6q_mmdc_io_lpddr2_offset, + .mmdc_num = 0, + .mmdc_offset = NULL, }; static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { @@ -164,6 +470,8 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { .pl310_compat = "arm,pl310-cache", .mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset), .mmdc_io_offset = imx6dl_mmdc_io_offset, + .mmdc_num = 0, + .mmdc_offset = NULL, }; static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { @@ -174,16 +482,8 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { .pl310_compat = "arm,pl310-cache", .mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset), .mmdc_io_offset = imx6sl_mmdc_io_offset, -}; - -static const struct imx6_pm_socdata imx6sll_pm_data __initconst = { - .mmdc_compat = "fsl,imx6sll-mmdc", - .src_compat = "fsl,imx6sll-src", - .iomuxc_compat = "fsl,imx6sll-iomuxc", - .gpc_compat = "fsl,imx6sll-gpc", - .pl310_compat = "arm,pl310-cache", - .mmdc_io_num = ARRAY_SIZE(imx6sll_mmdc_io_offset), - .mmdc_io_offset = imx6sll_mmdc_io_offset, + .mmdc_num = 0, + .mmdc_offset = NULL, }; static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { @@ -194,6 +494,19 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { .pl310_compat = "arm,pl310-cache", .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset), .mmdc_io_offset = imx6sx_mmdc_io_offset, + .mmdc_num = ARRAY_SIZE(imx6sx_mmdc_offset), + .mmdc_offset = imx6sx_mmdc_offset, +}; + +static const struct imx6_pm_socdata imx6sx_lpddr2_pm_data __initconst = { + .mmdc_compat = "fsl,imx6sx-mmdc", + .src_compat = "fsl,imx6sx-src", + .iomuxc_compat = "fsl,imx6sx-iomuxc", + .gpc_compat = "fsl,imx6sx-gpc", + .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_lpddr2_offset), + .mmdc_io_offset = imx6sx_mmdc_io_lpddr2_offset, + .mmdc_num = ARRAY_SIZE(imx6sx_mmdc_lpddr2_offset), + .mmdc_offset = imx6sx_mmdc_lpddr2_offset, }; static const struct imx6_pm_socdata imx6ul_pm_data __initconst = { @@ -204,6 +517,61 @@ static const struct imx6_pm_socdata imx6ul_pm_data __initconst = { .pl310_compat = NULL, .mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset), .mmdc_io_offset = imx6ul_mmdc_io_offset, + .mmdc_num = ARRAY_SIZE(imx6ul_mmdc_offset), + .mmdc_offset = imx6ul_mmdc_offset, +}; + +static const struct imx6_pm_socdata imx6ul_lpddr2_pm_data __initconst = { + .mmdc_compat = "fsl,imx6ul-mmdc", + .src_compat = "fsl,imx6ul-src", + .iomuxc_compat = "fsl,imx6ul-iomuxc", + .gpc_compat = "fsl,imx6ul-gpc", + .mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_lpddr2_offset), + .mmdc_io_offset = imx6ul_mmdc_io_lpddr2_offset, + .mmdc_num = ARRAY_SIZE(imx6ul_mmdc_lpddr2_offset), + .mmdc_offset = imx6ul_mmdc_lpddr2_offset, +}; + +static const struct imx6_pm_socdata imx6sll_pm_data __initconst = { + .mmdc_compat = "fsl,imx6sll-mmdc", + .src_compat = "fsl,imx6sll-src", + .iomuxc_compat = "fsl,imx6sll-iomuxc", + .gpc_compat = "fsl,imx6sll-gpc", + .mmdc_io_num = ARRAY_SIZE(imx6sll_mmdc_io_offset), + .mmdc_io_offset = imx6sll_mmdc_io_offset, + .mmdc_num = ARRAY_SIZE(imx6sll_mmdc_lpddr3_offset), + .mmdc_offset = imx6sll_mmdc_lpddr3_offset, +}; + +static struct map_desc iram_tlb_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_1M, + .type = MT_MEMORY_RWX_NONCACHED, +}; + +/* + * AIPS1 and AIPS2 is not used, because it will trigger a BUG_ON if + * lowlevel debug and earlyprintk are configured. + * + * it is because there is a vm conflict because UART1 is mapped early if + * AIPS1 is mapped using 1M size. + * + * Thus no use AIPS1 and AIPS2 to avoid kernel BUG_ON. + */ +static struct map_desc imx6_pm_io_desc[] __initdata = { + imx_map_entry(MX6Q, MMDC_P0, MT_DEVICE), + imx_map_entry(MX6Q, MMDC_P1, MT_DEVICE), + imx_map_entry(MX6Q, SRC, MT_DEVICE), + imx_map_entry(MX6Q, IOMUXC, MT_DEVICE), + imx_map_entry(MX6Q, CCM, MT_DEVICE), + imx_map_entry(MX6Q, ANATOP, MT_DEVICE), + imx_map_entry(MX6Q, GPC, MT_DEVICE), + imx_map_entry(MX6Q, L2, MT_DEVICE), +}; + +static const char * const low_power_ocram_match[] __initconst = { + "fsl,lpm-sram", + NULL }; /* @@ -218,14 +586,19 @@ struct imx6_cpu_pm_info { phys_addr_t resume_addr; /* The physical resume address for asm code */ u32 ddr_type; u32 pm_info_size; /* Size of pm_info. */ - struct imx6_pm_base mmdc_base; + struct imx6_pm_base mmdc0_base; + struct imx6_pm_base mmdc1_base; struct imx6_pm_base src_base; struct imx6_pm_base iomuxc_base; struct imx6_pm_base ccm_base; struct imx6_pm_base gpc_base; struct imx6_pm_base l2_base; + struct imx6_pm_base anatop_base; + u32 ttbr1; /* Store TTBR1 */ u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ - u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ + u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][3]; /* To save offset, value, low power settings */ + u32 mmdc_num; /* Number of MMDC registers which need saved/restored. */ + u32 mmdc_val[MX6_MAX_MMDC_NUM][2]; } __aligned(8); void imx6_set_int_mem_clk_lpm(bool enable) @@ -304,11 +677,18 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) val |= 0x2 << BP_CLPCR_LPM; val &= ~BM_CLPCR_VSTBY; val &= ~BM_CLPCR_SBYOS; - if (cpu_is_imx6sl()) + if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6sll()) val |= BM_CLPCR_BYPASS_PMIC_READY; if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() || - cpu_is_imx6ull() || cpu_is_imx6sll() || cpu_is_imx6ulz()) + cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; + else if (cpu_is_imx6q() && + imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2 && + imx_mmdc_get_lpddr2_2ch_mode() == IMX_LPDDR2_2CH_MODE) { + /* keep handshake enabled for lpddr2 2ch-mode */ + val &= ~BM_CLPCR_BYP_MMDC_CH0_LPM_HS; + val &= ~BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + } else val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; break; @@ -322,11 +702,18 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) val |= 0x3 << BP_CLPCR_STBY_COUNT; val |= BM_CLPCR_VSTBY; val |= BM_CLPCR_SBYOS; - if (cpu_is_imx6sl() || cpu_is_imx6sx()) + if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6sll()) val |= BM_CLPCR_BYPASS_PMIC_READY; if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() || - cpu_is_imx6ull() || cpu_is_imx6sll() || cpu_is_imx6ulz()) + cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; + else if (cpu_is_imx6q() && + imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2 && + imx_mmdc_get_lpddr2_2ch_mode() == IMX_LPDDR2_2CH_MODE) { + /* keep handshake enabled for lpddr2 2ch-mode */ + val &= ~BM_CLPCR_BYP_MMDC_CH0_LPM_HS; + val &= ~BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + } else val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; break; @@ -357,8 +744,18 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) return 0; } +#define MX6Q_SUSPEND_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + static int imx6q_suspend_finish(unsigned long val) { + if (psci_ops.cpu_suspend) { + return psci_ops.cpu_suspend(MX6Q_SUSPEND_PARAM, + __pa(cpu_resume)); + } + if (!imx6_suspend_in_ocram_fn) { cpu_do_idle(); } else { @@ -377,19 +774,104 @@ static int imx6q_suspend_finish(unsigned long val) return 0; } +static void imx6_console_save(unsigned int *regs) +{ + if (!console_base) + return; + + regs[0] = readl_relaxed(console_base + UART_UCR1); + regs[1] = readl_relaxed(console_base + UART_UCR2); + regs[2] = readl_relaxed(console_base + UART_UCR3); + regs[3] = readl_relaxed(console_base + UART_UCR4); + regs[4] = readl_relaxed(console_base + UART_UFCR); + regs[5] = readl_relaxed(console_base + UART_UESC); + regs[6] = readl_relaxed(console_base + UART_UTIM); + regs[7] = readl_relaxed(console_base + UART_UBIR); + regs[8] = readl_relaxed(console_base + UART_UBMR); + regs[9] = readl_relaxed(console_base + UART_UTS); +} + +static void imx6_console_restore(unsigned int *regs) +{ + if (!console_base) + return; + + writel_relaxed(regs[4], console_base + UART_UFCR); + writel_relaxed(regs[5], console_base + UART_UESC); + writel_relaxed(regs[6], console_base + UART_UTIM); + writel_relaxed(regs[7], console_base + UART_UBIR); + writel_relaxed(regs[8], console_base + UART_UBMR); + writel_relaxed(regs[9], console_base + UART_UTS); + writel_relaxed(regs[0], console_base + UART_UCR1); + writel_relaxed(regs[1] | 0x1, console_base + UART_UCR2); + writel_relaxed(regs[2], console_base + UART_UCR3); + writel_relaxed(regs[3], console_base + UART_UCR4); +} + +static void imx6_qspi_save(struct qspi_regs *pregs, int reg_num) +{ + int i; + + if (!qspi_base) + return; + + for (i = 0; i < reg_num; i++) { + if (QSPI_RETRIEVED == pregs[i].valuetype) + pregs[i].value = readl_relaxed(qspi_base + + pregs[i].offset); + } +} + +static void imx6_qspi_restore(struct qspi_regs *pregs, int reg_num) +{ + int i; + + if (!qspi_base) + return; + + for (i = 0; i < reg_num; i++) + writel_relaxed(pregs[i].value, qspi_base + pregs[i].offset); +} + static int imx6q_pm_enter(suspend_state_t state) { + unsigned int console_saved_reg[10] = {0}; + static unsigned int ccm_ccgr4, ccm_ccgr6; + +#ifdef CONFIG_SOC_IMX6SX + if (imx_src_is_m4_enabled()) { + if (imx_gpc_is_m4_sleeping() && imx_mu_is_m4_in_low_freq()) { + imx_gpc_hold_m4_in_sleep(); + imx_mu_enable_m4_irqs_in_gic(true); + } else { + pr_info("M4 is busy, enter WAIT mode instead of STOP!\n"); + imx6_set_lpm(WAIT_UNCLOCKED); + imx6_set_int_mem_clk_lpm(true); + imx_gpc_pre_suspend(false); + /* Zzz ... */ + cpu_do_idle(); + imx_gpc_post_resume(); + imx6_set_lpm(WAIT_CLOCKED); + + return 0; + } + } +#endif switch (state) { case PM_SUSPEND_STANDBY: imx6_set_lpm(STOP_POWER_ON); imx6_set_int_mem_clk_lpm(true); imx_gpc_pre_suspend(false); +#ifdef CONFIG_SOC_IMX6SL if (cpu_is_imx6sl()) imx6sl_set_wait_clk(true); +#endif /* Zzz ... */ cpu_do_idle(); +#ifdef CONFIG_SOC_IMX6SL if (cpu_is_imx6sl()) imx6sl_set_wait_clk(false); +#endif imx_gpc_post_resume(); imx6_set_lpm(WAIT_CLOCKED); break; @@ -405,8 +887,50 @@ static int imx6q_pm_enter(suspend_state_t state) imx6_enable_rbc(true); imx_gpc_pre_suspend(true); imx_anatop_pre_suspend(); + if ((cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) && + imx_gpc_is_mf_mix_off()) + imx6_console_save(console_saved_reg); + if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) { + ccm_ccgr4 = readl_relaxed(ccm_base + CCGR4); + ccm_ccgr6 = readl_relaxed(ccm_base + CCGR6); + /* + * i.MX6SX RDC needs PCIe and eim clk to be enabled + * if Mega/Fast off, it is better to check cpu type + * and whether Mega/Fast is off in this suspend flow, + * but we need to add cpu type check for 3 places which + * will increase code size, so here we just do it + * for all cases, as when STOP mode is entered, CCM + * hardware will gate all clocks, so it will NOT impact + * any function or power. + */ + writel_relaxed(ccm_ccgr4 | (0x3 << 0), ccm_base + + CCGR4); + writel_relaxed(ccm_ccgr6 | (0x3 << 10), ccm_base + + CCGR6); + memcpy(ocram_saved_in_ddr, ocram_base, ocram_size); + imx6_console_save(console_saved_reg); + if (imx_src_is_m4_enabled()) + imx6_qspi_save(qspi_regs_imx6sx, + sizeof(qspi_regs_imx6sx) / + sizeof(struct qspi_regs)); + } + /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish); + + if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) { + writel_relaxed(ccm_ccgr4, ccm_base + CCGR4); + writel_relaxed(ccm_ccgr6, ccm_base + CCGR6); + memcpy(ocram_base, ocram_saved_in_ddr, ocram_size); + imx6_console_restore(console_saved_reg); + if (imx_src_is_m4_enabled()) + imx6_qspi_restore(qspi_regs_imx6sx, + sizeof(qspi_regs_imx6sx) / + sizeof(struct qspi_regs)); + } + if ((cpu_is_imx6ull() || cpu_is_imx6ulz() || cpu_is_imx6sll()) && + imx_gpc_is_mf_mix_off()) + imx6_console_restore(console_saved_reg); if (cpu_is_imx6q() || cpu_is_imx6dl()) imx_smp_prepare(); imx_anatop_post_resume(); @@ -420,6 +944,13 @@ static int imx6q_pm_enter(suspend_state_t state) return -EINVAL; } +#ifdef CONFIG_SOC_IMX6SX + if (imx_src_is_m4_enabled()) { + imx_mu_enable_m4_irqs_in_gic(false); + imx_gpc_release_m4_in_sleep(); + } +#endif + return 0; } @@ -433,41 +964,113 @@ static const struct platform_suspend_ops imx6q_pm_ops = { .valid = imx6q_pm_valid, }; -static int __init imx6_pm_get_base(struct imx6_pm_base *base, - const char *compat) +static int __init imx6_dt_find_lpsram(unsigned long node, const char *uname, + int depth, void *data) { - struct device_node *node; - struct resource res; - int ret = 0; + unsigned long lpram_addr; + const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL); - node = of_find_compatible_node(NULL, NULL, compat); - if (!node) - return -ENODEV; + if (of_flat_dt_match(node, low_power_ocram_match)) { + if (!prop) + return -EINVAL; - ret = of_address_to_resource(node, 0, &res); - if (ret) - goto put_node; + lpram_addr = be32_to_cpup(prop); - base->pbase = res.start; - base->vbase = ioremap(res.start, resource_size(&res)); - if (!base->vbase) - ret = -ENOMEM; + /* We need to create a 1M page table entry. */ + iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000); + iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000); + iram_tlb_phys_addr = lpram_addr; + iram_tlb_base_addr = IMX_IO_P2V(lpram_addr); -put_node: - of_node_put(node); - return ret; + iotable_init(&iram_tlb_io_desc, 1); + } + + return 0; +} + +void __init imx6_pm_map_io(void) +{ + unsigned long i; + + iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); + + /* + * Get the address of IRAM or OCRAM to be used by the low + * power code from the device tree. + */ + WARN_ON(of_scan_flat_dt(imx6_dt_find_lpsram, NULL)); + + /* + * We moved suspend/resume and lowpower idle to TEE, + * But busfreq now still in Linux, this table is still needed + * If we later decide to move busfreq to TEE, we could drop this. + */ + /* Return if no IRAM space is allocated for suspend/resume code. */ + if (!iram_tlb_base_addr) { + pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \ + code. Please ensure device tree has an entry for \ + fsl,lpm-sram.\n"); + return; + } + + /* Set all entries to 0. */ + memset((void *)iram_tlb_base_addr, 0, MX6Q_IRAM_TLB_SIZE); + + /* + * Make sure the IRAM virtual address has a mapping in the IRAM + * page table. + * + * Only use the top 11 bits [31-20] when storing the physical + * address in the page table as only these bits are required + * for 1M mapping. + */ + i = ((iram_tlb_base_addr >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS1 virtual address has a mapping in the + * IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_AIPS1_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_AIPS1_BASE_ADDR & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS2 virtual address has a mapping in the + * IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_AIPS2_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_AIPS2_BASE_ADDR & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS3 virtual address has a mapping + * in the IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_AIPS3_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_AIPS3_BASE_ADDR & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the L2 controller virtual address has a mapping + * in the IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_L2_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_L2_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; } static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) { - phys_addr_t ocram_pbase; - struct device_node *node; - struct platform_device *pdev; struct imx6_cpu_pm_info *pm_info; - struct gen_pool *ocram_pool; - unsigned long ocram_base; + unsigned long iram_paddr; int i, ret = 0; const u32 *mmdc_offset_array; + const u32 *mmdc_io_offset_array; suspend_set_ops(&imx6q_pm_ops); @@ -476,41 +1079,27 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) return -EINVAL; } - node = of_find_compatible_node(NULL, NULL, "mmio-sram"); - if (!node) { - pr_warn("%s: failed to find ocram node!\n", __func__); - return -ENODEV; - } + if (psci_ops.cpu_suspend) + return ret; - 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 = gen_pool_get(&pdev->dev, NULL); - if (!ocram_pool) { - pr_warn("%s: ocram pool unavailable!\n", __func__); - ret = -ENODEV; - goto put_device; - } - - ocram_base = gen_pool_alloc(ocram_pool, MX6Q_SUSPEND_OCRAM_SIZE); - if (!ocram_base) { - pr_warn("%s: unable to alloc ocram!\n", __func__); - ret = -ENOMEM; - goto put_device; - } + /* + * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, + * The lower 8K is not used, so use the lower 8K for IRAM code and + * pm_info. + * + */ + iram_paddr = iram_tlb_phys_addr + MX6_SUSPEND_IRAM_ADDR_OFFSET; - ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base); + /* Make sure iram_paddr is 8 byte aligned. */ + if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1)) + iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN); - suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, - MX6Q_SUSPEND_OCRAM_SIZE, false); + /* Get the virtual address of the suspend code. */ + suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr); memset(suspend_ocram_base, 0, sizeof(*pm_info)); pm_info = suspend_ocram_base; - pm_info->pbase = ocram_pbase; + pm_info->pbase = iram_paddr; pm_info->resume_addr = __pa_symbol(v7_cpu_resume); pm_info->pm_info_size = sizeof(*pm_info); @@ -518,73 +1107,125 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) * ccm physical address is not used by asm code currently, * so get ccm virtual address directly. */ - pm_info->ccm_base.vbase = ccm_base; + pm_info->ccm_base.pbase = MX6Q_CCM_BASE_ADDR; + pm_info->ccm_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); - ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat); - if (ret) { - pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret); - goto put_device; - } + pm_info->mmdc0_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; + pm_info->mmdc0_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); - ret = imx6_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; - } + pm_info->mmdc1_base.pbase = MX6Q_MMDC_P1_BASE_ADDR; + pm_info->mmdc1_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_MMDC_P1_BASE_ADDR); - ret = imx6_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; - } + pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; + pm_info->src_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); - ret = imx6_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; - } + pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; + pm_info->iomuxc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); - if (socdata->pl310_compat) { - ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat); - if (ret) { - pr_warn("%s: failed to get pl310-cache base %d!\n", - __func__, ret); - goto pl310_cache_map_failed; - } - } + pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; + pm_info->gpc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); + + pm_info->l2_base.pbase = MX6Q_L2_BASE_ADDR; + pm_info->l2_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_L2_BASE_ADDR); + + pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; + pm_info->anatop_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); pm_info->ddr_type = imx_mmdc_get_ddr_type(); pm_info->mmdc_io_num = socdata->mmdc_io_num; - mmdc_offset_array = socdata->mmdc_io_offset; + mmdc_io_offset_array = socdata->mmdc_io_offset; + pm_info->mmdc_num = socdata->mmdc_num; + mmdc_offset_array = socdata->mmdc_offset; for (i = 0; i < pm_info->mmdc_io_num; i++) { pm_info->mmdc_io_val[i][0] = - mmdc_offset_array[i]; + mmdc_io_offset_array[i]; pm_info->mmdc_io_val[i][1] = readl_relaxed(pm_info->iomuxc_base.vbase + + mmdc_io_offset_array[i]); + pm_info->mmdc_io_val[i][2] = 0; + } + + /* i.MX6SLL has no DRAM RESET pin */ + if (cpu_is_imx6sll()) { + pm_info->mmdc_io_val[pm_info->mmdc_io_num - 2][2] = 0x1000; + pm_info->mmdc_io_val[pm_info->mmdc_io_num - 1][2] = 0x1000; + } else { + if (pm_info->ddr_type == IMX_DDR_TYPE_LPDDR2) { + /* for LPDDR2, CKE0/1 and RESET pin need special setting */ + pm_info->mmdc_io_val[pm_info->mmdc_io_num - 3][2] = 0x1000; + pm_info->mmdc_io_val[pm_info->mmdc_io_num - 2][2] = 0x1000; + pm_info->mmdc_io_val[pm_info->mmdc_io_num - 1][2] = 0x80000; + } + } + + /* initialize MMDC settings */ + for (i = 0; i < pm_info->mmdc_num; i++) { + pm_info->mmdc_val[i][0] = + mmdc_offset_array[i]; + pm_info->mmdc_val[i][1] = + readl_relaxed(pm_info->mmdc0_base.vbase + mmdc_offset_array[i]); } + if (cpu_is_imx6sll() && pm_info->ddr_type == IMX_MMDC_DDR_TYPE_LPDDR3) { + pm_info->mmdc_val[0][1] = 0x8000; + pm_info->mmdc_val[2][1] = 0xa1390003; + pm_info->mmdc_val[3][1] = 0x400000; + pm_info->mmdc_val[4][1] = 0x800; + pm_info->mmdc_val[13][1] = 0x800; + pm_info->mmdc_val[14][1] = 0x20052; + pm_info->mmdc_val[20][1] = 0x201718; + pm_info->mmdc_val[21][1] = 0x8000; + pm_info->mmdc_val[28][1] = 0xa1310003; + } + + /* need to overwrite the value for some mmdc registers */ + if ((cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz()) && + pm_info->ddr_type != IMX_DDR_TYPE_LPDDR2) { + pm_info->mmdc_val[20][1] = (pm_info->mmdc_val[20][1] + & 0xffff0000) | 0x0202; + pm_info->mmdc_val[23][1] = 0x8033; + } + + if (cpu_is_imx6sx() && + pm_info->ddr_type == IMX_DDR_TYPE_LPDDR2) { + pm_info->mmdc_val[0][1] = 0x8000; + pm_info->mmdc_val[2][1] = 0xa1390003; + pm_info->mmdc_val[3][1] = 0x380000; + pm_info->mmdc_val[4][1] = 0x800; + pm_info->mmdc_val[18][1] = 0x800; + pm_info->mmdc_val[20][1] = 0x20024; + pm_info->mmdc_val[23][1] = 0x1748; + pm_info->mmdc_val[32][1] = 0xa1310003; + } + + if ((cpu_is_imx6ul() || cpu_is_imx6ull() || cpu_is_imx6ulz()) && + pm_info->ddr_type == IMX_DDR_TYPE_LPDDR2) { + pm_info->mmdc_val[0][1] = 0x8000; + pm_info->mmdc_val[2][1] = 0xa1390003; + pm_info->mmdc_val[3][1] = 0x470000; + pm_info->mmdc_val[4][1] = 0x800; + pm_info->mmdc_val[13][1] = 0x800; + pm_info->mmdc_val[14][1] = 0x20012; + pm_info->mmdc_val[20][1] = 0x1748; + pm_info->mmdc_val[21][1] = 0x8000; + pm_info->mmdc_val[28][1] = 0xa1310003; + } + imx6_suspend_in_ocram_fn = fncpy( suspend_ocram_base + sizeof(*pm_info), &imx6_suspend, MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); - goto put_device; - -pl310_cache_map_failed: - iounmap(pm_info->gpc_base.vbase); -gpc_map_failed: - iounmap(pm_info->iomuxc_base.vbase); -iomuxc_map_failed: - iounmap(pm_info->src_base.vbase); -src_map_failed: - iounmap(pm_info->mmdc_base.vbase); -put_device: - put_device(&pdev->dev); -put_node: - of_node_put(node); - return ret; } @@ -616,28 +1257,6 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata IMX6Q_GPR1_GINT); } -static void imx6_pm_stby_poweroff(void) -{ - imx6_set_lpm(STOP_POWER_OFF); - imx6q_suspend_finish(0); - - mdelay(1000); - - pr_emerg("Unable to poweroff system\n"); -} - -static int imx6_pm_stby_poweroff_probe(void) -{ - if (pm_power_off) { - pr_warn("%s: pm_power_off already claimed %p %ps!\n", - __func__, pm_power_off, pm_power_off); - return -EBUSY; - } - - pm_power_off = imx6_pm_stby_poweroff; - return 0; -} - void __init imx6_pm_ccm_init(const char *ccm_compat) { struct device_node *np; @@ -654,14 +1273,14 @@ void __init imx6_pm_ccm_init(const char *ccm_compat) val = readl_relaxed(ccm_base + CLPCR); val &= ~BM_CLPCR_LPM; writel_relaxed(val, ccm_base + CLPCR); - - if (of_property_read_bool(np, "fsl,pmic-stby-poweroff")) - imx6_pm_stby_poweroff_probe(); } void __init imx6q_pm_init(void) { - imx6_pm_common_init(&imx6q_pm_data); + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx6_pm_common_init(&imx6q_lpddr2_pm_data); + else + imx6_pm_common_init(&imx6q_pm_data); } void __init imx6dl_pm_init(void) @@ -671,25 +1290,96 @@ void __init imx6dl_pm_init(void) void __init imx6sl_pm_init(void) { + struct device_node *np; struct regmap *gpr; - if (cpu_is_imx6sl()) { - imx6_pm_common_init(&imx6sl_pm_data); - } else { + if (cpu_is_imx6sll()) { imx6_pm_common_init(&imx6sll_pm_data); + np = of_find_node_by_path( + "/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000"); + if (np) + console_base = of_iomap(np, 0); + /* i.MX6SLL has bus auto clock gating function */ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); if (!IS_ERR(gpr)) regmap_update_bits(gpr, IOMUXC_GPR5, - IMX6SLL_GPR5_AFCG_X_BYPASS_MASK, 0); + IOMUXC_GPR5_CLOCK_AFCG_X_BYPASS_MASK, 0); + return; } + + imx6_pm_common_init(&imx6sl_pm_data); } void __init imx6sx_pm_init(void) { - imx6_pm_common_init(&imx6sx_pm_data); + struct device_node *np; + struct resource res; + + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx6_pm_common_init(&imx6sx_lpddr2_pm_data); + else + imx6_pm_common_init(&imx6sx_pm_data); + if (imx_get_soc_revision() < IMX_CHIP_REVISION_1_2) { + /* + * As there is a 16K OCRAM(start from 0x8f8000) + * dedicated for low power function on i.MX6SX, + * but ROM did NOT do the ocram address change + * accordingly, so we need to add a data patch + * to workaround this issue, otherwise, system + * will fail to resume from DSM mode. TO1.2 fixes + * this issue. + */ + romcp = syscon_regmap_lookup_by_compatible( + "fsl,imx6sx-romcp"); + if (IS_ERR(romcp)) { + pr_err("failed to find fsl,imx6sx-romcp regmap\n"); + return; + } + regmap_write(romcp, ROMC_ROMPATCH0D, iram_tlb_phys_addr); + regmap_update_bits(romcp, ROMC_ROMPATCHCNTL, + BM_ROMPATCHCNTL_0D, BM_ROMPATCHCNTL_0D); + regmap_update_bits(romcp, ROMC_ROMPATCHENL, + BM_ROMPATCHENL_0D, BM_ROMPATCHENL_0D); + regmap_write(romcp, ROMC_ROMPATCH0A, + ROM_ADDR_FOR_INTERNAL_RAM_BASE); + regmap_update_bits(romcp, ROMC_ROMPATCHCNTL, + BM_ROMPATCHCNTL_DIS, ~BM_ROMPATCHCNTL_DIS); + } + + np = of_find_compatible_node(NULL, NULL, "fsl,mega-fast-sram"); + ocram_base = of_iomap(np, 0); + WARN_ON(!ocram_base); + WARN_ON(of_address_to_resource(np, 0, &res)); + ocram_size = resource_size(&res); + ocram_saved_in_ddr = kzalloc(ocram_size, GFP_KERNEL); + WARN_ON(!ocram_saved_in_ddr); + + np = of_find_node_by_path( + "/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000"); + if (np) + console_base = of_iomap(np, 0); + if (imx_src_is_m4_enabled()) { + np = of_find_compatible_node(NULL, NULL, + "fsl,imx6sx-qspi-m4-restore"); + if (np) + qspi_base = of_iomap(np, 0); + WARN_ON(!qspi_base); + } } void __init imx6ul_pm_init(void) { - imx6_pm_common_init(&imx6ul_pm_data); + struct device_node *np; + + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx6_pm_common_init(&imx6ul_lpddr2_pm_data); + else + imx6_pm_common_init(&imx6ul_pm_data); + + if (cpu_is_imx6ull() || cpu_is_imx6ulz()) { + np = of_find_node_by_path( + "/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000"); + if (np) + console_base = of_iomap(np, 0); + } } diff --git a/arch/arm/mach-imx/pm-imx7.c b/arch/arm/mach-imx/pm-imx7.c new file mode 100644 index 000000000000..e59cbee6dfc2 --- /dev/null +++ b/arch/arm/mach-imx/pm-imx7.c @@ -0,0 +1,1230 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * 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/busfreq-imx.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_fdt.h> +#include <linux/of_irq.h> +#include <linux/psci.h> +#include <linux/slab.h> +#include <linux/suspend.h> +#include <linux/genalloc.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/imx7-iomuxc-gpr.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> +#include <linux/regmap.h> +#include <linux/suspend.h> +#include <asm/cacheflush.h> +#include <asm/fncpy.h> +#include <asm/mach/map.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> +#include <asm/tlb.h> + +#include <uapi/linux/psci.h> + +#include "common.h" +#include "hardware.h" +#include "cpuidle.h" + +#define MX7_SUSPEND_OCRAM_SIZE 0x1000 +#define MX7_MAX_DDRC_NUM 32 +#define MX7_MAX_DDRC_PHY_NUM 16 + +#define MX7_SUSPEND_IRAM_ADDR_OFFSET 0 +#define READ_DATA_FROM_HARDWARE 0 + +#define UART_UCR1 0x80 +#define UART_UCR2 0x84 +#define UART_UCR3 0x88 +#define UART_UCR4 0x8c +#define UART_UFCR 0x90 +#define UART_UESC 0x9c +#define UART_UTIM 0xa0 +#define UART_UBIR 0xa4 +#define UART_UBMR 0xa8 +#define UART_UBRC 0xac +#define UART_UTS 0xb4 + +#define MAX_IOMUXC_GPR 23 +#define MAX_UART_IO 4 +#define MAX_CCM_LPCG 167 +#define MAX_GPT 3 +#define MAX_GPIO_ROW 7 +#define MAX_GPIO_COL 8 + +#define UART_RX_IO 0x128 +#define UART_RX_PAD 0x398 +#define UART_TX_IO 0x12c +#define UART_TX_PAD 0x39c + +#define GPT_CR 0x0 +#define GPT_PR 0x4 +#define GPT_IR 0xc + +#define CCM_LPCG_START 0x4040 +#define CCM_LPCG_STEP 0x10 +#define CCM_EIM_LPCG 0x4160 +#define CCM_PXP_LPCG 0x44c0 +#define CCM_PCIE_LPCG 0x4600 + +#define BM_CCM_ROOT_POST_PODF 0x3f +#define BM_CCM_ROOT_PRE_PODF 0x70000 +#define BM_CCM_ROOT_MUX 0x7000000 +#define BM_CCM_ROOT_ENABLE 0x10000000 + +#define SYS_COUNTER_CNTSR 0x4 +#define BM_SYS_COUNTER_CNTSR_FCR1 0x200 +#define BM_SYS_COUNTER_CNTSR_FCR0 0x100 +#define BM_SYS_COUNTER_CNTCR_FCR1 0x200 +#define BM_SYS_COUNTER_CNTCR_FCR0 0x100 + +#define PFD_A_OFFSET 0xc0 +#define PFD_B_OFFSET 0xd0 + +#define PLL_ARM_OFFSET 0x60 +#define PLL_DDR_OFFSET 0x70 +#define PLL_DDR_SS_OFFSET 0x80 +#define PLL_DDR_NUM_OFFSET 0x90 +#define PLL_DDR_DENOM_OFFSET 0xa0 +#define PLL_480_OFFSET 0xb0 +#define PLL_ENET_OFFSET 0xe0 +#define PLL_AUDIO_OFFSET 0xf0 +#define PLL_AUDIO_SS_OFFSET 0x100 +#define PLL_AUDIO_NUM_OFFSET 0x110 +#define PLL_AUDIO_DENOM_OFFSET 0x120 +#define PLL_VIDEO_OFFSET 0x130 +#define PLL_VIDEO_SS_OFFSET 0x140 +#define PLL_VIDEO_NUM_OFFSET 0x150 +#define PLL_VIDEO_DENOM_OFFSET 0x160 + +#define REG_SET 0x4 +#define REG_CLR 0x8 + +#define GPIO_DR 0x0 +#define GPIO_GDIR 0x4 +#define GPIO_ICR1 0xc +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_EDGE 0x1c + +#define M4RCR 0x0C +#define M4_SP_OFF 0x00 +#define M4_PC_OFF 0x04 +#define M4_RCR_HALT 0xAB +#define M4_RCR_GO 0xAA +#define M4_OCRAMS_RESERVED_SIZE 0xc + +extern unsigned long iram_tlb_base_addr; +extern unsigned long iram_tlb_phys_addr; + +static unsigned int *ocram_saved_in_ddr; +static void __iomem *ocram_base; +static unsigned int ocram_size; +static unsigned int *lpm_ocram_saved_in_ddr; +static void __iomem *lpm_ocram_base; + +static unsigned int *lpm_m4tcm_saved_in_ddr; +static void __iomem *lpm_m4tcm_base; +static void __iomem *m4_bootrom_base; + +static unsigned int lpm_ocram_size; +static void __iomem *ccm_base; +static void __iomem *lpsr_base; +static void __iomem *console_base; +static void __iomem *suspend_ocram_base; +static void __iomem *iomuxc_base; +static void __iomem *gpt1_base; +static void __iomem *system_counter_ctrl_base; +static void __iomem *system_counter_cmp_base; +static void __iomem *gpio1_base; +static void (*imx7_suspend_in_ocram_fn)(void __iomem *ocram_vbase); +struct imx7_cpu_pm_info *pm_info; +static bool lpsr_enabled; +static u32 iomuxc_gpr[MAX_IOMUXC_GPR]; +static u32 uart1_io[MAX_UART_IO]; +static u32 ccm_lpcg[MAX_CCM_LPCG]; +static u32 ccm_root[][2] = { + {0x8000, 0}, {0x8080, 0}, {0x8100, 0}, {0x8800, 0}, + {0x8880, 0}, {0x8900, 0}, {0x8980, 0}, {0x9000, 0}, + {0x9800, 0}, {0x9880, 0}, {0xa000, 0}, {0xa080, 0}, + {0xa100, 0}, {0xa180, 0}, {0xa200, 0}, {0xa280, 0}, + {0xa300, 0}, {0xa380, 0}, {0xa400, 0}, {0xa480, 0}, + {0xa500, 0}, {0xa580, 0}, {0xa600, 0}, {0xa680, 0}, + {0xa700, 0}, {0xa780, 0}, {0xa800, 0}, {0xa880, 0}, + {0xa900, 0}, {0xa980, 0}, {0xaa00, 0}, {0xaa80, 0}, + {0xab00, 0}, {0xab80, 0}, {0xac00, 0}, {0xac80, 0}, + {0xad00, 0}, {0xad80, 0}, {0xae00, 0}, {0xae80, 0}, + {0xaf00, 0}, {0xaf80, 0}, {0xb000, 0}, {0xb080, 0}, + {0xb100, 0}, {0xb180, 0}, {0xb200, 0}, {0xb280, 0}, + {0xb300, 0}, {0xb380, 0}, {0xb400, 0}, {0xb480, 0}, + {0xb500, 0}, {0xb580, 0}, {0xb600, 0}, {0xb680, 0}, + {0xb700, 0}, {0xb780, 0}, {0xb800, 0}, {0xb880, 0}, + {0xb900, 0}, {0xb980, 0}, {0xba00, 0}, {0xba80, 0}, + {0xbb00, 0}, {0xbb80, 0}, {0xbc00, 0}, {0xbc80, 0}, + {0xbd00, 0}, {0xbd80, 0}, {0xbe00, 0}, +}; +static u32 pfd_a, pfd_b; +static u32 pll[15]; +static u32 gpt1_regs[MAX_GPT]; +static u32 sys_ctrl_reg, sys_cmp_reg; +static u32 gpio_reg[MAX_GPIO_ROW][MAX_GPIO_COL]; +/* + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx7_suspend code + * PM_INFO structure(imx7_cpu_pm_info) + * ======================== low address ======================= + */ + +struct imx7_pm_base { + phys_addr_t pbase; + void __iomem *vbase; +}; + +struct imx7_pm_socdata { + u32 ddr_type; + const char *ddrc_compat; + const char *src_compat; + const char *iomuxc_compat; + const char *gpc_compat; + const u32 ddrc_num; + const u32 (*ddrc_offset)[2]; + const u32 ddrc_phy_num; + const u32 (*ddrc_phy_offset)[2]; +}; + +static const u32 imx7d_ddrc_lpddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x1a0, READ_DATA_FROM_HARDWARE }, + { 0x1a4, READ_DATA_FROM_HARDWARE }, + { 0x1a8, READ_DATA_FROM_HARDWARE }, + { 0x64, READ_DATA_FROM_HARDWARE }, + { 0xd0, READ_DATA_FROM_HARDWARE }, + { 0xdc, READ_DATA_FROM_HARDWARE }, + { 0xe0, READ_DATA_FROM_HARDWARE }, + { 0xe4, READ_DATA_FROM_HARDWARE }, + { 0xf4, READ_DATA_FROM_HARDWARE }, + { 0x100, READ_DATA_FROM_HARDWARE }, + { 0x104, READ_DATA_FROM_HARDWARE }, + { 0x108, READ_DATA_FROM_HARDWARE }, + { 0x10c, READ_DATA_FROM_HARDWARE }, + { 0x110, READ_DATA_FROM_HARDWARE }, + { 0x114, READ_DATA_FROM_HARDWARE }, + { 0x118, READ_DATA_FROM_HARDWARE }, + { 0x120, READ_DATA_FROM_HARDWARE }, + { 0x11c, READ_DATA_FROM_HARDWARE }, + { 0x180, READ_DATA_FROM_HARDWARE }, + { 0x184, READ_DATA_FROM_HARDWARE }, + { 0x190, READ_DATA_FROM_HARDWARE }, + { 0x194, READ_DATA_FROM_HARDWARE }, + { 0x200, READ_DATA_FROM_HARDWARE }, + { 0x204, READ_DATA_FROM_HARDWARE }, + { 0x210, READ_DATA_FROM_HARDWARE }, + { 0x214, READ_DATA_FROM_HARDWARE }, + { 0x218, READ_DATA_FROM_HARDWARE }, + { 0x240, READ_DATA_FROM_HARDWARE }, + { 0x244, READ_DATA_FROM_HARDWARE }, +}; + +static const u32 imx7d_ddrc_phy_lpddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x4, READ_DATA_FROM_HARDWARE }, + { 0x8, READ_DATA_FROM_HARDWARE }, + { 0x10, READ_DATA_FROM_HARDWARE }, + { 0xb0, READ_DATA_FROM_HARDWARE }, + { 0x1c, READ_DATA_FROM_HARDWARE }, + { 0x9c, READ_DATA_FROM_HARDWARE }, + { 0x7c, READ_DATA_FROM_HARDWARE }, + { 0x80, READ_DATA_FROM_HARDWARE }, + { 0x84, READ_DATA_FROM_HARDWARE }, + { 0x88, READ_DATA_FROM_HARDWARE }, + { 0x6c, READ_DATA_FROM_HARDWARE }, + { 0x20, READ_DATA_FROM_HARDWARE }, + { 0x30, READ_DATA_FROM_HARDWARE }, + { 0x50, 0x01000008 }, + { 0x50, 0x00000008 }, + { 0xc0, 0x0e487304 }, + { 0xc0, 0x0e4c7304 }, + { 0xc0, 0x0e4c7306 }, + { 0xc0, 0x0e487304 }, +}; + +static const u32 imx7d_ddrc_ddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x1a0, READ_DATA_FROM_HARDWARE }, + { 0x1a4, READ_DATA_FROM_HARDWARE }, + { 0x1a8, READ_DATA_FROM_HARDWARE }, + { 0x64, READ_DATA_FROM_HARDWARE }, + { 0x490, READ_DATA_FROM_HARDWARE }, + { 0xd0, READ_DATA_FROM_HARDWARE }, + { 0xd4, READ_DATA_FROM_HARDWARE }, + { 0xdc, READ_DATA_FROM_HARDWARE }, + { 0xe0, READ_DATA_FROM_HARDWARE }, + { 0xe4, READ_DATA_FROM_HARDWARE }, + { 0xf4, READ_DATA_FROM_HARDWARE }, + { 0x100, READ_DATA_FROM_HARDWARE }, + { 0x104, READ_DATA_FROM_HARDWARE }, + { 0x108, READ_DATA_FROM_HARDWARE }, + { 0x10c, READ_DATA_FROM_HARDWARE }, + { 0x110, READ_DATA_FROM_HARDWARE }, + { 0x114, READ_DATA_FROM_HARDWARE }, + { 0x120, READ_DATA_FROM_HARDWARE }, + { 0x180, READ_DATA_FROM_HARDWARE }, + { 0x190, READ_DATA_FROM_HARDWARE }, + { 0x194, READ_DATA_FROM_HARDWARE }, + { 0x200, READ_DATA_FROM_HARDWARE }, + { 0x204, READ_DATA_FROM_HARDWARE }, + { 0x210, READ_DATA_FROM_HARDWARE }, + { 0x214, READ_DATA_FROM_HARDWARE }, + { 0x218, READ_DATA_FROM_HARDWARE }, + { 0x240, READ_DATA_FROM_HARDWARE }, + { 0x244, READ_DATA_FROM_HARDWARE }, +}; + +static const u32 imx7d_ddrc_phy_ddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x4, READ_DATA_FROM_HARDWARE }, + { 0x10, READ_DATA_FROM_HARDWARE }, + { 0xb0, READ_DATA_FROM_HARDWARE }, + { 0x9c, READ_DATA_FROM_HARDWARE }, + { 0x7c, READ_DATA_FROM_HARDWARE }, + { 0x80, READ_DATA_FROM_HARDWARE }, + { 0x84, READ_DATA_FROM_HARDWARE }, + { 0x88, READ_DATA_FROM_HARDWARE }, + { 0x6c, READ_DATA_FROM_HARDWARE }, + { 0x20, READ_DATA_FROM_HARDWARE }, + { 0x30, READ_DATA_FROM_HARDWARE }, + { 0x50, 0x01000010 }, + { 0x50, 0x00000010 }, + { 0xc0, 0x0e407304 }, + { 0xc0, 0x0e447304 }, + { 0xc0, 0x0e447306 }, + { 0xc0, 0x0e407304 }, +}; + +static const struct imx7_pm_socdata imx7d_pm_data_lpddr3 __initconst = { + .ddrc_compat = "fsl,imx7d-ddrc", + .src_compat = "fsl,imx7d-src", + .iomuxc_compat = "fsl,imx7d-iomuxc", + .gpc_compat = "fsl,imx7d-gpc", + .ddrc_num = ARRAY_SIZE(imx7d_ddrc_lpddr3_setting), + .ddrc_offset = imx7d_ddrc_lpddr3_setting, + .ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_lpddr3_setting), + .ddrc_phy_offset = imx7d_ddrc_phy_lpddr3_setting, +}; + +static const struct imx7_pm_socdata imx7d_pm_data_ddr3 __initconst = { + .ddrc_compat = "fsl,imx7d-ddrc", + .src_compat = "fsl,imx7d-src", + .iomuxc_compat = "fsl,imx7d-iomuxc", + .gpc_compat = "fsl,imx7d-gpc", + .ddrc_num = ARRAY_SIZE(imx7d_ddrc_ddr3_setting), + .ddrc_offset = imx7d_ddrc_ddr3_setting, + .ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_ddr3_setting), + .ddrc_phy_offset = imx7d_ddrc_phy_ddr3_setting, +}; + +/* + * This structure is for passing necessary data for low level ocram + * suspend code(arch/arm/mach-imx/suspend-imx7.S), if this struct + * definition is changed, the offset definition in + * arch/arm/mach-imx/suspend-imx7.S must be also changed accordingly, + * otherwise, the suspend to ocram function will be broken! + */ +struct imx7_cpu_pm_info { + u32 m4_reserve0; + u32 m4_reserve1; + u32 m4_reserve2; + phys_addr_t pbase; /* The physical address of pm_info. */ + phys_addr_t resume_addr; /* The physical resume address for asm code */ + u32 ddr_type; + u32 pm_info_size; /* Size of pm_info. */ + struct imx7_pm_base ddrc_base; + struct imx7_pm_base ddrc_phy_base; + struct imx7_pm_base src_base; + struct imx7_pm_base iomuxc_gpr_base; + struct imx7_pm_base ccm_base; + struct imx7_pm_base gpc_base; + struct imx7_pm_base snvs_base; + struct imx7_pm_base anatop_base; + struct imx7_pm_base lpsr_base; + struct imx7_pm_base gic_base; + u32 ttbr1; /* Store TTBR1 */ + u32 ddrc_num; /* Number of DDRC which need saved/restored. */ + u32 ddrc_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */ + u32 ddrc_phy_num; /* Number of DDRC which need saved/restored. */ + u32 ddrc_phy_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */ +} __aligned(8); + +static struct map_desc imx7_pm_io_desc[] __initdata = { + imx_map_entry(MX7D, AIPS1, MT_DEVICE), + imx_map_entry(MX7D, AIPS2, MT_DEVICE), + imx_map_entry(MX7D, AIPS3, MT_DEVICE), +}; + +static const char * const low_power_ocram_match[] __initconst = { + "fsl,lpm-sram", + NULL +}; + +static void imx7_gpio_save(void) +{ + u32 i; + + for (i = 0; i < 7; i++) { + gpio_reg[i][0] = readl_relaxed(gpio1_base + + (i << 16) + GPIO_DR); + gpio_reg[i][1] = readl_relaxed(gpio1_base + + (i << 16) + GPIO_GDIR); + gpio_reg[i][3] = readl_relaxed(gpio1_base + + (i << 16) + GPIO_ICR1); + gpio_reg[i][4] = readl_relaxed(gpio1_base + + (i << 16) + GPIO_ICR2); + gpio_reg[i][5] = readl_relaxed(gpio1_base + + (i << 16) + GPIO_IMR); + gpio_reg[i][7] = readl_relaxed(gpio1_base + + (i << 16) + GPIO_EDGE); + } +} + +static void imx7_gpio_restore(void) +{ + u32 i, val; + + for (i = 0; i < 7; i++) { + writel_relaxed(gpio_reg[i][1], gpio1_base + + (i << 16) + GPIO_GDIR); + writel_relaxed(gpio_reg[i][3], gpio1_base + + (i << 16) + GPIO_ICR1); + writel_relaxed(gpio_reg[i][4], gpio1_base + + (i << 16) + GPIO_ICR2); + writel_relaxed(gpio_reg[i][5], gpio1_base + + (i << 16) + GPIO_IMR); + writel_relaxed(gpio_reg[i][7], gpio1_base + + (i << 16) + GPIO_EDGE); + /* only restore output gpio value */ + val = readl_relaxed(gpio1_base + (i << 16) + GPIO_DR) | + (gpio_reg[i][0] & gpio_reg[i][1]); + writel_relaxed(val, gpio1_base + (i << 16) + GPIO_DR); + } +} + +static void imx7_ccm_save(void) +{ + u32 i; + + for (i = 0; i < MAX_CCM_LPCG; i++) + ccm_lpcg[i] = readl_relaxed(pm_info->ccm_base.vbase + + i * CCM_LPCG_STEP + CCM_LPCG_START); + pfd_a = readl_relaxed(pm_info->anatop_base.vbase + PFD_A_OFFSET); + pfd_b = readl_relaxed(pm_info->anatop_base.vbase + PFD_B_OFFSET); + + pll[0] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_ARM_OFFSET); + pll[1] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_DDR_OFFSET); + pll[2] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_DDR_SS_OFFSET); + pll[3] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_DDR_NUM_OFFSET); + pll[4] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_DDR_DENOM_OFFSET); + pll[5] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_480_OFFSET); + pll[6] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_ENET_OFFSET); + pll[7] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_AUDIO_OFFSET); + pll[8] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_AUDIO_SS_OFFSET); + pll[9] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_AUDIO_NUM_OFFSET); + pll[10] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_AUDIO_DENOM_OFFSET); + pll[11] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_VIDEO_OFFSET); + pll[12] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_VIDEO_SS_OFFSET); + pll[13] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_VIDEO_NUM_OFFSET); + pll[14] = readl_relaxed(pm_info->anatop_base.vbase + + PLL_VIDEO_DENOM_OFFSET); + + /* enable all PLLs/PFDs for saving CCM root */ + writel_relaxed(0x1c000070, pm_info->anatop_base.vbase + + PLL_480_OFFSET + 0x8); + writel_relaxed(0x80808080, pm_info->anatop_base.vbase + + PFD_A_OFFSET + 0x8); + writel_relaxed(0x80808080, pm_info->anatop_base.vbase + + PFD_B_OFFSET + 0x8); + writel_relaxed(0x1fc0, pm_info->anatop_base.vbase + + PLL_ENET_OFFSET + 0x4); + writel_relaxed(0x12000, pm_info->anatop_base.vbase + + PLL_AUDIO_OFFSET); + writel_relaxed(0x12000, pm_info->anatop_base.vbase + + PLL_VIDEO_OFFSET); + + for (i = 0; i < sizeof(ccm_root) / 8; i++) + ccm_root[i][1] = readl_relaxed( + pm_info->ccm_base.vbase + ccm_root[i][0]); +} + +static void imx7_ccm_restore(void) +{ + u32 i, val; + + /* enable all PLLs/PFDs for restoring CCM root */ + writel_relaxed(0x1c000070, pm_info->anatop_base.vbase + + PLL_480_OFFSET + REG_CLR); + writel_relaxed(0x80808080, pm_info->anatop_base.vbase + + PFD_A_OFFSET + REG_CLR); + writel_relaxed(0x80808080, pm_info->anatop_base.vbase + + PFD_B_OFFSET + REG_CLR); + writel_relaxed(0x1fc0, pm_info->anatop_base.vbase + + PLL_ENET_OFFSET + REG_SET); + writel_relaxed(0x12000, pm_info->anatop_base.vbase + + PLL_AUDIO_OFFSET); + writel_relaxed(0x12000, pm_info->anatop_base.vbase + + PLL_VIDEO_OFFSET); + + for (i = 0; i < sizeof(ccm_root) / 8; i++) { + val = readl_relaxed(pm_info->ccm_base.vbase + ccm_root[i][0]); + /* restore post podf */ + val &= ~BM_CCM_ROOT_POST_PODF; + val |= ccm_root[i][1] & BM_CCM_ROOT_POST_PODF; + writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]); + /* resotre pre podf */ + val &= ~BM_CCM_ROOT_PRE_PODF; + val |= ccm_root[i][1] & BM_CCM_ROOT_PRE_PODF; + writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]); + /* restore mux */ + val &= ~BM_CCM_ROOT_MUX; + val |= ccm_root[i][1] & BM_CCM_ROOT_MUX; + writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]); + /* restore enable */ + val &= ~BM_CCM_ROOT_ENABLE; + val |= ccm_root[i][1] & BM_CCM_ROOT_ENABLE; + writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]); + } + + /* restore PLLs */ + writel_relaxed(pll[0], pm_info->anatop_base.vbase + + PLL_ARM_OFFSET); + writel_relaxed(pll[1], pm_info->anatop_base.vbase + + PLL_DDR_OFFSET); + writel_relaxed(pll[2], pm_info->anatop_base.vbase + + PLL_DDR_SS_OFFSET); + writel_relaxed(pll[3], pm_info->anatop_base.vbase + + PLL_DDR_NUM_OFFSET); + writel_relaxed(pll[4], pm_info->anatop_base.vbase + + PLL_DDR_DENOM_OFFSET); + writel_relaxed(pll[5], pm_info->anatop_base.vbase + + PLL_480_OFFSET); + writel_relaxed(pll[6], pm_info->anatop_base.vbase + + PLL_ENET_OFFSET); + writel_relaxed(pll[7], pm_info->anatop_base.vbase + + PLL_AUDIO_OFFSET); + writel_relaxed(pll[8], pm_info->anatop_base.vbase + + PLL_AUDIO_SS_OFFSET); + writel_relaxed(pll[9], pm_info->anatop_base.vbase + + PLL_AUDIO_NUM_OFFSET); + writel_relaxed(pll[10], pm_info->anatop_base.vbase + + PLL_AUDIO_DENOM_OFFSET); + writel_relaxed(pll[11], pm_info->anatop_base.vbase + + PLL_VIDEO_OFFSET); + writel_relaxed(pll[12], pm_info->anatop_base.vbase + + PLL_VIDEO_SS_OFFSET); + writel_relaxed(pll[13], pm_info->anatop_base.vbase + + PLL_VIDEO_NUM_OFFSET); + writel_relaxed(pll[14], pm_info->anatop_base.vbase + + PLL_VIDEO_DENOM_OFFSET); + + for (i = 0; i < MAX_CCM_LPCG; i++) + writel_relaxed(ccm_lpcg[i], pm_info->ccm_base.vbase + + i * CCM_LPCG_STEP + CCM_LPCG_START); + /* restore PFDs */ + writel_relaxed(pfd_a & 0x80808080, + pm_info->anatop_base.vbase + PFD_A_OFFSET + REG_SET); + writel_relaxed(pfd_a, pm_info->anatop_base.vbase + PFD_A_OFFSET); + + writel_relaxed(pfd_b & 0x80808080, + pm_info->anatop_base.vbase + PFD_B_OFFSET + REG_SET); + writel_relaxed(pfd_b, pm_info->anatop_base.vbase + PFD_B_OFFSET); +} + +static void imx7_sys_counter_save(void) +{ + sys_ctrl_reg = readl_relaxed(system_counter_ctrl_base); + sys_cmp_reg = readl_relaxed(system_counter_cmp_base); +} + +static void imx7_sys_counter_restore(void) +{ + writel_relaxed(sys_ctrl_reg, system_counter_ctrl_base); + writel_relaxed(sys_cmp_reg, system_counter_cmp_base); +} + +static void imx7_gpt_save(void) +{ + gpt1_regs[0] = readl_relaxed(gpt1_base + GPT_CR); + gpt1_regs[1] = readl_relaxed(gpt1_base + GPT_PR); + gpt1_regs[2] = readl_relaxed(gpt1_base + GPT_IR); +} + +static void imx7_gpt_restore(void) +{ + writel_relaxed(gpt1_regs[0], gpt1_base + GPT_CR); + writel_relaxed(gpt1_regs[1], gpt1_base + GPT_PR); + writel_relaxed(gpt1_regs[2], gpt1_base + GPT_IR); +} + +static void imx7_iomuxc_gpr_save(void) +{ + u32 i; + + for (i = 0; i < MAX_IOMUXC_GPR; i++) + iomuxc_gpr[i] = readl_relaxed( + pm_info->iomuxc_gpr_base.vbase + i * 4); +} + +static void imx7_iomuxc_gpr_restore(void) +{ + u32 i; + + for (i = 0; i < MAX_IOMUXC_GPR; i++) + writel_relaxed(iomuxc_gpr[i], + pm_info->iomuxc_gpr_base.vbase + i * 4); +} + +static void imx7_console_save(unsigned int *regs) +{ + if (!console_base) + return; + + regs[0] = readl_relaxed(console_base + UART_UCR1); + regs[1] = readl_relaxed(console_base + UART_UCR2); + regs[2] = readl_relaxed(console_base + UART_UCR3); + regs[3] = readl_relaxed(console_base + UART_UCR4); + regs[4] = readl_relaxed(console_base + UART_UFCR); + regs[5] = readl_relaxed(console_base + UART_UESC); + regs[6] = readl_relaxed(console_base + UART_UTIM); + regs[7] = readl_relaxed(console_base + UART_UBIR); + regs[8] = readl_relaxed(console_base + UART_UBMR); + regs[9] = readl_relaxed(console_base + UART_UTS); +} + +static void imx7_console_io_save(void) +{ + /* save uart1 io, driver resume is too late */ + uart1_io[0] = readl_relaxed(iomuxc_base + UART_RX_IO); + uart1_io[1] = readl_relaxed(iomuxc_base + UART_RX_PAD); + uart1_io[2] = readl_relaxed(iomuxc_base + UART_TX_IO); + uart1_io[3] = readl_relaxed(iomuxc_base + UART_TX_PAD); +} + +static void imx7_console_restore(unsigned int *regs) +{ + if (!console_base) + return; + + writel_relaxed(regs[4], console_base + UART_UFCR); + writel_relaxed(regs[5], console_base + UART_UESC); + writel_relaxed(regs[6], console_base + UART_UTIM); + writel_relaxed(regs[7], console_base + UART_UBIR); + writel_relaxed(regs[8], console_base + UART_UBMR); + writel_relaxed(regs[9], console_base + UART_UTS); + writel_relaxed(regs[0], console_base + UART_UCR1); + writel_relaxed(regs[1] | 0x1, console_base + UART_UCR2); + writel_relaxed(regs[2], console_base + UART_UCR3); + writel_relaxed(regs[3], console_base + UART_UCR4); +} + +static void imx7_console_io_restore(void) +{ + /* restore uart1 io */ + writel_relaxed(uart1_io[0], iomuxc_base + UART_RX_IO); + writel_relaxed(uart1_io[1], iomuxc_base + UART_RX_PAD); + writel_relaxed(uart1_io[2], iomuxc_base + UART_TX_IO); + writel_relaxed(uart1_io[3], iomuxc_base + UART_TX_PAD); +} + +#define MX7D_SUSPEND_POWERDWN_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +#define MX7D_SUSPEND_STANDBY_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_STANDBY << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +static int imx7_suspend_finish(unsigned long val) +{ + u32 state; + + if (val == 0) + state = MX7D_SUSPEND_POWERDWN_PARAM; + else + state = MX7D_SUSPEND_STANDBY_PARAM; + + if (psci_ops.cpu_suspend) { + return psci_ops.cpu_suspend(state, __pa(cpu_resume)); + } + + if (!imx7_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(); + imx7_suspend_in_ocram_fn(suspend_ocram_base); + } + + return 0; +} + +static void imx7_pm_set_lpsr_resume_addr(unsigned long addr) +{ + writel_relaxed(addr, pm_info->lpsr_base.vbase); +} + +static int imx7_pm_is_resume_from_lpsr(void) +{ + return readl_relaxed(lpsr_base); +} + +static int imx7_pm_enter(suspend_state_t state) +{ + unsigned int console_saved_reg[10] = {0}; + u32 val; + + if (!iram_tlb_base_addr) { + pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \ + code. Please ensure device tree has an entry for \ + fsl,lpm-sram.\n"); + return -EINVAL; + } + + /* + * arm_arch_timer driver requires system counter to be + * a clock source with CLOCK_SOURCE_SUSPEND_NONSTOP flag + * set, which means hardware system counter needs to keep + * running during suspend, as the base clock for system + * counter is 24MHz which will be disabled in STOP mode, + * so we need to switch system counter's clock to alternate + * (lower) clock, it is based on 32K, from block guide, there + * is no special flow needs to be followed, system counter + * hardware will handle the clock transition. + */ + val = readl_relaxed(system_counter_ctrl_base); + val &= ~BM_SYS_COUNTER_CNTCR_FCR0; + val |= BM_SYS_COUNTER_CNTCR_FCR1; + writel_relaxed(val, system_counter_ctrl_base); + while (!(readl_relaxed(system_counter_ctrl_base + SYS_COUNTER_CNTSR) + & BM_SYS_COUNTER_CNTSR_FCR1)) + ; + + switch (state) { + case PM_SUSPEND_STANDBY: + imx_anatop_pre_suspend(); + imx_gpcv2_pre_suspend(false); + + /* Zzz ... */ + if (psci_ops.cpu_suspend) + cpu_suspend(1, imx7_suspend_finish); + else + imx7_suspend_in_ocram_fn(suspend_ocram_base); + + imx_anatop_post_resume(); + imx_gpcv2_post_resume(); + break; + case PM_SUSPEND_MEM: + imx_anatop_pre_suspend(); + imx_gpcv2_pre_suspend(true); + if (imx_gpcv2_is_mf_mix_off()) { + /* + * per design requirement, EXSC for PCIe/EIM/PXP + * will need clock to recover RDC setting on + * resume, so enable PCIe/EIM LPCG for RDC + * recovery when M/F mix off + */ + writel_relaxed(0x3, pm_info->ccm_base.vbase + + CCM_EIM_LPCG); + writel_relaxed(0x3, pm_info->ccm_base.vbase + + CCM_PXP_LPCG); + writel_relaxed(0x3, pm_info->ccm_base.vbase + + CCM_PCIE_LPCG); + /* stop m4 if mix will also be shutdown */ + if (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()) { + writel(M4_RCR_HALT, + pm_info->src_base.vbase + M4RCR); + imx_gpcv2_enable_wakeup_for_m4(); + } + imx7_console_save(console_saved_reg); + memcpy(ocram_saved_in_ddr, ocram_base, ocram_size); + if (lpsr_enabled) { + imx7_pm_set_lpsr_resume_addr(pm_info->resume_addr); + imx7_console_io_save(); + memcpy(lpm_ocram_saved_in_ddr, lpm_ocram_base, + lpm_ocram_size); + imx7_iomuxc_gpr_save(); + imx7_ccm_save(); + imx7_gpt_save(); + imx7_sys_counter_save(); + imx7_gpio_save(); + } + } + + /* Zzz ... */ + cpu_suspend(0, imx7_suspend_finish); + + if (imx7_pm_is_resume_from_lpsr()) { + imx7_console_io_restore(); + memcpy(lpm_ocram_base, lpm_ocram_saved_in_ddr, + lpm_ocram_size); + imx7_iomuxc_gpr_restore(); + imx7_ccm_restore(); + imx7_gpt_restore(); + imx7_sys_counter_restore(); + imx7_gpio_restore(); + imx7d_enable_rcosc(); + } + if (imx_gpcv2_is_mf_mix_off() || + imx7_pm_is_resume_from_lpsr()) { + writel_relaxed(0x0, pm_info->ccm_base.vbase + + CCM_EIM_LPCG); + writel_relaxed(0x0, pm_info->ccm_base.vbase + + CCM_PXP_LPCG); + writel_relaxed(0x0, pm_info->ccm_base.vbase + + CCM_PCIE_LPCG); + memcpy(ocram_base, ocram_saved_in_ddr, ocram_size); + imx7_console_restore(console_saved_reg); + if (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()) { + imx_gpcv2_disable_wakeup_for_m4(); + /* restore M4 image */ + memcpy(lpm_m4tcm_base, + lpm_m4tcm_saved_in_ddr, SZ_32K); + /* kick m4 to enable */ + writel(M4_RCR_GO, + pm_info->src_base.vbase + M4RCR); + /* offset high bus count for m4 image */ + request_bus_freq(BUS_FREQ_HIGH); + /* restore M4 to run mode */ + imx_mu_set_m4_run_mode(); + /* gpc wakeup */ + } + } + /* clear LPSR resume address */ + imx7_pm_set_lpsr_resume_addr(0); + imx_anatop_post_resume(); + imx_gpcv2_post_resume(); + break; + default: + return -EINVAL; + } + + /* restore system counter's clock to base clock */ + val = readl_relaxed(system_counter_ctrl_base); + val &= ~BM_SYS_COUNTER_CNTCR_FCR1; + val |= BM_SYS_COUNTER_CNTCR_FCR0; + writel_relaxed(val, system_counter_ctrl_base); + while (!(readl_relaxed(system_counter_ctrl_base + SYS_COUNTER_CNTSR) + & BM_SYS_COUNTER_CNTSR_FCR0)) + ; + + return 0; +} + +static int imx7_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM; +} + +static const struct platform_suspend_ops imx7_pm_ops = { + .enter = imx7_pm_enter, + .valid = imx7_pm_valid, +}; + +void __init imx7_pm_set_ccm_base(void __iomem *base) +{ + ccm_base = base; +} + +static struct map_desc iram_tlb_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_1M, + .type = MT_MEMORY_RWX_NONCACHED, +}; + +static int __init imx7_dt_find_lpsram(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned long lpram_addr; + const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL); + + if (of_flat_dt_match(node, low_power_ocram_match)) { + if (!prop) + return -EINVAL; + + lpram_addr = be32_to_cpup(prop); + + /* We need to create a 1M page table entry. */ + iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000); + iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000); + iram_tlb_phys_addr = lpram_addr; + iram_tlb_base_addr = IMX_IO_P2V(lpram_addr); + iotable_init(&iram_tlb_io_desc, 1); + } + + return 0; +} + +void __init imx7_pm_map_io(void) +{ + unsigned long i, j; + + iotable_init(imx7_pm_io_desc, ARRAY_SIZE(imx7_pm_io_desc)); + /* + * Get the address of IRAM or OCRAM to be used by the low + * power code from the device tree. + */ + WARN_ON(of_scan_flat_dt(imx7_dt_find_lpsram, NULL)); + + /* Return if no IRAM space is allocated for suspend/resume code. */ + if (!iram_tlb_base_addr) { + pr_warn("No valid ocram available for suspend/resume!\n"); + return; + } + + /* TODO: Handle M4 in TEE? */ + /* Set all entries to 0 except first 3 words reserved for M4. */ + memset((void *)(iram_tlb_base_addr + M4_OCRAMS_RESERVED_SIZE), + 0, MX7_IRAM_TLB_SIZE - M4_OCRAMS_RESERVED_SIZE); + + /* + * Make sure the IRAM virtual address has a mapping in the IRAM + * page table. + * + * Only use the top 12 bits [31-20] when storing the physical + * address in the page table as only these bits are required + * for 1M mapping. + */ + j = ((iram_tlb_base_addr >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS1 virtual address has a mapping in the + * IRAM page table. + */ + for (i = 0; i < 4; i++) { + j = ((IMX_IO_P2V(MX7D_AIPS1_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7D_AIPS1_BASE_ADDR + i * 0x100000) & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } + + /* + * Make sure the AIPS2 virtual address has a mapping in the + * IRAM page table. + */ + for (i = 0; i < 4; i++) { + j = ((IMX_IO_P2V(MX7D_AIPS2_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7D_AIPS2_BASE_ADDR + i * 0x100000) & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } + + /* + * Make sure the AIPS3 virtual address has a mapping + * in the IRAM page table. + */ + for (i = 0; i < 4; i++) { + j = ((IMX_IO_P2V(MX7D_AIPS3_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7D_AIPS3_BASE_ADDR + i * 0x100000) & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } + + /* + * Make sure the GIC virtual address has a mapping in the + * IRAM page table. + */ + j = ((IMX_IO_P2V(MX7D_GIC_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + (MX7D_GIC_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; +} + +static int __init imx7_suspend_init(const struct imx7_pm_socdata *socdata) +{ + const u32 (*ddrc_offset_array)[2]; + const u32 (*ddrc_phy_offset_array)[2]; + unsigned long iram_paddr; + int i; + + suspend_set_ops(&imx7_pm_ops); + + if (!socdata) { + pr_warn("%s: invalid argument!\n", __func__); + return -EINVAL; + } + + /* + * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, + * The lower 8K is not used, so use the lower 8K for IRAM code and + * pm_info. + * + */ + iram_paddr = iram_tlb_phys_addr + MX7_SUSPEND_IRAM_ADDR_OFFSET; + + /* Make sure iram_paddr is 8 byte aligned. */ + if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1)) + iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN); + + /* Get the virtual address of the suspend code. */ + suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr); + + if (psci_ops.cpu_suspend) { + pm_info = kmalloc(sizeof(*pm_info), GFP_KERNEL); + if (!pm_info) + return -ENOMEM; + } else { + pm_info = suspend_ocram_base; + } + /* pbase points to iram_paddr. */ + pm_info->pbase = iram_paddr; + pm_info->resume_addr = virt_to_phys(ca7_cpu_resume); + pm_info->pm_info_size = sizeof(*pm_info); + + /* + * ccm physical address is not used by asm code currently, + * so get ccm virtual address directly, as we already have + * it from ccm driver. + */ + pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR; + pm_info->ccm_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_CCM_BASE_ADDR); + + pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR; + pm_info->ddrc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_DDRC_BASE_ADDR); + + pm_info->ddrc_phy_base.pbase = MX7D_DDRC_PHY_BASE_ADDR; + pm_info->ddrc_phy_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR); + + pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR; + pm_info->src_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_SRC_BASE_ADDR); + + pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR; + pm_info->iomuxc_gpr_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR); + + pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR; + pm_info->gpc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_GPC_BASE_ADDR); + + pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR; + pm_info->anatop_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR); + + pm_info->snvs_base.pbase = MX7D_SNVS_BASE_ADDR; + pm_info->snvs_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_SNVS_BASE_ADDR); + + pm_info->lpsr_base.pbase = MX7D_LPSR_BASE_ADDR; + lpsr_base = pm_info->lpsr_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_LPSR_BASE_ADDR); + + pm_info->gic_base.pbase = MX7D_GIC_BASE_ADDR; + pm_info->gic_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_GIC_BASE_ADDR); + + pm_info->ddrc_num = socdata->ddrc_num; + ddrc_offset_array = socdata->ddrc_offset; + pm_info->ddrc_phy_num = socdata->ddrc_phy_num; + ddrc_phy_offset_array = socdata->ddrc_phy_offset; + + /* initialize DDRC settings */ + for (i = 0; i < pm_info->ddrc_num; i++) { + pm_info->ddrc_val[i][0] = ddrc_offset_array[i][0]; + if (ddrc_offset_array[i][1] == READ_DATA_FROM_HARDWARE) + pm_info->ddrc_val[i][1] = + readl_relaxed(pm_info->ddrc_base.vbase + + ddrc_offset_array[i][0]); + else + pm_info->ddrc_val[i][1] = ddrc_offset_array[i][1]; + + if (pm_info->ddrc_val[i][0] == 0xd0) + pm_info->ddrc_val[i][1] |= 0xc0000000; + } + + /* initialize DDRC PHY settings */ + for (i = 0; i < pm_info->ddrc_phy_num; i++) { + pm_info->ddrc_phy_val[i][0] = + ddrc_phy_offset_array[i][0]; + if (ddrc_phy_offset_array[i][1] == READ_DATA_FROM_HARDWARE) + pm_info->ddrc_phy_val[i][1] = + readl_relaxed(pm_info->ddrc_phy_base.vbase + + ddrc_phy_offset_array[i][0]); + else + pm_info->ddrc_phy_val[i][1] = + ddrc_phy_offset_array[i][1]; + } + + if (psci_ops.cpu_suspend) + return 0; + + imx7_suspend_in_ocram_fn = fncpy( + suspend_ocram_base + sizeof(*pm_info), + &imx7_suspend, + MX7_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); + + return 0; +} + +static void __init imx7_pm_common_init(const struct imx7_pm_socdata + *socdata) +{ + int ret; + struct regmap *gpr; + + if (IS_ENABLED(CONFIG_SUSPEND)) { + ret = imx7_suspend_init(socdata); + if (ret) + pr_warn("%s: No DDR LPM support with suspend %d!\n", + __func__, ret); + } + + /* + * Force IOMUXC irq pending, so that the interrupt to GPC can be + * used to deassert dsm_request signal when the signal gets + * asserted unexpectedly. + */ + gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_IRQ_MASK, + IMX7D_GPR1_IRQ_MASK); +} + +void __init imx7d_pm_init(void) +{ + struct device_node *np; + struct resource res; + if (imx_src_is_m4_enabled()) { + /* map the 32K of M4 TCM */ + np = of_find_node_by_path( + "/tcml@007f8000"); + if (np) + lpm_m4tcm_base = of_iomap(np, 0); + WARN_ON(!lpm_m4tcm_base); + + /* map the m4 bootrom from dtb */ + np = of_find_node_by_path( + "/soc/sram@00180000"); + if (np) + m4_bootrom_base = of_iomap(np, 0); + WARN_ON(!m4_bootrom_base); + + lpm_m4tcm_saved_in_ddr = kzalloc(SZ_32K, GFP_KERNEL); + WARN_ON(!lpm_m4tcm_saved_in_ddr); + + /* save M4 Image to DDR */ + memcpy(lpm_m4tcm_saved_in_ddr, lpm_m4tcm_base, SZ_32K); + } + np = of_find_compatible_node(NULL, NULL, "fsl,lpm-sram"); + if (of_get_property(np, "fsl,enable-lpsr", NULL)) + lpsr_enabled = true; + + if (psci_ops.cpu_suspend) + lpsr_enabled = false; + + if (lpsr_enabled) { + pr_info("LPSR mode enabled, DSM will go into LPSR mode!\n"); + lpm_ocram_base = of_iomap(np, 0); + WARN_ON(!lpm_ocram_base); + WARN_ON(of_address_to_resource(np, 0, &res)); + lpm_ocram_size = resource_size(&res); + lpm_ocram_saved_in_ddr = kzalloc(lpm_ocram_size, GFP_KERNEL); + WARN_ON(!lpm_ocram_saved_in_ddr); + + np = of_find_node_by_path( + "/soc/aips-bus@30000000/iomuxc@30330000"); + if (np) + iomuxc_base = of_iomap(np, 0); + WARN_ON(!iomuxc_base); + + np = of_find_node_by_path( + "/soc/aips-bus@30000000/gpt@302d0000"); + if (np) + gpt1_base = of_iomap(np, 0); + WARN_ON(!gpt1_base); + + np = of_find_node_by_path( + "/soc/aips-bus@30400000/system-counter-cmp@306b0000"); + if (np) + system_counter_cmp_base = of_iomap(np, 0); + WARN_ON(!system_counter_cmp_base); + + np = of_find_node_by_path( + "/soc/aips-bus@30000000/gpio@30200000"); + if (np) + gpio1_base = of_iomap(np, 0); + WARN_ON(!gpio1_base); + } + + np = of_find_node_by_path( + "/soc/aips-bus@30400000/system-counter-ctrl@306c0000"); + if (np) + system_counter_ctrl_base = of_iomap(np, 0); + WARN_ON(!system_counter_ctrl_base); + + if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR3 + || imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx7_pm_common_init(&imx7d_pm_data_lpddr3); + else if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_DDR3) + imx7_pm_common_init(&imx7d_pm_data_ddr3); + + np = of_find_compatible_node(NULL, NULL, "fsl,mega-fast-sram"); + ocram_base = of_iomap(np, 0); + WARN_ON(!ocram_base); + WARN_ON(of_address_to_resource(np, 0, &res)); + ocram_size = resource_size(&res); + ocram_saved_in_ddr = kzalloc(ocram_size, GFP_KERNEL); + WARN_ON(!ocram_saved_in_ddr); + + np = of_find_node_by_path( + "/soc/aips-bus@30800000/spba-bus@30800000/serial@30860000"); + if (np) + console_base = of_iomap(np, 0); + + /* clear LPSR resume address first */ + imx7_pm_set_lpsr_resume_addr(0); +} diff --git a/arch/arm/mach-imx/pm-imx7ulp.c b/arch/arm/mach-imx/pm-imx7ulp.c index 7b2f7387e662..0a6139d2d495 100644 --- a/arch/arm/mach-imx/pm-imx7ulp.c +++ b/arch/arm/mach-imx/pm-imx7ulp.c @@ -5,64 +5,842 @@ * Author: Dong Aisheng <aisheng.dong@nxp.com> */ +#include <linux/delay.h> +#include <linux/console.h> +#include <linux/init.h> #include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/genalloc.h> +#include <linux/mfd/syscon.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/of_irq.h> +#include <linux/psci.h> +#include <linux/of_platform.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/suspend.h> +#include <asm/cacheflush.h> +#include <asm/fncpy.h> +#include <asm/mach/map.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> +#include <asm/tlb.h> + +#include <uapi/linux/psci.h> #include "common.h" +#include "hardware.h" + +#define MU_SR 0x60 + +#define PMPROT 0x8 +#define PMCTRL 0x10 +#define PMSTAT 0x18 +#define SRS 0x20 +#define RPC 0x24 +#define SSRS 0x28 +#define SRIE 0x2c +#define SRIF 0x30 +#define CSRE 0x34 +#define MR 0x40 + +#define PMC1_HSRUN 0x4 +#define PMC1_RUN 0x8 +#define PMC1_VLPR 0xc +#define PMC1_STOP 0x10 +#define PMC1_VLPS 0x14 +#define PMC1_LLS 0x18 +#define PMC1_VLLS 0x1c +#define PMC1_STATUS 0x20 +#define PMC1_CTRL 0x24 +#define PMC0_CTRL 0x28 + +#define BM_PMPROT_AHSRUN (1 << 7) +#define BM_PMPROT_AVLP (1 << 5) +#define BM_PMPROT_ALLS (1 << 3) +#define BM_PMPROT_AVLLS (1 << 1) + +#define BM_PMCTRL_STOPA (1 << 24) +#define BM_PMCTRL_PSTOPO (3 << 16) +#define BM_PMCTRL_RUNM (3 << 8) +#define BM_PMCTRL_STOPM (7 << 0) + +#define BM_VLPS_RBBEN (1 << 28) + +#define BM_CTRL_LDOEN (1 << 31) +#define BM_CTRL_LDOOKDIS (1 << 30) + +#define BM_VLLS_MON1P2HVDHP (1 << 5) +#define BM_VLLS_MON1P2LVDHP (1 << 4) -#define SMC_PMCTRL 0x10 -#define BP_PMCTRL_PSTOPO 16 -#define PSTOPO_PSTOP3 0x3 -#define PSTOPO_PSTOP2 0x2 -#define PSTOPO_PSTOP1 0x1 -#define BP_PMCTRL_RUNM 8 -#define RUNM_RUN 0 #define BP_PMCTRL_STOPM 0 -#define STOPM_STOP 0 +#define BP_PMCTRL_PSTOPO 16 + +#define MX7ULP_MAX_MMDC_IO_NUM 64 +#define MX7ULP_MAX_MMDC_NUM 50 +#define MX7ULP_MAX_IOMUX_NUM 116 +#define MX7ULP_MAX_SELECT_INPUT_NUM 78 + +#define IOMUX_START 0x0 +#define SELECT_INPUT_START 0x200 + +#define TPM_SC 0x10 +#define TPM_MOD 0x18 +#define TPM_C0SC 0x20 +#define TPM_C0V 0x24 -#define BM_PMCTRL_PSTOPO (3 << BP_PMCTRL_PSTOPO) -#define BM_PMCTRL_RUNM (3 << BP_PMCTRL_RUNM) -#define BM_PMCTRL_STOPM (7 << BP_PMCTRL_STOPM) +#define PCC2_ENABLE_PCS_FIRC ((1 << 30) | (3 << 24)) +#define PCC2_ENABLE (1 << 30) + +#define LPUART_BAUD 0x10 +#define LPUART_CTRL 0x18 +#define LPUART_FIFO 0x28 +#define LPUART_WATER 0x2c + +#define GPIO_PDOR 0x0 +#define GPIO_PDDR 0x14 + +#define PTC2_LPUART4_TX_OFFSET 0x8 +#define PTC3_LPUART4_RX_OFFSET 0xc +#define PTC2_LPUART4_TX_INPUT_OFFSET 0x248 +#define PTC3_LPUART4_RX_INPUT_OFFSET 0x24c +#define LPUART4_MUX_VALUE (4 << 8) +#define LPUART4_INPUT_VALUE (1) + +#define MU_B_SR_NMIC (1 << 3) + +#define DGO_GPR3 0x60 +#define DGO_GPR4 0x64 + +#define ADDR_1M_MASK 0xFFF00000 + +#define WDOG_CS 0x0 +#define WDOG_CS_CMD32EN BIT(13) +#define WDOG_CNT 0x4 +#define REFRESH_SEQ0 0xA602 +#define REFRESH_SEQ1 0xB480 +#define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0) static void __iomem *smc1_base; +static void __iomem *pmc0_base; +static void __iomem *pmc1_base; +static void __iomem *tpm5_base; +static void __iomem *lpuart4_base; +static void __iomem *iomuxc1_base; +static void __iomem *pcc2_base; +static void __iomem *pcc3_base; +static void __iomem *mu_base; +static void __iomem *scg1_base; +static void __iomem *wdog1_base; +static void __iomem *gpio_base[4]; +static void __iomem *suspend_ocram_base; +static void (*imx7ulp_suspend_in_ocram_fn)(void __iomem *sram_base); + +static u32 tpm5_regs[4]; +static u32 lpuart4_regs[4]; +static u32 pcc2_regs[24][2] = { + {0x20, 0}, {0x3c, 0}, {0x40, 0}, {0x6c, 0}, + {0x84, 0}, {0x90, 0}, {0x94, 0}, {0x98, 0}, + {0x9c, 0}, {0xa4, 0}, {0xa8, 0}, {0xac, 0}, + {0xb0, 0}, {0xb4, 0}, {0xb8, 0}, {0xc4, 0}, + {0xcc, 0}, {0xd0, 0}, {0xd4, 0}, {0xd8, 0}, + {0xdc, 0}, {0xe0, 0}, {0xf4, 0}, {0x10c, 0}, +}; + +static u32 pcc3_regs[16][2] = { + {0x84, 0}, {0x88, 0}, {0x90, 0}, {0x94, 0}, + {0x98, 0}, {0x9c, 0}, {0xa0, 0}, {0xa4, 0}, + {0xa8, 0}, {0xac, 0}, {0xb8, 0}, {0xbc, 0}, + {0xc0, 0}, {0xc4, 0}, {0x140, 0}, {0x144, 0}, +}; + +static u32 scg1_offset[17] = { + 0x14, 0x30, 0x40, 0x304, + 0x500, 0x504, 0x508, 0x50c, + 0x510, 0x514, 0x600, 0x604, + 0x608, 0x60c, 0x610, 0x614, + 0x104, +}; + +extern unsigned long iram_tlb_base_addr; +extern unsigned long iram_tlb_phys_addr; + +/* + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx7ulp_suspend code + * PM_INFO structure(imx7ulp_cpu_pm_info) + * ======================== low address ======================= + */ +struct imx7ulp_pm_socdata { + u32 ddr_type; + const char *mmdc_compat; + const u32 mmdc_io_num; + const u32 *mmdc_io_offset; + const u32 mmdc_num; + const u32 *mmdc_offset; +}; + +static const u32 imx7ulp_mmdc_io_lpddr3_offset[] __initconst = { + 0x0, 0x4, 0x8, 0xc, + 0x10, 0x14, 0x18, 0x1c, + 0x20, 0x24, 0x28, 0x2c, + 0x30, 0x34, 0x38, 0x3c, + 0x40, 0x44, 0x48, 0x4c, + 0x50, 0x54, 0x58, 0x5c, + 0x60, 0x64, 0x68, 0x6c, + 0x70, 0x74, 0x78, 0x7c, + 0x80, 0x84, 0x88, 0x8c, + 0x90, 0x94, 0x98, 0x9c, + 0xa0, 0xa4, 0xa8, 0xac, + 0xb0, 0xb4, 0xb8, 0xbc, + 0xc0, 0xc4, 0xc8, 0xcc, + 0xd0, 0xd4, 0xd8, 0xdc, + 0xe8, 0xf8, 0xfc, 0x120, + 0x124, +}; + +static const u32 imx7ulp_mmdc_lpddr3_offset[] __initconst = { + 0x01c, 0x800, 0x85c, 0x890, + 0x848, 0x850, 0x81c, 0x820, + 0x824, 0x828, 0x82c, 0x830, + 0x834, 0x838, 0x8c0, 0x8b8, + 0x004, 0x00c, 0x010, 0x038, + 0x014, 0x018, 0x02c, 0x030, + 0x040, 0x000, 0x01c, 0x01c, + 0x01c, 0x01c, 0x01c, 0x01c, + 0x01c, 0x01c, 0x01c, 0x01c, + 0x01c, 0x01c, 0x83c, 0x020, + 0x800, 0x004, 0x404, 0x01c, +}; + +static const u32 imx7ulp_lpddr3_script[] __initconst = { + 0x00008000, 0xA1390003, 0x0D3900A0, 0x00400000, + 0x40404040, 0x40404040, 0x33333333, 0x33333333, + 0x33333333, 0x33333333, 0xf3333333, 0xf3333333, + 0xf3333333, 0xf3333333, 0x24922492, 0x00000800, + 0x00020052, 0x292C42F3, 0x00100A22, 0x00120556, + 0x00C700DB, 0x00211718, 0x0F9F26D2, 0x009F0E10, + 0x0000003F, 0xC3190000, 0x00008050, 0x00008058, + 0x003F8030, 0x003F8038, 0xFF0A8030, 0xFF0A8038, + 0x04028030, 0x04028038, 0x83018030, 0x83018038, + 0x01038030, 0x01038038, 0x20000000, 0x00001800, + 0xA1310000, 0x00020052, 0x00011006, 0x00000000, +}; + +static const struct imx7ulp_pm_socdata imx7ulp_lpddr3_pm_data __initconst = { + .mmdc_compat = "fsl,imx7ulp-mmdc", + .mmdc_io_num = ARRAY_SIZE(imx7ulp_mmdc_io_lpddr3_offset), + .mmdc_io_offset = imx7ulp_mmdc_io_lpddr3_offset, + .mmdc_num = ARRAY_SIZE(imx7ulp_mmdc_lpddr3_offset), + .mmdc_offset = imx7ulp_mmdc_lpddr3_offset, +}; + +/* + * This structure is for passing necessary data for low level ocram + * suspend code(arch/arm/mach-imx/suspend-imx7ulp.S), if this struct + * definition is changed, the offset definition in + * arch/arm/mach-imx/suspend-imx7ulp.S must be also changed accordingly, + * otherwise, the suspend to sram function will be broken! + */ +struct imx7ulp_cpu_pm_info { + u32 m4_reserve0; + u32 m4_reserve1; + u32 m4_reserve2; + phys_addr_t pbase; /* The physical address of pm_info. */ + phys_addr_t resume_addr; /* The physical resume address for asm code */ + u32 pm_info_size; /* Size of pm_info. */ + void __iomem *sim_base; + void __iomem *scg1_base; + void __iomem *mmdc_base; + void __iomem *mmdc_io_base; + void __iomem *smc1_base; + u32 scg1[17]; + u32 ttbr1; /* Store TTBR1 */ + u32 gpio[4][2]; + u32 iomux_num; /* Number of IOs which need saved/restored. */ + u32 iomux_val[MX7ULP_MAX_IOMUX_NUM]; /* To save value */ + u32 select_input_num; /* Number of select input which need saved/restored. */ + u32 select_input_val[MX7ULP_MAX_SELECT_INPUT_NUM]; /* To save value */ + u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ + u32 mmdc_io_val[MX7ULP_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ + u32 mmdc_num; /* Number of MMDC registers which need saved/restored. */ + u32 mmdc_val[MX7ULP_MAX_MMDC_NUM][2]; +} __aligned(8); + +static struct imx7ulp_cpu_pm_info *pm_info; +static void __iomem *aips1_base; +static void __iomem *aips2_base; +static void __iomem *aips3_base; +static void __iomem *aips4_base; +static void __iomem *aips5_base; + +static const char * const low_power_ocram_match[] __initconst = { + "fsl,lpm-sram", + NULL +}; + +static void imx7ulp_gpio_save(void) +{ + int i; + + for (i = 0; i < 4; i++) { + pm_info->gpio[i][0] = readl_relaxed(gpio_base[i] + GPIO_PDOR); + pm_info->gpio[i][1] = readl_relaxed(gpio_base[i] + GPIO_PDDR); + } +} + +static void imx7ulp_scg1_save(void) +{ + int i; + + for (i = 0; i < 17; i++) + pm_info->scg1[i] = readl_relaxed(scg1_base + scg1_offset[i]); +} + +static void imx7ulp_pcc3_save(void) +{ + int i; + + for (i = 0; i < 16; i++) + pcc3_regs[i][1] = readl_relaxed(pcc3_base + pcc3_regs[i][0]); +} + +static void imx7ulp_pcc3_restore(void) +{ + int i; + + for (i = 0; i < 16; i++) + writel_relaxed(pcc3_regs[i][1], pcc3_base + pcc3_regs[i][0]); +} + +static void imx7ulp_pcc2_save(void) +{ + int i; + + for (i = 0; i < 24; i++) + pcc2_regs[i][1] = readl_relaxed(pcc2_base + pcc2_regs[i][0]); +} + +static void imx7ulp_pcc2_restore(void) +{ + int i; + + for (i = 0; i < 24; i++) + writel_relaxed(pcc2_regs[i][1], pcc2_base + pcc2_regs[i][0]); +} + +static inline void imx7ulp_iomuxc_save(void) +{ + int i; + + pm_info->iomux_num = MX7ULP_MAX_IOMUX_NUM; + pm_info->select_input_num = MX7ULP_MAX_SELECT_INPUT_NUM; + + for (i = 0; i < pm_info->iomux_num; i++) + pm_info->iomux_val[i] = + readl_relaxed(iomuxc1_base + + IOMUX_START + i * 0x4); + for (i = 0; i < pm_info->select_input_num; i++) + pm_info->select_input_val[i] = + readl_relaxed(iomuxc1_base + + SELECT_INPUT_START + i * 0x4); +} + +static void imx7ulp_lpuart_save(void) +{ + lpuart4_regs[0] = readl_relaxed(lpuart4_base + LPUART_BAUD); + lpuart4_regs[1] = readl_relaxed(lpuart4_base + LPUART_FIFO); + lpuart4_regs[2] = readl_relaxed(lpuart4_base + LPUART_WATER); + lpuart4_regs[3] = readl_relaxed(lpuart4_base + LPUART_CTRL); +} + +static void imx7ulp_lpuart_restore(void) +{ + writel_relaxed(LPUART4_MUX_VALUE, + iomuxc1_base + PTC2_LPUART4_TX_OFFSET); + writel_relaxed(LPUART4_MUX_VALUE, + iomuxc1_base + PTC3_LPUART4_RX_OFFSET); + writel_relaxed(LPUART4_INPUT_VALUE, + iomuxc1_base + PTC2_LPUART4_TX_INPUT_OFFSET); + writel_relaxed(LPUART4_INPUT_VALUE, + iomuxc1_base + PTC3_LPUART4_RX_INPUT_OFFSET); + + writel_relaxed(lpuart4_regs[0], lpuart4_base + LPUART_BAUD); + writel_relaxed(lpuart4_regs[1], lpuart4_base + LPUART_FIFO); + writel_relaxed(lpuart4_regs[2], lpuart4_base + LPUART_WATER); + writel_relaxed(lpuart4_regs[3], lpuart4_base + LPUART_CTRL); +} + +static void imx7ulp_tpm_save(void) +{ + tpm5_regs[0] = readl_relaxed(tpm5_base + TPM_SC); + tpm5_regs[1] = readl_relaxed(tpm5_base + TPM_MOD); + tpm5_regs[2] = readl_relaxed(tpm5_base + TPM_C0SC); + tpm5_regs[3] = readl_relaxed(tpm5_base + TPM_C0V); +} + +static void imx7ulp_tpm_restore(void) +{ + writel_relaxed(tpm5_regs[0], tpm5_base + TPM_SC); + writel_relaxed(tpm5_regs[1], tpm5_base + TPM_MOD); + writel_relaxed(tpm5_regs[2], tpm5_base + TPM_C0SC); + writel_relaxed(tpm5_regs[3], tpm5_base + TPM_C0V); +} + +static void imx7ulp_set_dgo(u32 val) +{ + writel_relaxed(val, pm_info->sim_base + DGO_GPR3); + writel_relaxed(val, pm_info->sim_base + DGO_GPR4); +} int imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode) { - u32 val = readl_relaxed(smc1_base + SMC_PMCTRL); + u32 val1 = BM_PMPROT_AHSRUN | BM_PMPROT_AVLP | BM_PMPROT_AVLLS; + u32 val2 = readl_relaxed(smc1_base + PMCTRL); + u32 val3 = readl_relaxed(pmc0_base + PMC0_CTRL); - /* clear all */ - val &= ~(BM_PMCTRL_RUNM | BM_PMCTRL_STOPM | BM_PMCTRL_PSTOPO); + val2 &= ~(BM_PMCTRL_RUNM | + BM_PMCTRL_STOPM | BM_PMCTRL_PSTOPO); + val3 |= BM_CTRL_LDOOKDIS; switch (mode) { case ULP_PM_RUN: /* system/bus clock enabled */ - val |= PSTOPO_PSTOP3 << BP_PMCTRL_PSTOPO; + val2 |= 0x3 << BP_PMCTRL_PSTOPO; break; case ULP_PM_WAIT: /* system clock disabled, bus clock enabled */ - val |= PSTOPO_PSTOP2 << BP_PMCTRL_PSTOPO; + val2 |= 0x2 << BP_PMCTRL_PSTOPO; break; case ULP_PM_STOP: /* system/bus clock disabled */ - val |= PSTOPO_PSTOP1 << BP_PMCTRL_PSTOPO; + val2 |= 0x1 << BP_PMCTRL_PSTOPO; + break; + case ULP_PM_VLPS: + val2 |= 0x2 << BP_PMCTRL_STOPM; + break; + case ULP_PM_VLLS: + val2 |= 0x4 << BP_PMCTRL_STOPM; break; default: return -EINVAL; } - writel_relaxed(val, smc1_base + SMC_PMCTRL); + writel_relaxed(val1, smc1_base + PMPROT); + writel_relaxed(val2, smc1_base + PMCTRL); + writel_relaxed(val3, pmc0_base + PMC0_CTRL); return 0; } -void __init imx7ulp_pm_init(void) +#define MX7ULP_SUSPEND_POWERDWN_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +#define MX7ULP_SUSPEND_STANDBY_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_STANDBY << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) + +static int imx7ulp_suspend_finish(unsigned long val) +{ + u32 state; + + if (val == 0) + state = MX7ULP_SUSPEND_POWERDWN_PARAM; + else + state = MX7ULP_SUSPEND_STANDBY_PARAM; + + if (psci_ops.cpu_suspend) + return psci_ops.cpu_suspend(state, __pa(cpu_resume)); + + imx7ulp_suspend_in_ocram_fn(suspend_ocram_base); + + return 0; +} + +static void imx7ulp_wdog_refresh(void) +{ + /* + * On revision 2.2, wdog2 is by default disabled when out of + * reset, so here, we ONLY refresh wdog1. + */ + if (readl_relaxed(wdog1_base + WDOG_CS) & WDOG_CS_CMD32EN) { + writel(REFRESH, wdog1_base + WDOG_CNT); + } else { + writel_relaxed(REFRESH_SEQ0, wdog1_base + WDOG_CNT); + writel_relaxed(REFRESH_SEQ1, wdog1_base + WDOG_CNT); + } +} + +static int imx7ulp_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + if (psci_ops.cpu_suspend) + /* Zzz ... */ + cpu_suspend(1, imx7ulp_suspend_finish); + else { + imx7ulp_set_lpm(ULP_PM_VLPS); + writel_relaxed( + readl_relaxed(pmc1_base + PMC1_VLPS) | BM_VLPS_RBBEN, + pmc1_base + PMC1_VLPS); + + /* Zzz ... */ + cpu_suspend(0, imx7ulp_suspend_finish); + + writel_relaxed( + readl_relaxed(pmc1_base + PMC1_VLPS) & ~BM_VLPS_RBBEN, + pmc1_base + PMC1_VLPS); + imx7ulp_set_lpm(ULP_PM_RUN); + } + break; + case PM_SUSPEND_MEM: + if (psci_ops.cpu_suspend) { + /* Zzz ... */ + cpu_suspend(0, imx7ulp_suspend_finish); + } else { + imx7ulp_gpio_save(); + imx7ulp_scg1_save(); + imx7ulp_pcc2_save(); + imx7ulp_pcc3_save(); + imx7ulp_tpm_save(); + if (!console_suspend_enabled) + imx7ulp_lpuart_save(); + imx7ulp_iomuxc_save(); + imx7ulp_set_lpm(ULP_PM_VLLS); + + /* Zzz ... */ + cpu_suspend(0, imx7ulp_suspend_finish); + + imx7ulp_pcc2_restore(); + imx7ulp_pcc3_restore(); + if (!console_suspend_enabled) + imx7ulp_lpuart_restore(); + imx7ulp_set_dgo(0); + imx7ulp_tpm_restore(); + imx7ulp_set_lpm(ULP_PM_RUN); + } + break; + default: + return -EINVAL; + } + + imx7ulp_wdog_refresh(); + + return 0; +} + +/* Put CA7 into VLLS mode before M4 power off CA7 */ +void imx7ulp_poweroff(void) +{ + imx7ulp_set_lpm(ULP_PM_VLLS); + cpu_suspend(0, imx7ulp_suspend_finish); +} + +static int imx7ulp_pm_valid(suspend_state_t state) +{ + return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM); +} + +static const struct platform_suspend_ops imx7ulp_pm_ops = { + .enter = imx7ulp_pm_enter, + .valid = imx7ulp_pm_valid, +}; + +static int __init imx7ulp_suspend_init(void) +{ + int ret = 0; + + suspend_set_ops(&imx7ulp_pm_ops); + + return ret; +} + +static struct map_desc iram_tlb_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_1M, + .type = MT_MEMORY_RWX_NONCACHED, +}; + +static int __init imx7ulp_dt_find_lpsram(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned long lpram_addr; + const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL); + + if (of_flat_dt_match(node, low_power_ocram_match)) { + if (!prop) + return -EINVAL; + + lpram_addr = be32_to_cpup(prop); + + /* We need to create a 1M page table entry. */ + iram_tlb_io_desc.virtual = + IMX_IO_P2V(lpram_addr & ADDR_1M_MASK); + iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & ADDR_1M_MASK); + iram_tlb_phys_addr = lpram_addr; + iram_tlb_base_addr = IMX_IO_P2V(lpram_addr); + iotable_init(&iram_tlb_io_desc, 1); + } + + return 0; +} + +void __init imx7ulp_pm_map_io(void) +{ + /* + * Get the address of IRAM or OCRAM to be used by the low + * power code from the device tree. + */ + WARN_ON(of_scan_flat_dt(imx7ulp_dt_find_lpsram, NULL)); + + /* Return if no IRAM space is allocated for suspend/resume code. */ + if (!iram_tlb_base_addr) { + pr_warn("No valid ocram available for suspend/resume!\n"); + return; + } +} + +void __init imx7ulp_pm_common_init(const struct imx7ulp_pm_socdata + *socdata) { struct device_node *np; + unsigned long sram_paddr = 0; + const u32 *mmdc_offset_array; + const u32 *mmdc_io_offset_array; + unsigned long i, j; + int ret; + + if (psci_ops.cpu_suspend) { + aips1_base = ioremap(MX7ULP_AIPS1_BASE_ADDR, SZ_1M); + aips2_base = ioremap(MX7ULP_AIPS2_BASE_ADDR, SZ_1M); + aips3_base = ioremap(MX7ULP_AIPS3_BASE_ADDR, SZ_1M); + aips4_base = ioremap(MX7ULP_AIPS4_BASE_ADDR, SZ_1M); + aips5_base = ioremap(MX7ULP_AIPS5_BASE_ADDR, SZ_1M); + } else { + /* Set all entries to 0 except first 3 words reserved for M4. */ + memset((void *)iram_tlb_base_addr, 0, MX7ULP_IRAM_TLB_SIZE); + + /* + * Make sure the IRAM virtual address has a mapping in the IRAM + * page table. + * + * Only use the top 12 bits [31-20] when storing the physical + * address in the page table as only these bits are required + * for 1M mapping. + */ + j = ((iram_tlb_base_addr >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + (iram_tlb_phys_addr & ADDR_1M_MASK) | + TT_ATTRIB_NON_CACHEABLE_1M; + /* + * Make sure the AIPS1 virtual address has a mapping in the + * IRAM page table. + */ + aips1_base = ioremap(MX7ULP_AIPS1_BASE_ADDR, SZ_1M); + j = (((u32)aips1_base >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7ULP_AIPS1_BASE_ADDR) & ADDR_1M_MASK) | + TT_ATTRIB_NON_CACHEABLE_1M; + /* + * Make sure the AIPS2 virtual address has a mapping in the + * IRAM page table. + */ + aips2_base = ioremap(MX7ULP_AIPS2_BASE_ADDR, SZ_1M); + j = (((u32)aips2_base >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7ULP_AIPS2_BASE_ADDR) & ADDR_1M_MASK) | + TT_ATTRIB_NON_CACHEABLE_1M; + /* + * Make sure the AIPS3 virtual address has a mapping in the + * IRAM page table. + */ + aips3_base = ioremap(MX7ULP_AIPS3_BASE_ADDR, SZ_1M); + j = (((u32)aips3_base >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7ULP_AIPS3_BASE_ADDR) & ADDR_1M_MASK) | + TT_ATTRIB_NON_CACHEABLE_1M; + /* + * Make sure the AIPS4 virtual address has a mapping in the + * IRAM page table. + */ + aips4_base = ioremap(MX7ULP_AIPS4_BASE_ADDR, SZ_1M); + j = (((u32)aips4_base >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7ULP_AIPS4_BASE_ADDR) & ADDR_1M_MASK) | + TT_ATTRIB_NON_CACHEABLE_1M; + /* + * Make sure the AIPS5 virtual address has a mapping in the + * IRAM page table. + */ + aips5_base = ioremap(MX7ULP_AIPS5_BASE_ADDR, SZ_1M); + j = (((u32)aips5_base >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7ULP_AIPS5_BASE_ADDR) & ADDR_1M_MASK) | + TT_ATTRIB_NON_CACHEABLE_1M; + } np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1"); smc1_base = of_iomap(np, 0); WARN_ON(!smc1_base); + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pmc0"); + pmc0_base = of_iomap(np, 0); + WARN_ON(!pmc0_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pmc1"); + pmc1_base = of_iomap(np, 0); + WARN_ON(!pmc1_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-tpm"); + tpm5_base = of_iomap(np, 0); + WARN_ON(!tpm5_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-lpuart"); + lpuart4_base = of_iomap(np, 0); + WARN_ON(!lpuart4_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pcc2"); + pcc2_base = of_iomap(np, 0); + WARN_ON(!pcc2_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pcc3"); + pcc3_base = of_iomap(np, 0); + WARN_ON(!pcc3_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-iomuxc1"); + iomuxc1_base = of_iomap(np, 0); + WARN_ON(!iomuxc1_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-scg1"); + scg1_base = of_iomap(np, 0); + WARN_ON(!scg1_base); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-wdt"); + wdog1_base = of_iomap(np, 0); + WARN_ON(!wdog1_base); + + np = NULL; + for (i = 0; i < 4; i++) { + np = of_find_compatible_node(np, NULL, "fsl,vf610-gpio"); + gpio_base[i] = of_iomap(np, 1); + WARN_ON(!gpio_base[i]); + } + + if (psci_ops.cpu_suspend) { + pm_info = kzalloc(SZ_16K, GFP_KERNEL); + if (!pm_info) + panic("pm info allocation failed\n"); + } else { + /* + * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, + * The lower 8K is not used, so use the lower 8K for IRAM code and + * pm_info. + * + */ + sram_paddr = iram_tlb_phys_addr; + + /* Make sure sram_paddr is 8 byte aligned. */ + if ((uintptr_t)(sram_paddr) & (FNCPY_ALIGN - 1)) + sram_paddr += FNCPY_ALIGN - sram_paddr % (FNCPY_ALIGN); + + /* Get the virtual address of the suspend code. */ + suspend_ocram_base = (void *)IMX_IO_P2V(sram_paddr); + + pm_info = suspend_ocram_base; + } + pm_info->pbase = sram_paddr; + pm_info->resume_addr = virt_to_phys(imx7ulp_cpu_resume); + pm_info->pm_info_size = sizeof(*pm_info); + + pm_info->scg1_base = aips2_base + + (MX7ULP_SCG1_BASE_ADDR & ~ADDR_1M_MASK); + pm_info->smc1_base = aips3_base + + (MX7ULP_SMC1_BASE_ADDR & ~ADDR_1M_MASK); + pm_info->mmdc_base = aips4_base + + (MX7ULP_MMDC_BASE_ADDR & ~ADDR_1M_MASK); + pm_info->mmdc_io_base = aips4_base + + (MX7ULP_MMDC_IO_BASE_ADDR & ~ADDR_1M_MASK); + pm_info->sim_base = aips5_base + + (MX7ULP_SIM_BASE_ADDR & ~ADDR_1M_MASK); + + pm_info->mmdc_io_num = socdata->mmdc_io_num; + mmdc_io_offset_array = socdata->mmdc_io_offset; + pm_info->mmdc_num = socdata->mmdc_num; + mmdc_offset_array = socdata->mmdc_offset; + + for (i = 0; i < pm_info->mmdc_io_num; i++) { + pm_info->mmdc_io_val[i][0] = + mmdc_io_offset_array[i]; + pm_info->mmdc_io_val[i][1] = + readl_relaxed(pm_info->mmdc_io_base + + mmdc_io_offset_array[i]); + } + + /* initialize MMDC settings */ + for (i = 0; i < pm_info->mmdc_num; i++) + pm_info->mmdc_val[i][0] = + mmdc_offset_array[i]; + + for (i = 0; i < pm_info->mmdc_num; i++) + pm_info->mmdc_val[i][1] = imx7ulp_lpddr3_script[i]; + + if (!psci_ops.cpu_suspend) { + imx7ulp_suspend_in_ocram_fn = fncpy( + suspend_ocram_base + sizeof(*pm_info), + &imx7ulp_suspend, + MX7ULP_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); + } + + if (IS_ENABLED(CONFIG_SUSPEND)) { + ret = imx7ulp_suspend_init(); + if (ret) + pr_warn("%s: No DDR LPM support with suspend %d!\n", + __func__, ret); + } +} + +void __init imx7ulp_pm_init(void) +{ + imx7ulp_pm_common_init(&imx7ulp_lpddr3_pm_data); imx7ulp_set_lpm(ULP_PM_RUN); } + +static irqreturn_t imx7ulp_nmi_isr(int irq, void *param) +{ + writel_relaxed(readl_relaxed(mu_base + MU_SR) | MU_B_SR_NMIC, + mu_base + MU_SR); + pm_system_wakeup(); + + return IRQ_HANDLED; +} + +void imx7ulp_enable_nmi(void) +{ + struct device_node *np; + int irq, ret; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-nmi"); + mu_base = of_iomap(np, 0); + WARN_ON(!mu_base); + irq = of_irq_get(np, 0); + ret = request_irq(irq, imx7ulp_nmi_isr, + IRQF_NO_SUSPEND, "imx7ulp-nmi", NULL); + if (ret) { + pr_err("%s: register interrupt %d failed, rc %d\n", + __func__, irq, ret); + return; + } +} diff --git a/arch/arm/mach-imx/pm-rpmsg.c b/arch/arm/mach-imx/pm-rpmsg.c new file mode 100644 index 000000000000..4dfe489f5d38 --- /dev/null +++ b/arch/arm/mach-imx/pm-rpmsg.c @@ -0,0 +1,353 @@ +/* + * Copyright 2017-2018 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/imx_rpmsg.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_qos.h> +#include <linux/reboot.h> +#include <linux/rpmsg.h> +#include <linux/uaccess.h> +#include <linux/virtio.h> +#include "common.h" + +#define RPMSG_TIMEOUT 1000 + +#define PM_RPMSG_TYPE 0 +#define HEATBEAT_RPMSG_TYPE 2 + +enum pm_rpmsg_cmd { + PM_RPMSG_MODE, + PM_RPMSG_HEART_BEAT, + PM_RPMSG_HEART_BEAT_OFF, +}; + +enum pm_rpmsg_power_mode { + PM_RPMSG_HSRUN, + PM_RPMSG_RUN, + PM_RPMSG_VLPR, + PM_RPMSG_WAIT, + PM_RPMSG_VLPS, + PM_RPMSG_VLLS, + PM_RPMSG_REBOOT, + PM_RPMSG_SHUTDOWN, +}; + +struct pm_rpmsg_info { + struct rpmsg_device *rpdev; + struct device *dev; + struct pm_rpmsg_data *msg; + struct pm_qos_request pm_qos_req; + struct notifier_block restart_handler; + struct completion cmd_complete; + bool first_flag; + struct mutex lock; +}; + +static struct pm_rpmsg_info pm_rpmsg; + +static struct delayed_work heart_beat_work; + +static bool heartbeat_off; + +struct pm_rpmsg_data { + struct imx_rpmsg_head header; + u8 data; +} __attribute__ ((packed)); + +static int pm_send_message(struct pm_rpmsg_data *msg, + struct pm_rpmsg_info *info, bool ack) +{ + int err; + + if (!info->rpdev) { + dev_dbg(info->dev, + "rpmsg channel not ready, m4 image ready?\n"); + return -EINVAL; + } + + mutex_lock(&info->lock); + pm_qos_add_request(&info->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, 0); + + reinit_completion(&info->cmd_complete); + + err = rpmsg_send(info->rpdev->ept, (void *)msg, + sizeof(struct pm_rpmsg_data)); + + if (err) { + dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err); + goto err_out; + } + + if (ack) { + err = wait_for_completion_timeout(&info->cmd_complete, + msecs_to_jiffies(RPMSG_TIMEOUT)); + if (!err) { + dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n"); + err = -ETIMEDOUT; + goto err_out; + } + + if (info->msg->data != 0) { + dev_err(&info->rpdev->dev, "rpmsg not ack %d!\n", + info->msg->data); + err = -EINVAL; + goto err_out; + } + + err = 0; + } + +err_out: + pm_qos_remove_request(&info->pm_qos_req); + mutex_unlock(&info->lock); + + return err; +} + +static int pm_vlls_notify_m4(bool enter) +{ + struct pm_rpmsg_data msg; + + msg.header.cate = IMX_RMPSG_LIFECYCLE; + msg.header.major = IMX_RMPSG_MAJOR; + msg.header.minor = IMX_RMPSG_MINOR; + msg.header.type = PM_RPMSG_TYPE; + msg.header.cmd = PM_RPMSG_MODE; + msg.data = enter ? PM_RPMSG_VLLS : PM_RPMSG_RUN; + + return pm_send_message(&msg, &pm_rpmsg, true); +} + +void pm_shutdown_notify_m4(void) +{ + struct pm_rpmsg_data msg; + + msg.header.cate = IMX_RMPSG_LIFECYCLE; + msg.header.major = IMX_RMPSG_MAJOR; + msg.header.minor = IMX_RMPSG_MINOR; + msg.header.type = PM_RPMSG_TYPE; + msg.header.cmd = PM_RPMSG_MODE; + msg.data = PM_RPMSG_SHUTDOWN; + /* No ACK from M4 */ + pm_send_message(&msg, &pm_rpmsg, false); + imx7ulp_poweroff(); +} + +void pm_reboot_notify_m4(void) +{ + struct pm_rpmsg_data msg; + + msg.header.cate = IMX_RMPSG_LIFECYCLE; + msg.header.major = IMX_RMPSG_MAJOR; + msg.header.minor = IMX_RMPSG_MINOR; + msg.header.type = PM_RPMSG_TYPE; + msg.header.cmd = PM_RPMSG_MODE; + msg.data = PM_RPMSG_REBOOT; + + pm_send_message(&msg, &pm_rpmsg, true); + +} + +void pm_heartbeat_off_notify_m4(bool enter) +{ + struct pm_rpmsg_data msg; + + msg.header.cate = IMX_RMPSG_LIFECYCLE; + msg.header.major = IMX_RMPSG_MAJOR; + msg.header.minor = IMX_RMPSG_MINOR; + msg.header.type = PM_RPMSG_TYPE; + msg.header.cmd = PM_RPMSG_HEART_BEAT_OFF; + msg.data = enter ? 0 : 1; + + pm_send_message(&msg, &pm_rpmsg, true); +} + +static void pm_heart_beat_work_handler(struct work_struct *work) +{ + struct pm_rpmsg_data msg; + + /* Notify M4 side A7 in RUN mode at boot time */ + if (pm_rpmsg.first_flag) { + pm_vlls_notify_m4(false); + + pm_heartbeat_off_notify_m4(heartbeat_off); + + pm_rpmsg.first_flag = false; + } + + if (!heartbeat_off) { + msg.header.cate = IMX_RMPSG_LIFECYCLE; + msg.header.major = IMX_RMPSG_MAJOR; + msg.header.minor = IMX_RMPSG_MINOR; + msg.header.type = HEATBEAT_RPMSG_TYPE; + msg.header.cmd = PM_RPMSG_HEART_BEAT; + msg.data = 0; + pm_send_message(&msg, &pm_rpmsg, false); + + schedule_delayed_work(&heart_beat_work, + msecs_to_jiffies(30000)); + } +} + +static void pm_poweroff_rpmsg(void) +{ + pm_shutdown_notify_m4(); + pr_emerg("Unable to poweroff system\n"); +} + +static int pm_restart_handler(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + pm_reboot_notify_m4(); + + return NOTIFY_DONE; +} + +static int pm_rpmsg_probe(struct rpmsg_device *rpdev) +{ + int ret; + + pm_rpmsg.rpdev = rpdev; + + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n", + rpdev->src, rpdev->dst); + + init_completion(&pm_rpmsg.cmd_complete); + mutex_init(&pm_rpmsg.lock); + + INIT_DELAYED_WORK(&heart_beat_work, + pm_heart_beat_work_handler); + + pm_rpmsg.first_flag = true; + schedule_delayed_work(&heart_beat_work, 0); + + pm_rpmsg.restart_handler.notifier_call = pm_restart_handler; + pm_rpmsg.restart_handler.priority = 128; + ret = register_restart_handler(&pm_rpmsg.restart_handler); + if (ret) + dev_err(&rpdev->dev, "cannot register restart handler\n"); + + pm_power_off = pm_poweroff_rpmsg; + + return 0; +} + +static int pm_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len, + void *priv, u32 src) +{ + struct pm_rpmsg_data *msg = (struct pm_rpmsg_data *)data; + + pm_rpmsg.msg = msg; + + complete(&pm_rpmsg.cmd_complete); + + return 0; +} + +static void pm_rpmsg_remove(struct rpmsg_device *rpdev) +{ + dev_info(&rpdev->dev, "pm rpmsg driver is removed\n"); +} + +static struct rpmsg_device_id pm_rpmsg_id_table[] = { + { .name = "rpmsg-life-cycle-channel" }, + { }, +}; + +static struct rpmsg_driver pm_rpmsg_driver = { + .drv.name = "pm_rpmsg", + .drv.owner = THIS_MODULE, + .id_table = pm_rpmsg_id_table, + .probe = pm_rpmsg_probe, + .callback = pm_rpmsg_cb, + .remove = pm_rpmsg_remove, +}; + +#ifdef CONFIG_PM_SLEEP +static int pm_heartbeat_suspend(struct device *dev) +{ + int err; + + err = pm_vlls_notify_m4(true); + if (err) + return err; + + cancel_delayed_work_sync(&heart_beat_work); + + return 0; +} + +static int pm_heartbeat_resume(struct device *dev) +{ + int err; + + err = pm_vlls_notify_m4(false); + if (err) + return err; + + schedule_delayed_work(&heart_beat_work, + msecs_to_jiffies(10000)); + + return 0; +} +#endif + +static int pm_heartbeat_probe(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, &pm_rpmsg); + + return register_rpmsg_driver(&pm_rpmsg_driver); +} + +static const struct of_device_id pm_heartbeat_id[] = { + {"fsl,heartbeat-rpmsg",}, + {}, +}; +MODULE_DEVICE_TABLE(of, pm_heartbeat_id); + +static const struct dev_pm_ops pm_heartbeat_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_heartbeat_suspend, + pm_heartbeat_resume) +}; + +static struct platform_driver pm_heartbeat_driver = { + .driver = { + .name = "heartbeat-rpmsg", + .owner = THIS_MODULE, + .of_match_table = pm_heartbeat_id, + .pm = &pm_heartbeat_ops, + }, + .probe = pm_heartbeat_probe, +}; + +static int __init setup_heartbeat(char *str) +{ + heartbeat_off = true; + + return 1; +}; +__setup("heartbeat_off", setup_heartbeat); + +module_platform_driver(pm_heartbeat_driver); + +MODULE_DESCRIPTION("Freescale PM rpmsg driver"); +MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-imx/smc_sip.h b/arch/arm/mach-imx/smc_sip.h new file mode 100644 index 000000000000..30c854be7d74 --- /dev/null +++ b/arch/arm/mach-imx/smc_sip.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 NXP + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __SMC_SIP_H__ +#define __SMC_SIP_H__ + +#include <linux/arm-smccc.h> + +/* + * Macro definition building the OPTEE SMC Code function + * for a Fast Call, SIP operation + */ +#define OPTEE_SMC_FAST_CALL_SIP_VAL(func_num) \ + ARM_SMCCC_CALL_VAL( \ + ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_SIP, \ + (func_num)) + + +/* + * Definition of the i.MX SMC SIP Operations + * Operation value must be aligned with i.MX OPTEE + * SIP definitions + */ +/* Busfreq operation */ +#define IMX_SIP_BUSFREQ_CHANGE 6 + +#endif /* __SMC_SIP_H__ */ + diff --git a/arch/arm/mach-imx/smp_wfe.S b/arch/arm/mach-imx/smp_wfe.S new file mode 100644 index 000000000000..08894bb39c4d --- /dev/null +++ b/arch/arm/mach-imx/smp_wfe.S @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include <asm/smp_scu.h> +#include "hardware.h" + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + +#ifdef CONFIG_SMP + .align 3 + +ENTRY(imx7_smp_wfe) + push {r4 - r11, lr} + + dsb + isb + + disable_l1_dcache + + isb + + /* Turn off SMP bit. */ + mrc p15, 0, r8, c1, c0, 1 + bic r8, r8, #0x40 + mcr p15, 0, r8, c1, c0, 1 + + isb + /* Set flag of entering WFE. */ + mov r7, #0xff + lsl r7, r7, r0 + mov r6, #SCU_PM_DORMANT + lsl r6, r6, r0 + ldr r8, [r1, #0x4] + bic r8, r8, r7 + orr r6, r6, r8 + str r6, [r1, #0x4] + +go_back_wfe: + wfe + + /* Offset 0x0 stores busfeq done flag */ + ldr r6, [r1] + cmp r6, #1 + beq go_back_wfe + + /* Turn ON SMP bit. */ + mrc p15, 0, r8, c1, c0, 1 + orr r8, r8, #0x40 + mcr p15, 0, r8, c1, c0, 1 + + isb + /* Enable L1 data cache. */ + mrc p15, 0, r8, c1, c0, 0 + orr r8, r8, #0x4 + mcr p15, 0, r8, c1, c0, 0 + isb + + /* Set flag of exiting WFE. */ + mov r7, #0xff + lsl r7, r7, r0 + mov r6, #SCU_PM_NORMAL + lsl r6, r6, r0 + ldr r8, [r1, #0x4] + bic r8, r8, r7 + orr r6, r6, r8 + str r6, [r1, #0x4] + + /* Pop all saved registers. */ + pop {r4 - r11, lr} + mov pc, lr + .ltorg +ENDPROC(imx7_smp_wfe) +#endif diff --git a/arch/arm/mach-imx/smp_wfe_imx6.S b/arch/arm/mach-imx/smp_wfe_imx6.S new file mode 100644 index 000000000000..791e93ce98da --- /dev/null +++ b/arch/arm/mach-imx/smp_wfe_imx6.S @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> +#include <asm/smp_scu.h> +#include "hardware.h" + +#ifdef CONFIG_SMP +.extern scu_base +#endif + +.globl wfe_smp_freq_change_start +.globl wfe_smp_freq_change_end + +#ifdef CONFIG_SMP + + .align 3 + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r11, lr} + + ldr r7, =v7_flush_kern_cache_all + mov lr, pc + mov pc, r7 + pop {r0 - r11, lr} + + /* disable d-cache */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + dsb + isb + + push {r0 - r11, lr} + + ldr r7, =v7_flush_kern_cache_all + mov lr, pc + mov pc, r7 + pop {r0 - r11, lr} + + .endm + +ENTRY(wfe_smp_freq_change) +wfe_smp_freq_change_start: + push {r4 - r11, lr} + + mov r6, r0 + mov r7, r1 + + dsb + isb + + disable_l1_dcache + + isb + + /* Turn off SMP bit. */ + mrc p15, 0, r8, c1, c0, 1 + bic r8, r8, #0x40 + mcr p15, 0, r8, c1, c0, 1 + + isb + + /* Inform the SCU we are going to enter WFE. */ + push {r0 - r11, lr} + + ldr r0,=scu_base + ldr r0, [r0] + mov r1, #SCU_PM_DORMANT + ldr r3, =scu_power_mode + mov lr, pc + mov pc, r3 + + pop {r0 - r11, lr} + +go_back_wfe: + wfe + + ldr r3, [r7] + cmp r3, #1 + beq go_back_wfe + + /* Turn ON SMP bit. */ + mrc p15, 0, r8, c1, c0, 1 + orr r8, r8, #0x40 + mcr p15, 0, r8, c1, c0, 1 + + isb + /* Enable L1 data cache. */ + mrc p15, 0, r8, c1, c0, 0 + orr r8, r8, #0x4 + mcr p15, 0, r8, c1, c0, 0 + isb + + /* Inform the SCU we have exited WFE. */ + push {r0 - r11, lr} + + ldr r0,=scu_base + ldr r0, [r0] + mov r1, #SCU_PM_NORMAL + ldr r3, =scu_power_mode + mov lr, pc + mov pc, r3 + + pop {r0 - r11, lr} + + /* Pop all saved registers. */ + pop {r4 - r11, lr} + mov pc, lr + .ltorg +wfe_smp_freq_change_end: +ENDPROC(wfe_smp_freq_change) + +#ifdef CONFIG_OPTEE +/** + * @brief Switch CPU in WFE mode while bus frequency change + * on-going + * + * @param[in] r0 CPU in WFE Status + * @param[in] r1 Bus frequency change status + */ + +.globl imx_smp_wfe_optee_end + +ENTRY(imx_smp_wfe_optee) + push {r4-r11, lr} + + dsb + isb + + disable_l1_dcache + isb + + /* Set flag CPU entering WFE. */ + mov r4, #1 + str r4, [r0] + + dsb + isb + +1: + wfe + + /* Check if busfreq is done, else loop */ + ldr r4, [r1] + cmp r4, #1 + beq 1b + + /* Enable L1 data cache. */ + mrc p15, 0, r4, c1, c0, 0 + orr r4, r4, #0x4 + mcr p15, 0, r4, c1, c0, 0 + isb + + /* Set flag CPU exiting WFE. */ + mov r4, #0 + str r4, [r0] + + /* Pop all saved registers. */ + pop {r4-r11, lr} + mov pc, lr + .ltorg +imx_smp_wfe_optee_end: +ENDPROC(imx_smp_wfe_optee) +#endif +#endif diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 0beea6d0217f..399771e2912e 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -12,6 +12,7 @@ #include <linux/smp.h> #include <asm/smp_plat.h> #include "common.h" +#include "hardware.h" #define SRC_SCR 0x000 #define SRC_GPR1 0x020 @@ -23,9 +24,18 @@ #define BP_SRC_SCR_SW_IPU2_RST 12 #define BP_SRC_SCR_CORE1_RST 14 #define BP_SRC_SCR_CORE1_ENABLE 22 +/* below is for i.MX7D */ +#define SRC_GPR1_V2 0x074 +#define SRC_A7RCR0 0x004 +#define SRC_A7RCR1 0x008 +#define SRC_M4RCR 0x00C + +#define BP_SRC_A7RCR0_A7_CORE_RESET0 0 +#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1 static void __iomem *src_base; -static DEFINE_SPINLOCK(scr_lock); +static DEFINE_SPINLOCK(src_lock); +static bool m4_is_enabled; static const int sw_reset_bits[5] = { BP_SRC_SCR_SW_GPU_RST, @@ -35,6 +45,11 @@ static const int sw_reset_bits[5] = { BP_SRC_SCR_SW_IPU2_RST }; +bool imx_src_is_m4_enabled(void) +{ + return m4_is_enabled; +} + static int imx_src_reset_module(struct reset_controller_dev *rcdev, unsigned long sw_reset_idx) { @@ -51,11 +66,11 @@ static int imx_src_reset_module(struct reset_controller_dev *rcdev, bit = 1 << sw_reset_bits[sw_reset_idx]; - spin_lock_irqsave(&scr_lock, flags); + spin_lock_irqsave(&src_lock, flags); val = readl_relaxed(src_base + SRC_SCR); val |= bit; writel_relaxed(val, src_base + SRC_SCR); - spin_unlock_irqrestore(&scr_lock, flags); + spin_unlock_irqrestore(&src_lock, flags); timeout = jiffies + msecs_to_jiffies(1000); while (readl(src_base + SRC_SCR) & bit) { @@ -81,32 +96,59 @@ void imx_enable_cpu(int cpu, bool enable) u32 mask, val; cpu = cpu_logical_map(cpu); - mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); - spin_lock(&scr_lock); - val = readl_relaxed(src_base + SRC_SCR); - val = enable ? val | mask : val & ~mask; - val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); - writel_relaxed(val, src_base + SRC_SCR); - spin_unlock(&scr_lock); + spin_lock(&src_lock); + if (cpu_is_imx7d()) { + /* enable core */ + if (enable) + imx_gpcv2_set_core1_pdn_pup_by_software(false); + + mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_A7RCR1); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_A7RCR1); + } else { + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); + writel_relaxed(val, src_base + SRC_SCR); + } + spin_unlock(&src_lock); } void imx_set_cpu_jump(int cpu, void *jump_addr) { + spin_lock(&src_lock); cpu = cpu_logical_map(cpu); - writel_relaxed(__pa_symbol(jump_addr), - src_base + SRC_GPR1 + cpu * 8); + if (cpu_is_imx7d()) + writel_relaxed(__pa_symbol(jump_addr), + src_base + SRC_GPR1_V2 + cpu * 8); + else + writel_relaxed(__pa_symbol(jump_addr), + src_base + SRC_GPR1 + cpu * 8); + spin_unlock(&src_lock); } u32 imx_get_cpu_arg(int cpu) { cpu = cpu_logical_map(cpu); - return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); + if (cpu_is_imx7d()) + return readl_relaxed(src_base + SRC_GPR1_V2 + + cpu * 8 + 4); + else + return readl_relaxed(src_base + SRC_GPR1 + + cpu * 8 + 4); } void imx_set_cpu_arg(int cpu, u32 arg) { cpu = cpu_logical_map(cpu); - writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); + if (cpu_is_imx7d()) + writel_relaxed(arg, src_base + SRC_GPR1_V2 + + cpu * 8 + 4); + else + writel_relaxed(arg, src_base + SRC_GPR1 + + cpu * 8 + 4); } void __init imx_src_init(void) @@ -120,6 +162,15 @@ void __init imx_src_init(void) src_base = of_iomap(np, 0); WARN_ON(!src_base); + if (cpu_is_imx7d()) { + val = readl_relaxed(src_base + SRC_M4RCR); + if (((val & BIT(3)) == BIT(3)) && !(val & BIT(0))) + m4_is_enabled = true; + else + m4_is_enabled = false; + return; + } + imx_reset_controller.of_node = np; if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) reset_controller_register(&imx_reset_controller); @@ -128,9 +179,17 @@ void __init imx_src_init(void) * force warm reset sources to generate cold reset * for a more reliable restart */ - spin_lock(&scr_lock); + spin_lock(&src_lock); val = readl_relaxed(src_base + SRC_SCR); + + /* bit 4 is m4c_non_sclr_rst on i.MX6SX */ + if (cpu_is_imx6sx() && ((val & + (1 << BP_SRC_SCR_SW_OPEN_VG_RST)) == 0)) + m4_is_enabled = true; + else + m4_is_enabled = false; + val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); writel_relaxed(val, src_base + SRC_SCR); - spin_unlock(&scr_lock); + spin_unlock(&src_lock); } diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index 1eabf2d2834b..a7e349e583e7 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -41,23 +41,32 @@ #define PM_INFO_RESUME_ADDR_OFFSET 0x4 #define PM_INFO_DDR_TYPE_OFFSET 0x8 #define PM_INFO_PM_INFO_SIZE_OFFSET 0xC -#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 -#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 -#define PM_INFO_MX6Q_SRC_P_OFFSET 0x18 -#define PM_INFO_MX6Q_SRC_V_OFFSET 0x1C -#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x20 -#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x24 -#define PM_INFO_MX6Q_CCM_P_OFFSET 0x28 -#define PM_INFO_MX6Q_CCM_V_OFFSET 0x2C -#define PM_INFO_MX6Q_GPC_P_OFFSET 0x30 -#define PM_INFO_MX6Q_GPC_V_OFFSET 0x34 -#define PM_INFO_MX6Q_L2_P_OFFSET 0x38 -#define PM_INFO_MX6Q_L2_V_OFFSET 0x3C -#define PM_INFO_MMDC_IO_NUM_OFFSET 0x40 -#define PM_INFO_MMDC_IO_VAL_OFFSET 0x44 +#define PM_INFO_MX6Q_MMDC0_P_OFFSET 0x10 +#define PM_INFO_MX6Q_MMDC0_V_OFFSET 0x14 +#define PM_INFO_MX6Q_MMDC1_P_OFFSET 0x18 +#define PM_INFO_MX6Q_MMDC1_V_OFFSET 0x1C +#define PM_INFO_MX6Q_SRC_P_OFFSET 0x20 +#define PM_INFO_MX6Q_SRC_V_OFFSET 0x24 +#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x28 +#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x2C +#define PM_INFO_MX6Q_CCM_P_OFFSET 0x30 +#define PM_INFO_MX6Q_CCM_V_OFFSET 0x34 +#define PM_INFO_MX6Q_GPC_P_OFFSET 0x38 +#define PM_INFO_MX6Q_GPC_V_OFFSET 0x3C +#define PM_INFO_MX6Q_L2_P_OFFSET 0x40 +#define PM_INFO_MX6Q_L2_V_OFFSET 0x44 +#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x48 +#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x4C +#define PM_INFO_MX6Q_TTBR1_V_OFFSET 0x50 +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x54 +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x58 +/* below offsets depends on MX6_MAX_MMDC_IO_NUM(36) definition */ +#define PM_INFO_MMDC_NUM_OFFSET 0x208 +#define PM_INFO_MMDC_VAL_OFFSET 0x20C #define MX6Q_SRC_GPR1 0x20 #define MX6Q_SRC_GPR2 0x24 +#define MX6Q_MMDC_MISC 0x18 #define MX6Q_MMDC_MAPSR 0x404 #define MX6Q_MMDC_MPDGCTRL0 0x83c #define MX6Q_GPC_IMR1 0x08 @@ -65,9 +74,49 @@ #define MX6Q_GPC_IMR3 0x10 #define MX6Q_GPC_IMR4 0x14 #define MX6Q_CCM_CCR 0x0 +#define MX6Q_ANATOP_CORE 0x140 .align 3 + /* Check if the cpu is cortex-a7 */ + .macro is_cortex_a7 + + /* Read the primary cpu number is MPIDR */ + mrc p15, 0, r5, c0, c0, 0 + ldr r6, =0xfff0 + and r5, r5, r6 + ldr r6, =0xc070 + cmp r5, r6 + + .endm + + .macro disable_l1_cache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 -r10, lr} + ldr r7, = v7_flush_dcache_all + mov lr, pc + mov pc , r7 + pop {r0 -r10, lr} + + .endm + .macro sync_l2_cache /* sync L2 cache to drain L2's buffers to DRAM. */ @@ -86,29 +135,8 @@ .endm - .macro resume_mmdc - - /* restore MMDC IO */ - cmp r5, #0x0 - ldreq r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] - ldrne r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] - - ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] - ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET - add r7, r7, r0 -1: - ldr r8, [r7], #0x4 - ldr r9, [r7], #0x4 - str r9, [r11, r8] - subs r6, r6, #0x1 - bne 1b - - cmp r5, #0x0 - ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] - ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] - - cmp r3, #IMX_DDR_TYPE_LPDDR2 - bne 4f + /* r11 must be MMDC base address */ + .macro reset_read_fifo /* reset read FIFO, RST_RD_FIFO */ ldr r7, =MX6Q_MMDC_MPDGCTRL0 @@ -128,23 +156,294 @@ ldr r6, [r11, r7] ands r6, r6, #(1 << 31) bne 3b + + /* check if lppdr2 2 channel mode is enabled */ + ldr r7, =MX6Q_MMDC_MISC + ldr r6, [r11, r7] + ands r6, r6, #(1 << 2) + beq 6f + + ldr r7, =MX6Q_MMDC_MPDGCTRL0 + ldr r6, [r12, r7] + orr r6, r6, #(1 << 31) + str r6, [r12, r7] 4: + ldr r6, [r12, r7] + ands r6, r6, #(1 << 31) + bne 4b + + ldr r6, [r12, r7] + orr r6, r6, #(1 << 31) + str r6, [r12, r7] +5: + ldr r6, [r12, r7] + ands r6, r6, #(1 << 31) + bne 5b + +6: + .endm + + /* r11 must be MMDC base address */ + .macro mmdc_out_and_auto_self_refresh + /* let DDR out of self-refresh */ ldr r7, [r11, #MX6Q_MMDC_MAPSR] bic r7, r7, #(1 << 21) str r7, [r11, #MX6Q_MMDC_MAPSR] -5: +7: ldr r7, [r11, #MX6Q_MMDC_MAPSR] ands r7, r7, #(1 << 25) - bne 5b + bne 7b /* enable DDR auto power saving */ ldr r7, [r11, #MX6Q_MMDC_MAPSR] bic r7, r7, #0x1 str r7, [r11, #MX6Q_MMDC_MAPSR] + /* check if lppdr2 2 channel mode is enabled */ + ldr r7, =MX6Q_MMDC_MISC + ldr r6, [r11, r7] + ands r6, r6, #(1 << 2) + beq 9f + + ldr r7, [r12, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 21) + str r7, [r12, #MX6Q_MMDC_MAPSR] +8: + ldr r7, [r12, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + bne 8b + + ldr r7, [r12, #MX6Q_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r12, #MX6Q_MMDC_MAPSR] +9: + .endm + + /* r10 must be iomuxc base address */ + .macro resume_iomuxc_gpr + + add r10, r10, #0x4000 + /* IOMUXC GPR DRAM_RESET_BYPASS */ + ldr r4, [r10, #0x8] + bic r4, r4, #(0x1 << 27) + str r4, [r10, #0x8] + /* IOMUXC GPR DRAM_CKE_BYPASS */ + ldr r4, [r10, #0x8] + bic r4, r4, #(0x1 << 31) + str r4, [r10, #0x8] + + .endm + + .macro resume_io + + /* restore MMDC IO */ + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] + + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +10: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x8 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 10b + + cmp r5, #0x0 + /* Here only MMDC0 is set */ + ldreq r11, [r0, #PM_INFO_MX6Q_MMDC0_V_OFFSET] + ldrne r11, [r0, #PM_INFO_MX6Q_MMDC0_P_OFFSET] + ldreq r12, [r0, #PM_INFO_MX6Q_MMDC1_V_OFFSET] + ldrne r12, [r0, #PM_INFO_MX6Q_MMDC1_P_OFFSET] + + reset_read_fifo + mmdc_out_and_auto_self_refresh + + .endm + + .macro resume_mmdc_io + + cmp r5, #0x0 + ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] + ldreq r11, [r0, #PM_INFO_MX6Q_MMDC0_V_OFFSET] + ldrne r11, [r0, #PM_INFO_MX6Q_MMDC0_P_OFFSET] + + /* resume mmdc iomuxc settings */ + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +11: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x8 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 11b + + /* check whether we need to restore MMDC */ + cmp r5, #0x0 + beq 12f + + /* check whether last suspend is with M/F mix off */ + ldr r9, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] + ldr r6, [r9, #0x220] + cmp r6, #0x0 + bne 13f +12: + resume_iomuxc_gpr + reset_read_fifo + + b 17f +13: + /* restore MMDC settings */ + ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_VAL_OFFSET + add r7, r7, r0 +14: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r11, r8] + subs r6, r6, #0x1 + bne 14b + + /* let DDR enter self-refresh */ + ldr r7, [r11, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 20) + str r7, [r11, #MX6Q_MMDC_MAPSR] +15: + ldr r7, [r11, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + beq 15b + + resume_iomuxc_gpr + reset_read_fifo + + /* let DDR out of self-refresh */ + ldr r7, [r11, #MX6Q_MMDC_MAPSR] + bic r7, r7, #(1 << 20) + str r7, [r11, #MX6Q_MMDC_MAPSR] +16: + ldr r7, [r11, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + bne 16b + + /* kick off MMDC */ + ldr r4, =0x0 + str r4, [r11, #0x1c] + +17: + mmdc_out_and_auto_self_refresh + + .endm + + .macro store_ttbr1 + + /* Store TTBR1 to pm_info->ttbr1 */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r6, [r6] + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r6, c2, c0, 1 + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + is_cortex_a7 + beq 17f + +#ifdef CONFIG_CACHE_L2X0 + ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + mov r6, #0x0 + str r6, [r8, #0x100] + + dsb + isb +#endif +17: .endm + .macro restore_ttbr1 + + is_cortex_a7 + beq 18f + +#ifdef CONFIG_CACHE_L2X0 + /* Enable L2. */ + ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + ldr r7, =0x1 + str r7, [r8, #0x100] +#endif + +18: + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Restore TTBCR */ + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Restore TTBR1, get the origin ttbr1 from pm info */ + ldr r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + + ENTRY(imx6_suspend) ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] @@ -179,10 +478,25 @@ ENTRY(imx6_suspend) str r9, [r11, #MX6Q_SRC_GPR1] str r1, [r11, #MX6Q_SRC_GPR2] + /* + * Check if the cpu is Cortex-A7, for Cortex-A7 + * the cache implementation is not the same as + * Cortex-A9, so the cache maintenance operation + * is different. + */ + is_cortex_a7 + beq a7_dache_flush + /* need to sync L2 cache before DSM. */ sync_l2_cache - - ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] + b ttbr_store +a7_dache_flush: + disable_l1_cache +ttbr_store: + store_ttbr1 + + ldr r11, [r0, #PM_INFO_MX6Q_MMDC0_V_OFFSET] + ldr r12, [r0, #PM_INFO_MX6Q_MMDC1_V_OFFSET] /* * put DDR explicitly into self-refresh and * disable automatic power savings. @@ -201,31 +515,59 @@ poll_dvfs_set: ands r7, r7, #(1 << 25) beq poll_dvfs_set + /* check if lppdr2 2 channel mode is enabled */ + ldr r7, =MX6Q_MMDC_MISC + ldr r6, [r11, r7] + ands r6, r6, #(1 << 2) + beq skip_self_refresh_ch1 + + ldr r7, [r12, #MX6Q_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r12, #MX6Q_MMDC_MAPSR] + + ldr r7, [r12, #MX6Q_MMDC_MAPSR] + orr r7, r7, #(1 << 21) + str r7, [r12, #MX6Q_MMDC_MAPSR] + +poll_dvfs_set_ch1: + ldr r7, [r12, #MX6Q_MMDC_MAPSR] + ands r7, r7, #(1 << 25) + beq poll_dvfs_set_ch1 + +skip_self_refresh_ch1: + /* use r11 to store the IO address */ ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] - ldr r6, =0x0 - ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET add r8, r8, r0 - /* LPDDR2's last 3 IOs need special setting */ - cmp r3, #IMX_DDR_TYPE_LPDDR2 - subeq r7, r7, #0x3 set_mmdc_io_lpm: - ldr r9, [r8], #0x8 - str r6, [r11, r9] - subs r7, r7, #0x1 + ldr r7, [r8], #0x8 + ldr r9, [r8], #0x4 + str r9, [r11, r7] + subs r6, r6, #0x1 bne set_mmdc_io_lpm - cmp r3, #IMX_DDR_TYPE_LPDDR2 - bne set_mmdc_io_lpm_done - ldr r6, =0x1000 - ldr r9, [r8], #0x8 - str r6, [r11, r9] - ldr r9, [r8], #0x8 - str r6, [r11, r9] - ldr r6, =0x80000 - ldr r9, [r8] - str r6, [r11, r9] -set_mmdc_io_lpm_done: + /* check whether it supports Mega/Fast off */ + ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] + cmp r6, #0x0 + beq set_mmdc_lpm_done + + /* IOMUXC GPR DRAM_RESET */ + add r11, r11, #0x4000 + ldr r6, [r11, #0x8] + orr r6, r6, #(0x1 << 28) + str r6, [r11, #0x8] + + /* IOMUXC GPR DRAM_RESET_BYPASS */ + ldr r6, [r11, #0x8] + orr r6, r6, #(0x1 << 27) + str r6, [r11, #0x8] + + /* IOMUXC GPR DRAM_CKE_BYPASS */ + ldr r6, [r11, #0x8] + orr r6, r6, #(0x1 << 31) + str r6, [r11, #0x8] +set_mmdc_lpm_done: /* * mask all GPC interrupts before @@ -285,6 +627,27 @@ rbc_loop: subs r6, r6, #0x1 bne rbc_loop + /* + * ERR005852 Analog: Transition from Deep Sleep Mode to + * LDO Bypass Mode may cause the slow response of the + * VDDARM_CAP output. + * + * Software workaround: + * if internal ldo(VDDARM) bypassed, switch to analog bypass + * mode (0x1E), prio to entering DSM, and then, revert to the + * normal bypass mode, when exiting from DSM. + */ + ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] + ldr r10, [r11, #MX6Q_ANATOP_CORE] + and r10, r10, #0x1f + cmp r10, #0x1f + bne ldo_check_done1 +ldo_analog_bypass: + ldr r10, [r11, #MX6Q_ANATOP_CORE] + bic r10, r10, #0x1f + orr r10, r10, #0x1e + str r10, [r11, #MX6Q_ANATOP_CORE] +ldo_check_done1: /* Zzz, enter stop mode */ wfi nop @@ -297,8 +660,28 @@ rbc_loop: * wakeup source, system should auto * resume, we need to restore MMDC IO first */ + /* restore it with 0x1f if use ldo bypass mode.*/ + ldr r10, [r11, #MX6Q_ANATOP_CORE] + and r10, r10, #0x1f + cmp r10, #0x1e + bne ldo_check_done2 +ldo_bypass_restore: + ldr r10, [r11, #MX6Q_ANATOP_CORE] + orr r10, r10, #0x1f + str r10, [r11, #MX6Q_ANATOP_CORE] +ldo_check_done2: mov r5, #0x0 - resume_mmdc + /* check whether it supports Mega/Fast off */ + ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] + cmp r6, #0x0 + beq only_resume_io + resume_mmdc_io + b resume_mmdc_done +only_resume_io: + resume_io +resume_mmdc_done: + + restore_ttbr1 /* return to suspend finish */ ret lr @@ -313,6 +696,16 @@ resume: mcr p15, 0, r6, c1, c0, 0 isb + /* restore it with 0x1f if use ldo bypass mode.*/ + ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] + ldr r7, [r11, #MX6Q_ANATOP_CORE] + and r7, r7, #0x1f + cmp r7, #0x1e + bne ldo_check_done3 + ldr r7, [r11, #MX6Q_ANATOP_CORE] + orr r7, r7, #0x1f + str r7, [r11, #MX6Q_ANATOP_CORE] +ldo_check_done3: /* get physical resume address from pm_info. */ ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] /* clear core0's entry and parameter */ @@ -323,7 +716,16 @@ resume: ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] mov r5, #0x1 - resume_mmdc + /* check whether it supports Mega/Fast off */ + ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] + cmp r6, #0x0 + beq dsm_only_resume_io + resume_mmdc_io + b dsm_resume_mmdc_done +dsm_only_resume_io: + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] + resume_io +dsm_resume_mmdc_done: ret lr ENDPROC(imx6_suspend) diff --git a/arch/arm/mach-imx/suspend-imx7.S b/arch/arm/mach-imx/suspend-imx7.S new file mode 100644 index 000000000000..1fb9333ad5b4 --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx7.S @@ -0,0 +1,713 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * 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/asm-offsets.h> +#include "hardware.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 ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx7_suspend code + * PM_INFO structure(imx7_cpu_pm_info) + * ======================== low address ======================= + */ + +/* + * Below offsets are based on struct imx7_cpu_pm_info + * which defined in arch/arm/mach-imx/pm-imx7.c, this + * structure contains necessary pm info for low level + * suspend related code. + */ +#define PM_INFO_M4_RESERVE0_OFFSET 0x0 +#define PM_INFO_M4_RESERVE1_OFFSET 0x4 +#define PM_INFO_M4_RESERVE2_OFFSET 0x8 +#define PM_INFO_PBASE_OFFSET 0xc +#define PM_INFO_RESUME_ADDR_OFFSET 0x10 +#define PM_INFO_DDR_TYPE_OFFSET 0x14 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x18 +#define PM_INFO_MX7_DDRC_P_OFFSET 0x1c +#define PM_INFO_MX7_DDRC_V_OFFSET 0x20 +#define PM_INFO_MX7_DDRC_PHY_P_OFFSET 0x24 +#define PM_INFO_MX7_DDRC_PHY_V_OFFSET 0x28 +#define PM_INFO_MX7_SRC_P_OFFSET 0x2c +#define PM_INFO_MX7_SRC_V_OFFSET 0x30 +#define PM_INFO_MX7_IOMUXC_GPR_P_OFFSET 0x34 +#define PM_INFO_MX7_IOMUXC_GPR_V_OFFSET 0x38 +#define PM_INFO_MX7_CCM_P_OFFSET 0x3c +#define PM_INFO_MX7_CCM_V_OFFSET 0x40 +#define PM_INFO_MX7_GPC_P_OFFSET 0x44 +#define PM_INFO_MX7_GPC_V_OFFSET 0x48 +#define PM_INFO_MX7_SNVS_P_OFFSET 0x4c +#define PM_INFO_MX7_SNVS_V_OFFSET 0x50 +#define PM_INFO_MX7_ANATOP_P_OFFSET 0x54 +#define PM_INFO_MX7_ANATOP_V_OFFSET 0x58 +#define PM_INFO_MX7_LPSR_P_OFFSET 0x5c +#define PM_INFO_MX7_LPSR_V_OFFSET 0x60 +#define PM_INFO_MX7_GIC_DIST_P_OFFSET 0x64 +#define PM_INFO_MX7_GIC_DIST_V_OFFSET 0x68 +#define PM_INFO_MX7_TTBR1_V_OFFSET 0x6c +#define PM_INFO_DDRC_REG_NUM_OFFSET 0x70 +#define PM_INFO_DDRC_REG_OFFSET 0x74 +#define PM_INFO_DDRC_VALUE_OFFSET 0x78 +#define PM_INFO_DDRC_PHY_REG_NUM_OFFSET 0x174 +#define PM_INFO_DDRC_PHY_REG_OFFSET 0x178 +#define PM_INFO_DDRC_PHY_VALUE_OFFSET 0x17c + +#define MX7_SRC_GPR1 0x74 +#define MX7_SRC_GPR2 0x78 +#define GPC_PGC_C0 0x800 +#define GPC_PGC_FM 0xa00 +#define ANADIG_SNVS_MISC_CTRL 0x380 +#define ANADIG_SNVS_MISC_CTRL_SET 0x384 +#define ANADIG_SNVS_MISC_CTRL_CLR 0x388 +#define ANADIG_DIGPROG 0x800 +#define DDRC_STAT 0x4 +#define DDRC_PWRCTL 0x30 +#define DDRC_PSTAT 0x3fc +#define DDRC_PCTRL_0 0x490 +#define DDRC_DFIMISC 0x1b0 +#define DDRC_SWCTL 0x320 +#define DDRC_SWSTAT 0x324 +#define DDRPHY_LP_CON0 0x18 + +#define CCM_SNVS_LPCG 0x250 +#define MX7D_GPC_IMR1 0x30 +#define MX7D_GPC_IMR2 0x34 +#define MX7D_GPC_IMR3 0x38 +#define MX7D_GPC_IMR4 0x3c + + .align 3 + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro store_ttbr1 + + /* Store TTBR1 to pm_info->ttbr1 */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_MX7_TTBR1_V_OFFSET] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r6, [r6] + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r6, c2, c0, 1 + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro restore_ttbr1 + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Restore TTBCR */ + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Restore TTBR1, get the origin ttbr1 from pm info */ + ldr r7, [r0, #PM_INFO_MX7_TTBR1_V_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + + .macro ddrc_enter_self_refresh + + ldr r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r11, #DDRC_PWRCTL] + + /* wait rw port_busy clear */ + ldr r6, =(0x1 << 16) + orr r6, r6, #0x1 +1: + ldr r7, [r11, #DDRC_PSTAT] + ands r7, r7, r6 + bne 1b + + /* enter self-refresh bit 5 */ + ldr r7, =(0x1 << 5) + str r7, [r11, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +2: + ldr r7, [r11, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 2b +3: + ldr r7, [r11, #DDRC_STAT] + ands r7, r7, #0x20 + beq 3b + + /* disable dram clk */ + ldr r7, [r11, #DDRC_PWRCTL] + orr r7, r7, #(1 << 3) + str r7, [r11, #DDRC_PWRCTL] + + .endm + + .macro ddrc_exit_self_refresh + + cmp r5, #0x0 + ldreq r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + ldrne r11, [r0, #PM_INFO_MX7_DDRC_P_OFFSET] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r11, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +4: + ldr r7, [r11, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + beq 4b + + /* enable auto self-refresh */ + ldr r7, [r11, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r11, #DDRC_PWRCTL] + + .endm + + .macro wait_delay +5: + subs r6, r6, #0x1 + bne 5b + + .endm + + .macro ddr_enter_retention + + ldr r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r11, #DDRC_PCTRL_0] + + /* wait rw port_busy clear */ + ldr r6, =(0x1 << 16) + orr r6, r6, #0x1 +6: + ldr r7, [r11, #DDRC_PSTAT] + ands r7, r7, r6 + bne 6b + + ldr r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + /* enter self-refresh bit 5 */ + ldr r7, =(0x1 << 5) + str r7, [r11, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +7: + ldr r7, [r11, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 7b +8: + ldr r7, [r11, #DDRC_STAT] + ands r7, r7, #0x20 + beq 8b + + /* disable dram clk */ + ldr r7, =(0x1 << 5) + orr r7, r7, #(1 << 3) + str r7, [r11, #DDRC_PWRCTL] + + ldr r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldr r7, [r11, #ANADIG_DIGPROG] + and r7, r7, #0xff + cmp r7, #0x11 + bne 10f + + /* TO 1.1 */ + ldr r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_V_OFFSET] + ldr r7, =0x38000000 + str r7, [r11] + + /* LPSR mode need to use TO1.0 flow as IOMUX lost power */ + ldr r10, [r0, #PM_INFO_MX7_LPSR_V_OFFSET] + ldr r7, [r10] + cmp r7, #0x0 + beq 11f +10: + /* reset ddr_phy */ + ldr r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldr r7, =0x0 + str r7, [r11, #ANADIG_SNVS_MISC_CTRL] + + /* delay 7 us */ + ldr r6, =6000 + wait_delay + + ldr r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + ldr r6, =0x1000 + ldr r7, [r11, r6] + orr r7, r7, #0x1 + str r7, [r11, r6] +11: + /* turn off ddr power */ + ldr r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldr r7, =(0x1 << 29) + str r7, [r11, #ANADIG_SNVS_MISC_CTRL_SET] + + ldr r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + ldr r6, =0x1000 + ldr r7, [r11, r6] + orr r7, r7, #0x1 + str r7, [r11, r6] + + .endm + + .macro ddr_exit_retention + + cmp r5, #0x0 + ldreq r1, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldrne r1, [r0, #PM_INFO_MX7_ANATOP_P_OFFSET] + ldreq r2, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + ldrne r2, [r0, #PM_INFO_MX7_SRC_P_OFFSET] + ldreq r3, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + ldrne r3, [r0, #PM_INFO_MX7_DDRC_P_OFFSET] + ldreq r4, [r0, #PM_INFO_MX7_DDRC_PHY_V_OFFSET] + ldrne r4, [r0, #PM_INFO_MX7_DDRC_PHY_P_OFFSET] + ldreq r10, [r0, #PM_INFO_MX7_CCM_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7_CCM_P_OFFSET] + ldreq r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_V_OFFSET] + ldrne r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_P_OFFSET] + + /* turn on ddr power */ + ldr r7, =(0x1 << 29) + str r7, [r1, #ANADIG_SNVS_MISC_CTRL_CLR] + + ldr r6, =50 + wait_delay + + /* clear ddr_phy reset */ + ldr r6, =0x1000 + ldr r7, [r2, r6] + orr r7, r7, #0x3 + str r7, [r2, r6] + ldr r7, [r2, r6] + bic r7, r7, #0x1 + str r7, [r2, r6] +13: + ldr r6, [r0, #PM_INFO_DDRC_REG_NUM_OFFSET] + ldr r7, =PM_INFO_DDRC_REG_OFFSET + add r7, r7, r0 +14: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r3, r8] + subs r6, r6, #0x1 + bne 14b + ldr r7, =0x20 + str r7, [r3, #DDRC_PWRCTL] + ldr r7, =0x0 + str r7, [r3, #DDRC_DFIMISC] + + /* do PHY, clear ddr_phy reset */ + ldr r6, =0x1000 + ldr r7, [r2, r6] + bic r7, r7, #0x2 + str r7, [r2, r6] + + ldr r7, [r1, #ANADIG_DIGPROG] + and r7, r7, #0xff + cmp r7, #0x11 + bne 12f + + /* + * TKT262940: + * System hang when press RST for DDR PAD is + * in retention mode, fixed on TO1.1 + */ + ldr r7, [r11] + bic r7, r7, #(1 << 27) + str r7, [r11] + ldr r7, [r11] + bic r7, r7, #(1 << 29) + str r7, [r11] +12: + ldr r7, =(0x1 << 30) + str r7, [r1, #ANADIG_SNVS_MISC_CTRL_SET] + + /* need to delay ~5mS */ + ldr r6, =0x100000 + wait_delay + + ldr r6, [r0, #PM_INFO_DDRC_PHY_REG_NUM_OFFSET] + ldr r7, =PM_INFO_DDRC_PHY_REG_OFFSET + add r7, r7, r0 + +15: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r4, r8] + subs r6, r6, #0x1 + bne 15b + + ldr r7, =0x0 + add r9, r10, #0x4000 + str r7, [r9, #0x130] + + ldr r7, =0x170 + orr r7, r7, #0x8 + str r7, [r11, #0x20] + + ldr r7, =0x2 + add r9, r10, #0x4000 + str r7, [r9, #0x130] + + ldr r7, =0xf + str r7, [r4, #DDRPHY_LP_CON0] + + /* wait until self-refresh mode entered */ +16: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 16b + ldr r7, =0x0 + str r7, [r3, #DDRC_SWCTL] + ldr r7, =0x1 + str r7, [r3, #DDRC_DFIMISC] + ldr r7, =0x1 + str r7, [r3, #DDRC_SWCTL] +17: + ldr r7, [r3, #DDRC_SWSTAT] + and r7, r7, #0x1 + cmp r7, #0x1 + bne 17b +18: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x20 + cmp r7, #0x20 + bne 18b + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r3, #DDRC_PWRCTL] +19: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x30 + cmp r7, #0x0 + bne 19b + +20: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x1 + bne 20b + + /* enable port */ + ldr r7, =0x1 + str r7, [r3, #DDRC_PCTRL_0] + + /* enable auto self-refresh */ + ldr r7, [r3, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r3, #DDRC_PWRCTL] + + .endm + +ENTRY(imx7_suspend) + push {r4-r12} + + /* make sure SNVS clk is enabled */ + ldr r11, [r0, #PM_INFO_MX7_CCM_V_OFFSET] + add r11, r11, #0x4000 + ldr r7, =0x3 + str r7, [r11, #CCM_SNVS_LPCG] + + /* check whether it is a standby mode */ + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_C0] + cmp r7, #0 + beq ddr_only_self_refresh + + /* + * The value of r0 is mapped the same in origin table and IRAM table, + * thus no need to care r0 here. + */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] + ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r6, =imx7_suspend + ldr r7, =resume + sub r7, r7, r6 + add r8, r1, r4 + add r9, r8, r7 + + ldr r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + /* store physical resume addr and pm_info address. */ + str r9, [r11, #MX7_SRC_GPR1] + str r1, [r11, #MX7_SRC_GPR2] + + disable_l1_dcache + + store_ttbr1 + + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_FM] + cmp r7, #0 + beq ddr_only_self_refresh + + ddr_enter_retention + /* enter LPSR mode if resume addr is valid */ + ldr r11, [r0, #PM_INFO_MX7_LPSR_V_OFFSET] + ldr r7, [r11] + cmp r7, #0x0 + beq ddr_retention_enter_out + + /* disable STOP mode before entering LPSR */ + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11] + bic r7, #0xf + str r7, [r11] + + /* shut down vddsoc to enter lpsr mode */ + ldr r11, [r0, #PM_INFO_MX7_SNVS_V_OFFSET] + ldr r7, [r11, #0x38] + orr r7, r7, #0x60 + str r7, [r11, #0x38] +wait_shutdown: + wfi + nop + nop + nop + nop + b wait_shutdown + +ddr_only_self_refresh: + ddrc_enter_self_refresh + b wfi +ddr_retention_enter_out: + + ldr r11, [r0, #PM_INFO_MX7_GIC_DIST_V_OFFSET] + ldr r7, =0x0 + ldr r8, =0x1000 + str r7, [r11, r8] + + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r4, [r11, #MX7D_GPC_IMR1] + ldr r5, [r11, #MX7D_GPC_IMR2] + ldr r6, [r11, #MX7D_GPC_IMR3] + ldr r7, [r11, #MX7D_GPC_IMR4] + + ldr r8, =0xffffffff + str r8, [r11, #MX7D_GPC_IMR1] + str r8, [r11, #MX7D_GPC_IMR2] + str r8, [r11, #MX7D_GPC_IMR3] + str r8, [r11, #MX7D_GPC_IMR4] + + /* + * enable the RBC bypass counter here + * to hold off the interrupts. RBC counter + * = 0x3f (2ms). With this setting, the latency + * from wakeup interrupt to ARM power up + * is ~2ms. + */ + ldr r8, [r11, #0x14] + orr r8, r8, #(0x3f << 24) + str r8, [r11, #0x14] + + /* enable the counter. */ + ldr r8, [r11, #0x14] + orr r8, r8, #(0x1 << 30) + str r8, [r11, #0x14] + + /* unmask all the GPC interrupts. */ + str r4, [r11, #MX7D_GPC_IMR1] + str r5, [r11, #MX7D_GPC_IMR2] + str r6, [r11, #MX7D_GPC_IMR3] + str r7, [r11, #MX7D_GPC_IMR4] + + /* + * now delay for a short while (3usec) + * ARM is at 1GHz at this point + * so a short loop should be enough. + * this delay is required to ensure that + * the RBC counter can start counting in + * case an interrupt is already pending + * or in case an interrupt arrives just + * as ARM is about to assert DSM_request. + */ + ldr r7, =2000 +rbc_loop: + subs r7, r7, #0x1 + bne rbc_loop +wfi: + /* Zzz, enter stop mode */ + wfi + nop + nop + nop + nop + + mov r5, #0x0 + + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_FM] + cmp r7, #0 + beq wfi_ddr_self_refresh_out + + ddr_exit_retention + b wfi_ddr_retention_out +wfi_ddr_self_refresh_out: + ddrc_exit_self_refresh +wfi_ddr_retention_out: + + /* check whether it is a standby mode */ + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_C0] + cmp r7, #0 + beq standby_out + + ldr r11, [r0, #PM_INFO_MX7_GIC_DIST_V_OFFSET] + ldr r7, =0x1 + ldr r8, =0x1000 + str r7, [r11, r8] + + restore_ttbr1 +standby_out: + pop {r4-r12} + /* return to suspend finish */ + mov pc, lr + +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 + + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + /* clear core0's entry and parameter */ + ldr r11, [r0, #PM_INFO_MX7_SRC_P_OFFSET] + mov r7, #0x0 + str r7, [r11, #MX7_SRC_GPR1] + str r7, [r11, #MX7_SRC_GPR2] + + mov r5, #0x1 + + ldr r11, [r0, #PM_INFO_MX7_GPC_P_OFFSET] + ldr r7, [r11, #GPC_PGC_FM] + cmp r7, #0 + beq dsm_ddr_self_refresh_out + + ddr_exit_retention + b dsm_ddr_retention_out +dsm_ddr_self_refresh_out: + ddrc_exit_self_refresh +dsm_ddr_retention_out: + + mov pc, lr +ENDPROC(imx7_suspend) + +ENTRY(ca7_cpu_resume) + bl v7_invalidate_l1 + b cpu_resume +ENDPROC(ca7_cpu_resume) diff --git a/arch/arm/mach-imx/suspend-imx7ulp.S b/arch/arm/mach-imx/suspend-imx7ulp.S new file mode 100644 index 000000000000..bd45e460f75f --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx7ulp.S @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * 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/asm-offsets.h> +#include "hardware.h" + +/* + * ==================== low level suspend ==================== + * + * Better to follow below rules to use ARM registers: + * r0: pm_info structure address; + * + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx7ulp_suspend code + * PM_INFO structure(imx7ulp_cpu_pm_info) + * ======================== low address ======================= + */ + +/* + * Below offsets are based on struct imx7ulp_cpu_pm_info + * which defined in arch/arm/mach-imx/pm-imx7ulp.c, this + * structure contains necessary pm info for low level + * suspend related code. + */ +#define PM_INFO_M4_RESERVE0_OFFSET 0x0 +#define PM_INFO_M4_RESERVE1_OFFSET 0x4 +#define PM_INFO_M4_RESERVE2_OFFSET 0x8 +#define PM_INFO_PBASE_OFFSET 0xc +#define PM_INFO_RESUME_ADDR_OFFSET 0x10 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x14 +#define PM_INFO_PM_INFO_SIM_VBASE_OFFSET 0x18 +#define PM_INFO_PM_INFO_SCG1_VBASE_OFFSET 0x1c +#define PM_INFO_PM_INFO_MMDC_VBASE_OFFSET 0x20 +#define PM_INFO_PM_INFO_MMDC_IO_VBASE_OFFSET 0x24 +#define PM_INFO_PM_INFO_SMC1_VBASE_OFFSET 0x28 +#define PM_INFO_PM_INFO_SCG1_VAL_OFFSET 0x2c +#define PM_INFO_MX7ULP_TTBR1_V_OFFSET 0x70 +#define PM_INFO_MX7ULP_GPIO_REG_OFFSET 0x74 +#define PM_INFO_IOMUX_NUM_OFFSET 0x94 +#define PM_INFO_IOMUX_VAL_OFFSET 0x98 +#define PM_INFO_SELECT_INPUT_NUM_OFFSET 0x268 +#define PM_INFO_SELECT_INPUT_VAL_OFFSET 0x26c +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x3a4 +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x3a8 +/* below offsets depends on MX7ULP_MAX_MMDC_IO_NUM(36) definition */ +#define PM_INFO_MMDC_NUM_OFFSET 0x5a8 +#define PM_INFO_MMDC_VAL_OFFSET 0x5ac + +#define DGO_CTRL0 0x50 +#define DGO_GPR3 0x60 +#define DGO_GPR4 0x64 + +#define MX7ULP_MMDC_MISC 0x18 +#define MX7ULP_MMDC_MAPSR 0x404 +#define MX7ULP_MMDC_MPDGCTRL0 0x83c + +#define SCG_RCCR 0x14 +#define SCG_DDRCCR 0x30 +#define SCG_NICCCR 0x40 +#define SCG_FIRCDIV 0x304 +#define SCG_APLLCSR 0x500 +#define SCG_APLLDIV 0x504 +#define SCG_APLLCFG 0x508 +#define SCG_APLLPFD 0x50c +#define SCG_APLLNUM 0x510 +#define SCG_APLLDENOM 0x514 +#define SCG_SPLLCSR 0x600 +#define SCG_SPLLDIV 0x604 +#define SCG_SPLLCFG 0x608 +#define SCG_SPLLPFD 0x60c +#define SCG_SPLLNUM 0x610 +#define SCG_SPLLDENOM 0x614 +#define SCG_SOSCDIV 0x104 + +#define PMC1_CTRL 0x24 + +#define GPIO_PDOR 0x0 +#define GPIO_PDDR 0x14 +#define GPIO_PORT_NUM 0x4 +#define GPIO_PORT_OFFSET 0x40 + +#define PMCTRL 0x10 + +#define IOMUX_OFFSET 0x0 +#define SELECT_INPUT_OFFSET 0x200 + + .align 3 + + .macro store_ttbr1 + + /* Store TTBR1 to pm_info->ttbr1 */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_MX7ULP_TTBR1_V_OFFSET] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r6, [r6] + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r6, c2, c0, 1 + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro restore_ttbr1 + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Restore TTBCR */ + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Restore TTBR1, get the origin ttbr1 from pm info */ + ldr r7, [r0, #PM_INFO_MX7ULP_TTBR1_V_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro restore_mmdc_settings + + ldr r10, =MX7ULP_MMDC_IO_BASE_ADDR + ldr r11, =MX7ULP_MMDC_BASE_ADDR + + /* resume mmdc iomuxc settings */ + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +11: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r10, r8] + subs r6, r6, #0x1 + bne 11b + + /* restore MMDC settings */ + ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_VAL_OFFSET + add r7, r7, r0 +1: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r11, r8] + subs r6, r6, #0x1 + bne 1b + + /* let DDR enter self-refresh */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + orr r7, r7, #(1 << 20) + str r7, [r11, #MX7ULP_MMDC_MAPSR] +2: + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + beq 2b + + /* let DDR out of self-refresh */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + bic r7, r7, #(1 << 20) + str r7, [r11, #MX7ULP_MMDC_MAPSR] +3: + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + bne 3b + + /* kick off MMDC */ + ldr r4, =0x0 + str r4, [r11, #0x1c] + + /* let DDR out of self-refresh */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + bic r7, r7, #(1 << 20) + str r7, [r11, #MX7ULP_MMDC_MAPSR] +4: + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + bne 4b + + /* enable DDR auto power saving */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r11, #MX7ULP_MMDC_MAPSR] + + .endm + +ENTRY(imx7ulp_suspend) + push {r4-r12} + + /* + * The value of r0 is mapped the same in origin table and IRAM table, + * thus no need to care r0 here. + */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + ldr r3, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r6, =imx7ulp_suspend + ldr r7, =resume + sub r7, r7, r6 + add r8, r1, r3 + add r9, r8, r7 + + ldr r11, [r0, #PM_INFO_PM_INFO_SIM_VBASE_OFFSET] + /* store physical resume addr and pm_info address. */ + str r9, [r11, #DGO_GPR3] + str r1, [r11, #DGO_GPR4] + ldr r7, [r11, #DGO_CTRL0] + orr r7, r7, #0xc + str r7, [r11, #DGO_CTRL0] +wait_dgo: + ldr r7, [r11, #DGO_CTRL0] + and r7, r7, #0x18000 + cmp r7, #0x18000 + bne wait_dgo + + ldr r7, [r11, #DGO_CTRL0] + orr r7, r7, #0x18000 + bic r7, r7, #0xc + str r7, [r11, #DGO_CTRL0] + + disable_l1_dcache + + store_ttbr1 + + ldr r11, [r0, #PM_INFO_PM_INFO_MMDC_VBASE_OFFSET] + + /* + * put DDR explicitly into self-refresh and + * disable automatic power savings. + */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + orr r7, r7, #0x1 + str r7, [r11, #MX7ULP_MMDC_MAPSR] + + /* make the DDR explicitly enter self-refresh. */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + orr r7, r7, #(1 << 20) + str r7, [r11, #MX7ULP_MMDC_MAPSR] + +poll_dvfs_set: + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + beq poll_dvfs_set + + /* put mmdc io into lpm */ + ldr r11, [r0, #PM_INFO_PM_INFO_MMDC_IO_VBASE_OFFSET] + ldr r10, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +mmdc_io_lpm: + ldr r8, [r7], #0x8 + mov r9, #0x0 + str r9, [r11, r8] + subs r10, r10, #0x1 + bne mmdc_io_lpm + + /* switch NIC clock to FIRC */ + ldr r10, [r0, #PM_INFO_PM_INFO_SCG1_VBASE_OFFSET] + ldr r7, [r10, #SCG_NICCCR] + bic r7, #(1 << 28) + str r7, [r10, #SCG_NICCCR] + + /* switch RUN clock to FIRC */ + ldr r7, [r10, #SCG_RCCR] + bic r7, #(0xf << 24) + orr r7, #(0x3 << 24) + str r7, [r10, #SCG_RCCR] + + /* turn off SPLL and SPFD */ + ldr r7, [r10, #SCG_SPLLPFD] + mov r8, r7 + orr r7, r7, #(0x1 << 31) + orr r7, r7, #(0x1 << 23) + orr r7, r7, #(0x1 << 15) + orr r7, r7, #(0x1 << 7) + str r7, [r10, #SCG_SPLLPFD] + + ldr r7, [r10, #SCG_SPLLCSR] + bic r7, r7, #0x1 + str r7, [r10, #SCG_SPLLCSR] + + /* turn off APLL and APFD */ + ldr r7, [r10, #SCG_APLLPFD] + mov r9, r7 + orr r7, r7, #(0x1 << 31) + orr r7, r7, #(0x1 << 23) + orr r7, r7, #(0x1 << 15) + orr r7, r7, #(0x1 << 7) + str r7, [r10, #SCG_APLLPFD] + + ldr r7, [r10, #SCG_APLLCSR] + bic r7, r7, #0x1 + str r7, [r10, #SCG_APLLCSR] + + /* Zzz, enter stop mode */ + wfi + nop + nop + nop + nop + + /* clear core0's entry and parameter */ + ldr r10, [r0, #PM_INFO_PM_INFO_SIM_VBASE_OFFSET] + mov r7, #0x0 + str r7, [r10, #DGO_GPR3] + str r7, [r10, #DGO_GPR4] + + /* enable SPLL and SPFD */ + ldr r10, [r0, #PM_INFO_PM_INFO_SCG1_VBASE_OFFSET] + ldr r7, [r10, #SCG_SPLLCSR] + orr r7, r7, #1 + str r7, [r10, #SCG_SPLLCSR] +wait_spll: + ldr r7, [r10, #SCG_SPLLCSR] + ands r7, r7, #(1 << 24) + beq wait_spll + + str r8, [r10, #SCG_SPLLPFD] + /* switch RUN clock to SPLL */ + ldr r7, [r10, #SCG_RCCR] + bic r7, #(0xf << 24) + orr r7, #(0x6 << 24) + str r7, [r10, #SCG_RCCR] + + /* enable APLL and APFD */ + ldr r7, [r10, #SCG_APLLCSR] + orr r7, r7, #1 + str r7, [r10, #SCG_APLLCSR] +wait_apll: + ldr r7, [r10, #SCG_APLLCSR] + ands r7, r7, #(1 << 24) + beq wait_apll + + str r9, [r10, #SCG_APLLPFD] + + /* switch NIC clock to DDR */ + ldr r7, [r10, #SCG_NICCCR] + orr r7, #(1 << 28) + str r7, [r10, #SCG_NICCCR] + + /* let mmdc io out of lpm */ + ldr r11, [r0, #PM_INFO_PM_INFO_MMDC_IO_VBASE_OFFSET] + ldr r10, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET + add r7, r7, r0 +mmdc_io_exit_lpm: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r11, r8] + subs r10, r10, #0x1 + bne mmdc_io_exit_lpm + + /* let DDR out of self-refresh */ + ldr r11, [r0, #PM_INFO_PM_INFO_MMDC_VBASE_OFFSET] + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + bic r7, r7, #(1 << 20) + str r7, [r11, #MX7ULP_MMDC_MAPSR] +poll_dvfs_clear: + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + ands r7, r7, #(1 << 24) + bne poll_dvfs_clear + + /* enable DDR auto power saving */ + ldr r7, [r11, #MX7ULP_MMDC_MAPSR] + bic r7, r7, #0x1 + str r7, [r11, #MX7ULP_MMDC_MAPSR] + + restore_ttbr1 + pop {r4-r12} + /* return to suspend finish */ + mov pc, lr + +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 r6, =MX7ULP_SIM_BASE_ADDR + ldr r0, [r6, #DGO_GPR4] + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + + ldr r11, =MX7ULP_SCG1_BASE_ADDR + /* enable spll and pfd0 */ + ldr r5, =PM_INFO_PM_INFO_SCG1_VAL_OFFSET + add r6, r5, #48 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SPLLCFG] + + add r6, r5, #56 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SPLLNUM] + + add r6, r5, #60 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SPLLDENOM] + + add r6, r5, #40 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SPLLCSR] +5: + ldr r7, [r11, #SCG_SPLLCSR] + ands r7, r7, #0x1000000 + beq 5b + + add r6, r5, #44 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SPLLDIV] + + add r6, r5, #52 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SPLLPFD] + + add r6, r5, #0 + ldr r7, [r0, r6] + str r7, [r11, #SCG_RCCR] + + /* enable apll and pfd0 */ + add r6, r5, #24 + ldr r7, [r0, r6] + str r7, [r11, #SCG_APLLCFG] + + add r6, r5, #32 + ldr r7, [r0, r6] + str r7, [r11, #SCG_APLLNUM] + + add r6, r5, #36 + ldr r7, [r0, r6] + str r7, [r11, #SCG_APLLDENOM] + + add r6, r5, #16 + ldr r7, [r0, r6] + str r7, [r11, #SCG_APLLCSR] +6: + ldr r7, [r11, #SCG_APLLCSR] + ands r7, r7, #0x1000000 + beq 6b + + add r6, r5, #20 + ldr r7, [r0, r6] + str r7, [r11, #SCG_APLLDIV] + + add r6, r5, #28 + ldr r7, [r0, r6] + str r7, [r11, #SCG_APLLPFD] + + /* set ddr ccr */ + add r6, r5, #4 + ldr r7, [r0, r6] + str r7, [r11, #SCG_DDRCCR] + + /* set nic sel */ + add r6, r5, #8 + ldr r7, [r0, r6] + str r7, [r11, #SCG_NICCCR] + + /* set firc div2 to get 48MHz */ + add r6, r5, #12 + ldr r7, [r0, r6] + str r7, [r11, #SCG_FIRCDIV] + + /* restore system OSC div */ + add r6, r5, #64 + ldr r7, [r0, r6] + str r7, [r11, #SCG_SOSCDIV] + + /* enable mmdc clock in pcc3 */ + ldr r11, =MX7ULP_PCC3_BASE_ADDR + ldr r7, [r11, #0xac] + orr r7, r7, #(1 << 30) + str r7, [r11, #0xac] + + /* enable GPIO clock in pcc2 */ + ldr r11, =MX7ULP_PCC2_BASE_ADDR + ldr r7, [r11, #0x3c] + orr r7, r7, #(1 << 30) + str r7, [r11, #0x3c] + + /* restore gpio settings */ + ldr r10, =MX7ULP_GPIOC_BASE_ADDR + ldr r7, =PM_INFO_MX7ULP_GPIO_REG_OFFSET + add r7, r7, r0 + ldr r6, =GPIO_PORT_NUM +12: + ldr r9, [r7], #0x4 + str r9, [r10, #GPIO_PDOR] + ldr r9, [r7], #0x4 + str r9, [r10, #GPIO_PDDR] + add r10, r10, #GPIO_PORT_OFFSET + subs r6, r6, #0x1 + bne 12b + + /* restore iomuxc settings */ + ldr r10, =MX7ULP_IOMUXC1_BASE_ADDR + add r10, r10, #IOMUX_OFFSET + ldr r6, [r0, #PM_INFO_IOMUX_NUM_OFFSET] + ldr r7, =PM_INFO_IOMUX_VAL_OFFSET + add r7, r7, r0 +13: + ldr r9, [r7], #0x4 + str r9, [r10], #0x4 + subs r6, r6, #0x1 + bne 13b + + /* restore select input settings */ + ldr r10, =MX7ULP_IOMUXC1_BASE_ADDR + add r10, r10, #SELECT_INPUT_OFFSET + ldr r6, [r0, #PM_INFO_SELECT_INPUT_NUM_OFFSET] + ldr r7, =PM_INFO_SELECT_INPUT_VAL_OFFSET + add r7, r7, r0 +14: + ldr r9, [r7], #0x4 + str r9, [r10], #0x4 + subs r6, r6, #0x1 + bne 14b + + /* isoack */ + ldr r6, =MX7ULP_PMC1_BASE_ADDR + ldr r7, [r6, #PMC1_CTRL] + orr r7, r7, #(1 << 14) + str r7, [r6, #PMC1_CTRL] + + restore_mmdc_settings + + mov pc, lr +ENDPROC(imx7ulp_suspend) + +ENTRY(imx7ulp_cpu_resume) + bl v7_invalidate_l1 + b cpu_resume +ENDPROC(imx7ulp_cpu_resume) diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 12c26eb88afb..bc632a3ed9b5 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -867,6 +867,11 @@ static int __init __l2c_init(const struct l2c_init_data *data, l2x0_saved_regs.aux_ctrl = aux; data->enable(l2x0_base, data->num_lock); + } else { + pr_info("%s cache controller enabled try to unlock\n", + data->type); + + data->unlock(l2x0_base, data->num_lock); } outer_cache = fns; diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 27576c7b836e..15c8733ce44a 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2320,6 +2320,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, #endif dev->archdata.dma_ops_setup = true; } +EXPORT_SYMBOL(arch_setup_dma_ops); void arch_teardown_dma_ops(struct device *dev) { diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index d42b93316183..5606c0e7fde4 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -399,6 +399,13 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size) } EXPORT_SYMBOL(ioremap_wc); +void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size) +{ + return arch_ioremap_caller(res_cookie, size, MT_MEMORY_RW_NS, + __builtin_return_address(0)); +} +EXPORT_SYMBOL(ioremap_cache_ns); + /* * Remap an arbitrary physical address space into the kernel virtual * address space as memory. Needed when the kernel wants to execute diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 48c2888297dd..5cf31b491382 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -312,6 +312,13 @@ static struct mem_type mem_types[] __ro_after_init = { .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, + [MT_MEMORY_RW_NS] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_XN, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_XN, + .domain = DOMAIN_KERNEL, + }, [MT_ROM] = { .prot_sect = PMD_TYPE_SECT, .domain = DOMAIN_KERNEL, @@ -648,6 +655,7 @@ static void __init build_mem_type_table(void) } kern_pgprot |= PTE_EXT_AF; vecs_pgprot |= PTE_EXT_AF; + mem_types[MT_MEMORY_RW_NS].prot_pte |= PTE_EXT_AF | cp->pte; /* * Set PXN for user mappings @@ -676,6 +684,7 @@ static void __init build_mem_type_table(void) mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot; mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd; mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot; + mem_types[MT_MEMORY_RW_NS].prot_sect |= ecc_mask | cp->pmd; mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot; mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask; mem_types[MT_ROM].prot_sect |= cp->pmd; |