aboutsummaryrefslogtreecommitdiff
path: root/arch/arm64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/Kconfig26
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi27
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi64
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi254
-rw-r--r--arch/arm64/boot/dts/qcom/msm-iommu-v2.dtsi238
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-coresight.dtsi254
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-iommu.dtsi21
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-mdss.dtsi122
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-mtp.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi39
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-pins.dtsi319
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi635
-rw-r--r--arch/arm64/boot/dts/qcom/pm8916.dtsi126
-rw-r--r--arch/arm64/configs/defconfig127
-rw-r--r--arch/arm64/configs/qcom_defconfig274
-rw-r--r--arch/arm64/include/asm/cacheflush.h6
-rw-r--r--arch/arm64/include/asm/cpu_ops.h5
-rw-r--r--arch/arm64/include/asm/device.h9
-rw-r--r--arch/arm64/include/asm/dma-iommu.h36
-rw-r--r--arch/arm64/include/asm/smp_plat.h2
-rw-r--r--arch/arm64/kernel/cpu_ops.c16
-rw-r--r--arch/arm64/kernel/psci.c1
-rw-r--r--arch/arm64/kernel/smp.c1
-rw-r--r--arch/arm64/kernel/smp_spin_table.c6
-rw-r--r--arch/arm64/mm/cache.S4
-rw-r--r--arch/arm64/mm/dma-mapping.c1039
27 files changed, 3629 insertions, 28 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7a59117a2bd9..3aa5028607ae 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -156,6 +156,32 @@ config NEED_DMA_MAP_STATE
config NEED_SG_DMA_LENGTH
def_bool y
+config ARM64_DMA_USE_IOMMU
+ bool
+ select ARM_HAS_SG_CHAIN
+ select NEED_SG_DMA_LENGTH
+
+if ARM64_DMA_USE_IOMMU
+
+config ARM64_DMA_IOMMU_ALIGNMENT
+ int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers"
+ range 4 9
+ default 8
+ help
+ DMA mapping framework by default aligns all buffers to the smallest
+ PAGE_SIZE order which is greater than or equal to the requested buffer
+ size. This works well for buffers up to a few hundreds kilobytes, but
+ for larger buffers it just a waste of address space. Drivers which has
+ relatively small addressing window (like 64Mib) might run out of
+ virtual space with just a few allocations.
+
+ With this parameter you can specify the maximum PAGE_SIZE order for
+ DMA IOMMU buffers. Larger buffers will be aligned only to this
+ specified order. The order is expressed as a power of two multiplied
+ by the PAGE_SIZE.
+
+endif
+
config SMP
def_bool y
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi
index e03c11d9d834..181ac9c16460 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi
@@ -10,6 +10,14 @@
};
};
+ pm8916_gpios_default: default {
+ usb_hub_reset_pm {
+ pins = "gpio1";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ };
+ };
+
usb_sw_sel_pm: usb_sw_sel_pm {
pinconf {
pins = "gpio4";
@@ -34,6 +42,25 @@
pinconf {
pins = "mpp2", "mpp3";
function = PMIC_GPIO_FUNC_NORMAL;
+ power-source = <PM8916_GPIO_VPH>;
+ output-low; // USB device mode
+ };
+ };
+
+ pm8916_gpios_leds_default: pm8916_gpios_leds_default {
+ pinconf {
+ pins = "gpio1", "gpio2";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ };
+ };
+};
+
+&pm8916_mpps {
+ pm8916_mpps_leds_default: pm8916_mpps_leds_default {
+ pinconf {
+ pins = "mpp2", "mpp3";
+ function = "digital";
output-low;
};
};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
index cbeee0bcdf52..c7db0aeaebaa 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
@@ -9,5 +9,69 @@
function = "gpio";
output-low;
};
+
+ usb_id_default: usb_id_default {
+ pins = "gpio121";
+ function = "gpio";
+ drive-strength = <8>;
+ input-enable;
+ bias-pull-up;
+ };
+ };
+
+ msm_gpios_leds_default: msm_gpios_leds_default {
+ pinconf {
+ pins = "gpio21", "gpio120";
+ function = "gpio";
+ output-low;
+ };
+ };
+
+ adv7533_int_active: adv533_int_active {
+ pinmux {
+ function = "gpio";
+ pins = "gpio31";
+ };
+ pinconf {
+ pins = "gpio31";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ adv7533_int_suspend: adv7533_int_suspend {
+ pinmux {
+ function = "gpio";
+ pins = "gpio31";
+ };
+ pinconf {
+ pins = "gpio31";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ adv7533_switch_active: adv7533_switch_active {
+ pinmux {
+ function = "gpio";
+ pins = "gpio32";
+ };
+ pinconf {
+ pins = "gpio32";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ adv7533_switch_suspend: adv7533_switch_suspend {
+ pinmux {
+ function = "gpio";
+ pins = "gpio32";
+ };
+ pinconf {
+ pins = "gpio32";
+ drive-strength = <2>;
+ bias-disable;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
index 825f489a2af7..b0cac5337fcc 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
@@ -12,10 +12,11 @@
*/
/dts-v1/;
-
+#include <dt-bindings/arm/qcom-ids.h>
#include "apq8016-sbc.dtsi"
/ {
model = "Qualcomm Technologies, Inc. APQ 8016 SBC";
compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
+ qcom,board-id = <QCOM_BRD_ID(SBC, 1, 0) QCOM_BRD_SUBTYPE_DEFAULT>;
};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
index 66804ffbc6d2..bc40ec5945aa 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -11,14 +11,17 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/sound/apq8016-lpass.h>
#include "msm8916.dtsi"
#include "pm8916.dtsi"
#include "apq8016-sbc-soc-pins.dtsi"
#include "apq8016-sbc-pmic-pins.dtsi"
-
+#include "msm8916-mdss.dtsi"
/ {
aliases {
serial0 = &blsp1_uart2;
+ serial1 = &blsp1_uart1;
};
chosen {
@@ -33,6 +36,31 @@
pinctrl-1 = <&blsp1_uart2_sleep>;
};
+ i2c@78b6000 {
+ /* On Low speed expansion */
+ status = "okay";
+ };
+
+ i2c@78b8000 {
+ /* On High speed expansion */
+ status = "okay";
+ };
+
+ i2c@78ba000 {
+ /* On Low speed expansion */
+ status = "okay";
+ };
+
+ spi@78b7000 {
+ /* On High speed expansion */
+ status = "okay";
+ };
+
+ spi@78b9000 {
+ /* On Low speed expansion */
+ status = "okay";
+ };
+
leds {
pinctrl-names = "default";
pinctrl-0 = <&msmgpio_leds>,
@@ -84,4 +112,228 @@
};
};
};
+
+ usb2513 {
+ compatible = "smsc,usb3503";
+ reset-gpios = <&pm8916_gpios 3 GPIO_ACTIVE_LOW>;
+ initial-mode = <1>;
+ };
+
+ usb_id: usb-id {
+ interrupt-parent = <&msmgpio>;
+ compatible = "linux,extcon-usb-gpio";
+ id-gpio = <&msmgpio 121 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb_id_default>;
+ };
+
+ leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&msm_gpios_leds_default>,
+ <&pm8916_gpios_leds_default>,
+ <&pm8916_mpps_leds_default>;
+
+ compatible = "gpio-leds";
+
+ led@1 {
+ label = "apq8016-sbc:green:user0";
+ gpios = <&msmgpio 21 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led@2 {
+ label = "apq8016-sbc:green:user1";
+ gpios = <&msmgpio 120 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+
+ led@3 {
+ label = "apq8016-sbc:green:user2";
+ gpios = <&pm8916_gpios 1 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc1";
+ default-state = "off";
+ };
+
+ led@4 {
+ label = "apq8016-sbc:green:user3";
+ gpios = <&pm8916_gpios 2 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "none";
+ default-state = "off";
+ };
+
+ led@5 {
+ label = "apq8016-sbc:yellow:wifi";
+ gpios = <&pm8916_mpps 2 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "wlan";
+ default-state = "off";
+ };
+
+ led@6 {
+ label = "apq8016-sbc:blue:bt";
+ gpios = <&pm8916_mpps 3 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "bt";
+ default-state = "off";
+ };
+ };
+
+};
+&blsp_dma {
+ status = "okay";
+};
+
+&blsp1_uart1 {
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp1_uart1_default>;
+ pinctrl-1 = <&blsp1_uart1_sleep>;
+};
+
+&blsp_spi3 {
+ status = "okay";
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8916_l8>;
+ vqmmc-supply = <&pm8916_l5>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+ status = "okay";
+};
+
+&sdhc_2 {
+ vmmc-supply = <&pm8916_l11>;
+ vqmmc-supply = <&pm8916_l12>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "okay";
+};
+
+&usb_dev {
+ extcon = <&usb_id>, <&usb_id>;
+ status = "okay";
+};
+
+&usb_host {
+ status = "okay";
+};
+
+&usb_otg {
+ extcon = <&usb_id>, <&usb_id>;
+ dr_mode = "otg";
+ status = "okay";
+ switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>; // D+/D- lines: 1 - Routed to HUB, 0 - Device
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb_sw_sel_pm>;
+};
+
+&blsp_i2c4 {
+ status = "ok";
+
+ adv_bridge: bridge@39 {
+ status = "ok";
+ compatible = "adi,adv7533";
+ reg = <0x39>;
+ interrupt-parent = <&msmgpio>;
+ //interrupts = <31 2>;
+ adi,dsi-lanes = <4>;
+ pd-gpios = <&msmgpio 32 0>;
+ pinctrl-names = "default","sleep";
+ pinctrl-0 = <&adv7533_int_active &adv7533_switch_active>;
+ pinctrl-1 = <&adv7533_int_suspend &adv7533_switch_suspend>;
+ #sound-dai-cells = <0>;
+
+ port {
+ adv_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+
+ };
+};
+
+&mdss_dsi0 {
+ status = "ok";
+
+ port {
+ dsi_out: endpoint {
+ remote-endpoint = <&adv_in>;
+ };
+ };
+};
+
+&lpass {
+ status = "okay";
+};
+
+&wcd_codec {
+ status = "okay";
+ clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
+ clock-names = "mclk";
+ digital = <&wcd_digital>;
+};
+ /*
+ Internal Codec
+ playback - Primary MI2S
+ capture - Ter MI2S
+
+ External Primary:
+ playback - secondary MI2S
+ capture - Quat MI2S
+
+ External Secondary:
+ playback - Quat MI2S
+ capture - Quat MI2S
+
+ */
+&sound {
+ status = "okay";
+ pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>;
+ pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>;
+ pinctrl-names = "default", "sleep";
+ qcom,model = "DB410c";
+
+
+ internal-codec-playback-dai-link@0 { /* I2S - Internal codec */
+ link-name = "WCD";
+ cpu { /* PRIMARY */
+ sound-dai = <&lpass MI2S_PRIMARY>;
+ };
+ codec {
+ sound-dai = <&wcd_codec 0>;
+ };
+ };
+
+ /* External Primary or External Secondary -ADV7533 HDMI */
+ external-dai-link@0 {
+ link-name = "ADV7533";
+
+ cpu { /* QUAT */
+ sound-dai = <&lpass MI2S_QUATERNARY>;
+ };
+ codec {
+ sound-dai = <&adv_bridge 0>;
+ };
+ };
+};
+
+/* default regulators required for mezzanine boards */
+&pm8916_l15 {
+ regulator-always-on;
};
diff --git a/arch/arm64/boot/dts/qcom/msm-iommu-v2.dtsi b/arch/arm64/boot/dts/qcom/msm-iommu-v2.dtsi
new file mode 100644
index 000000000000..6f73eb26aaec
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-iommu-v2.dtsi
@@ -0,0 +1,238 @@
+/* Copyright (c) 2013-2014, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ gfx_iommu: qcom,iommu@1f00000 {
+ compatible = "qcom,msm-smmu-v2", "qcom,msm-mmu-500";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x1f00000 0x10000>;
+ reg-names = "iommu_base";
+ interrupts = <0 43 0>, <0 42 0>;
+ interrupt-names = "global_cfg_NS_irq", "global_cfg_S_irq";
+ label = "gfx_iommu";
+ qcom,iommu-secure-id = <18>;
+ clocks = <&gcc GCC_SMMU_CFG_CLK>,
+ <&gcc GCC_GFX_TCU_CLK>;
+ clock-names = "iface_clk", "core_clk";
+ status = "disabled";
+
+ qcom,iommu-ctx@1f09000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1f09000 0x1000>;
+ interrupts = <0 241 0>;
+ qcom,iommu-ctx-sids = <0>;
+ label = "gfx3d_user";
+ };
+
+ qcom,iommu-ctx@1f0a000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1f0a000 0x1000>;
+ interrupts = <0 242 0>;
+ qcom,iommu-ctx-sids = <1>;
+ label = "gfx3d_priv";
+ };
+ };
+
+ apps_iommu: qcom,iommu@1e00000 {
+ compatible = "qcom,msm-smmu-v2", "qcom,msm-mmu-500";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x1e00000 0x40000
+ 0x1ef0000 0x3000>;
+ reg-names = "iommu_base", "smmu_local_base";
+ interrupts = <0 43 0>, <0 42 0>;
+ interrupt-names = "global_cfg_NS_irq", "global_cfg_S_irq";
+ label = "apps_iommu";
+ qcom,iommu-secure-id = <17>;
+ clocks = <&gcc GCC_SMMU_CFG_CLK>,
+ <&gcc GCC_APSS_TCU_CLK>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,cb-base-offset = <0x20000>;
+ status = "disabled";
+
+ qcom,iommu-ctx@1e22000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e22000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x2000>;
+ label = "jpeg_enc0";
+ };
+
+ qcom,iommu-ctx@1e23000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e23000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x400>;
+ label = "vfe";
+ };
+
+ qcom,iommu-ctx@1e24000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e24000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0xc00>;
+ label = "mdp_0";
+ };
+
+ venus_ns: qcom,iommu-ctx@1e25000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e25000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x800 0x801 0x802 0x803
+ 0x804 0x805 0x807>;
+ label = "venus_ns";
+ };
+
+ qcom,iommu-ctx@1e26000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e26000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x402>;
+ label = "cpp";
+ };
+
+ qcom,iommu-ctx@1e27000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e27000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x1000>;
+ label = "mDSP";
+ };
+
+ qcom,iommu-ctx@1e28000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e28000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x1400>;
+ label = "gss";
+ };
+
+ qcom,iommu-ctx@1e29000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e29000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x1800>;
+ label = "a2";
+ };
+
+ qcom,iommu-ctx@1e32000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ qcom,secure-context;
+ reg = <0x1e32000 0x1000>;
+ interrupts = <0 70 0>, <0 70 0>;
+ qcom,iommu-ctx-sids = <0xc01>;
+ label = "mdp_1";
+ };
+
+ venus_sec_pixel: qcom,iommu-ctx@1e33000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ qcom,secure-context;
+ reg = <0x1e33000 0x1000>;
+ interrupts = <0 70 0>, <0 70 0>;
+ qcom,iommu-ctx-sids = <0x885>;
+ label = "venus_sec_pixel";
+ };
+
+ venus_sec_bitstream: qcom,iommu-ctx@1e34000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ qcom,secure-context;
+ reg = <0x1e34000 0x1000>;
+ interrupts = <0 70 0>, <0 70 0>;
+ qcom,iommu-ctx-sids = <0x880 0x881 0x882 0x883 0x884>;
+ label = "venus_sec_bitstream";
+ };
+
+ venus_sec_non_pixel: qcom,iommu-ctx@1e35000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ qcom,secure-context;
+ reg = <0x1e35000 0x1000>;
+ interrupts = <0 70 0>, <0 70 0>;
+ qcom,iommu-ctx-sids = <0x887 0x8a0>;
+ label = "venus_sec_non_pixel";
+ };
+
+ venus_fw: qcom,iommu-ctx@1e36000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ qcom,secure-context;
+ reg = <0x1e36000 0x1000>;
+ interrupts = <0 70 0>, <0 70 0>;
+ qcom,iommu-ctx-sids = <0x8c0 0x8c6>;
+ label = "venus_fw";
+ };
+
+ periph_rpm: qcom,iommu-ctx@1e37000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ qcom,secure-context;
+ reg = <0x1e37000 0x1000>;
+ interrupts = <0 70 0>, <0 70 0>;
+ qcom,iommu-ctx-sids = <0x40>;
+ label = "periph_rpm";
+ };
+
+ qcom,iommu-ctx@1e38000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e38000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0xC0 0xC4 0xC8 0xCC 0xD0 0xD3
+ 0xD4 0xD7 0xD8 0xDB 0xDC 0xDF
+ 0xF0 0xF3 0xF4 0xF7 0xF8 0xFB
+ 0xFC 0xFF>;
+ label = "periph_CE";
+ };
+
+ qcom,iommu-ctx@1e39000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e39000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x280 0x283 0x284 0x287 0x288
+ 0x28B 0x28C 0x28F 0x290 0x293
+ 0x294 0x297 0x298 0x29B 0x29C
+ 0x29F>;
+ label = "periph_BLSP";
+ };
+
+ qcom,iommu-ctx@1e3a000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e3a000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x100>;
+ label = "periph_SDC1";
+ };
+
+ qcom,iommu-ctx@1e3b000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e3b000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x140>;
+ label = "periph_SDC2";
+ };
+
+ qcom,iommu-ctx@1e3c000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e3c000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x1c0>;
+ label = "periph_audio";
+ };
+
+ qcom,iommu-ctx@1e3d000 {
+ compatible = "qcom,msm-smmu-v2-ctx";
+ reg = <0x1e3d000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0x2c0>;
+ label = "periph_USB_HS1";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8916-coresight.dtsi
new file mode 100644
index 000000000000..c008dc7a32bb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-coresight.dtsi
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+
+ tpiu@820000 {
+ compatible = "arm,coresight-tpiu", "arm,primecell";
+ reg = <0x820000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ port {
+ tpiu_in: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out1>;
+ };
+ };
+ };
+
+ funnel@821000 {
+ compatible = "arm,coresight-funnel", "arm,primecell";
+ reg = <0x821000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /*
+ * Not described input ports:
+ * 0 - connected to Resource and Power Manger CPU ETM
+ * 1 - not-connected
+ * 2 - connected to Modem CPU ETM
+ * 3 - not-connected
+ * 5 - not-connected
+ * 6 - connected trought funnel to Wireless CPU ETM
+ * 7 - connected to STM component
+ */
+ port@4 {
+ reg = <4>;
+ funnel0_in4: endpoint {
+ slave-mode;
+ remote-endpoint = <&funnel1_out>;
+ };
+ };
+ port@8 {
+ reg = <0>;
+ funnel0_out: endpoint {
+ remote-endpoint = <&etf_in>;
+ };
+ };
+ };
+ };
+
+ replicator@824000 {
+ compatible = "qcom,coresight-replicator1x", "arm,primecell";
+ reg = <0x824000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ replicator_out0: endpoint {
+ remote-endpoint = <&etr_in>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ replicator_out1: endpoint {
+ remote-endpoint = <&tpiu_in>;
+ };
+ };
+ port@2 {
+ reg = <0>;
+ replicator_in: endpoint {
+ slave-mode;
+ remote-endpoint = <&etf_out>;
+ };
+ };
+ };
+ };
+
+ etf@825000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0x825000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ etf_out: endpoint {
+ remote-endpoint = <&replicator_in>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ etf_in: endpoint {
+ slave-mode;
+ remote-endpoint = <&funnel0_out>;
+ };
+ };
+ };
+ };
+
+ etr@826000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0x826000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ port {
+ etr_in: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out0>;
+ };
+ };
+ };
+
+ funnel@841000 { /* APSS funnel only 4 inputs are used */
+ compatible = "arm,coresight-funnel", "arm,primecell";
+ reg = <0x841000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel1_in0: endpoint {
+ slave-mode;
+ remote-endpoint = <&etm0_out>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ funnel1_in1: endpoint {
+ slave-mode;
+ remote-endpoint = <&etm1_out>;
+ };
+ };
+ port@2 {
+ reg = <2>;
+ funnel1_in2: endpoint {
+ slave-mode;
+ remote-endpoint = <&etm2_out>;
+ };
+ };
+ port@3 {
+ reg = <3>;
+ funnel1_in3: endpoint {
+ slave-mode;
+ remote-endpoint = <&etm3_out>;
+ };
+ };
+ port@4 {
+ reg = <0>;
+ funnel1_out: endpoint {
+ remote-endpoint = <&funnel0_in4>;
+ };
+ };
+ };
+ };
+
+ etm@85c000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0x85c000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ cpu = <&CPU0>;
+
+ port {
+ etm0_out: endpoint {
+ remote-endpoint = <&funnel1_in0>;
+ };
+ };
+ };
+
+ etm@85d000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0x85d000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ cpu = <&CPU1>;
+
+ port {
+ etm1_out: endpoint {
+ remote-endpoint = <&funnel1_in1>;
+ };
+ };
+ };
+
+ etm@85e000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0x85e000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ cpu = <&CPU2>;
+
+ port {
+ etm2_out: endpoint {
+ remote-endpoint = <&funnel1_in2>;
+ };
+ };
+ };
+
+ etm@85f000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0x85f000 0x1000>;
+
+ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "atclk";
+
+ cpu = <&CPU3>;
+
+ port {
+ etm3_out: endpoint {
+ remote-endpoint = <&funnel1_in3>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-iommu.dtsi b/arch/arm64/boot/dts/qcom/msm8916-iommu.dtsi
new file mode 100644
index 000000000000..82acb8df2a8a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-iommu.dtsi
@@ -0,0 +1,21 @@
+/* Copyright (c) 2013-2014, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm-iommu-v2.dtsi"
+
+&gfx_iommu {
+ status = "ok";
+};
+
+&apps_iommu {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8916-mdss.dtsi
new file mode 100644
index 000000000000..95d3d337ae48
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-mdss.dtsi
@@ -0,0 +1,122 @@
+/* Copyright (c) 2015, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ gpu: qcom,adreno-3xx@01c00000 {
+ compatible = "qcom,adreno-3xx";
+ #stream-id-cells = <16>;
+ reg = <0x01c00000 0x20000>;
+ reg-names = "kgsl_3d0_reg_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ clock-names =
+ "core_clk",
+ "iface_clk",
+ "mem_clk",
+ "mem_iface_clk",
+ "alt_mem_iface_clk",
+ "gfx3d_clk_src";
+ clocks =
+ <&gcc GCC_OXILI_GFX3D_CLK>,
+ <&gcc GCC_OXILI_AHB_CLK>,
+ <&gcc GCC_OXILI_GMEM_CLK>,
+ <&gcc GCC_BIMC_GFX_CLK>,
+ <&gcc GCC_BIMC_GPU_CLK>,
+ <&gcc GFX3D_CLK_SRC>;
+ power-domains = <&gcc OXILI_GDSC>;
+ qcom,chipid = <0x03000600>;
+ qcom,gpu-pwrlevels {
+ compatible = "qcom,gpu-pwrlevels";
+ qcom,gpu-pwrlevel@0 {
+ qcom,gpu-freq = <400000000>;
+ };
+ qcom,gpu-pwrlevel@1 {
+ qcom,gpu-freq = <19200000>;
+ };
+ };
+ };
+
+ mdss_mdp: qcom,mdss_mdp@1a00000 {
+ compatible = "qcom,mdss_mdp";
+ reg = <0x1a00000 0x90000>,
+ <0x1ac8000 0x3000>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 72 0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ power-domains = <&gcc MDSS_GDSC>;
+
+ connectors = <&mdss_dsi0>;
+ gpus = <&gpu>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc MDP_CLK_SRC>,
+ <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>;
+ clock-names = "iface_clk", "bus_clk", "core_clk_src",
+ "core_clk", "lut_clk", "vsync_clk";
+ };
+
+ mdss_dsi0: qcom,mdss_dsi@1a98000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ label = "MDSS DSI CTRL->0";
+ qcom,dsi-host-index = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x1a98000 0x25c>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <4 0>;
+
+ vdda-supply = <&pm8916_l2>;
+ vdd-supply = <&pm8916_l17>;
+ vddio-supply = <&pm8916_l6>;
+
+ clocks = <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_BYTE0_CLK>,
+ <&gcc GCC_MDSS_PCLK0_CLK>,
+ <&gcc GCC_MDSS_ESC0_CLK>,
+ <&gcc BYTE0_CLK_SRC>,
+ <&gcc PCLK0_CLK_SRC>;
+ clock-names = "mdp_core_clk", "iface_clk", "bus_clk",
+ "core_mmss_clk", "byte_clk", "pixel_clk",
+ "core_clk", "byte_clk_src", "pixel_clk_src";
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+ };
+
+ mdss_dsi_phy0: qcom,mdss_dsi_phy@1a98300 {
+ compatible = "qcom,dsi-phy-28nm-lp";
+ qcom,dsi-phy-index = <0>;
+
+ power-domains = <&gcc MDSS_GDSC>;
+
+ reg-names = "dsi_pll", "dsi_phy", "dsi_phy_regulator";
+ reg = <0x1a98300 0xd4>,
+ <0x1a98500 0x280>,
+ <0x1a98780 0x30>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>;
+ clock-names = "iface_clk";
+
+ vddio-supply = <&pm8916_l6>;
+ };
+};
+
+
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
index fced77f0fd3a..6c68b4ed4de2 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
@@ -13,10 +13,13 @@
/dts-v1/;
+#include <dt-bindings/arm/qcom-ids.h>
#include "msm8916-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM 8916 MTP";
compatible = "qcom,msm8916-mtp", "qcom,msm8916-mtp-smb1360",
"qcom,msm8916", "qcom,mtp";
+ qcom,board-id = <QCOM_BRD_ID(MTP, 1, 0) QCOM_BRD_SUBTYPE_DEFAULT>,
+ <QCOM_BRD_ID(MTP, 1, 0) QCOM_BRD_SUBTYPE_MTP8916_SMB1360>;
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
index a1aa0b201e92..a222af32debe 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
@@ -32,3 +32,42 @@
};
};
};
+
+&blsp_dma {
+ status = "okay";
+};
+
+&blsp_spi3 {
+ status = "okay";
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8916_l8>;
+ vqmmc-supply = <&pm8916_l5>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+ status = "okay";
+};
+
+&sdhc_2 {
+ //vmmc-supply = <&pm8916_l11>;
+ vqmmc-supply = <&pm8916_l12>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
index 568956859088..5d2e4a5e91ef 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
@@ -12,6 +12,34 @@
*/
&msmgpio {
+ blsp1_uart1_default: blsp1_uart1_default {
+ pinmux {
+ function = "blsp_uart1";
+ // TX, RX, CTS_N, RTS_N
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ };
+ pinconf {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart1_sleep: blsp1_uart1_sleep {
+ pinmux {
+ function = "blsp_uart1";
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ };
+ pinconf {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
blsp1_uart2_default: blsp1_uart2_default {
pinmux {
@@ -241,6 +269,30 @@
};
};
+ i2c2_default: i2c2_default {
+ pinmux {
+ function = "blsp_i2c2";
+ pins = "gpio6", "gpio7";
+ };
+ pinconf {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ i2c2_sleep: i2c2_sleep {
+ pinmux {
+ function = "gpio";
+ pins = "gpio6", "gpio7";
+ };
+ pinconf {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
i2c4_default: i2c4_default {
pinmux {
function = "blsp_i2c4";
@@ -255,7 +307,7 @@
i2c4_sleep: i2c4_sleep {
pinmux {
- function = "blsp_i2c4";
+ function = "gpio";
pins = "gpio14", "gpio15";
};
pinconf {
@@ -265,6 +317,30 @@
};
};
+ i2c6_default: i2c6_default {
+ pinmux {
+ function = "blsp_i2c6";
+ pins = "gpio22", "gpio23";
+ };
+ pinconf {
+ pins = "gpio22", "gpio23";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ i2c6_sleep: i2c6_sleep {
+ pinmux {
+ function = "gpio";
+ pins = "gpio22", "gpio23";
+ };
+ pinconf {
+ pins = "gpio22", "gpio23";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
sdhc2_cd_pin {
sdc2_cd_on: cd_on {
pinmux {
@@ -427,4 +503,245 @@
};
};
};
+
+ ext-codec-lines {
+ ext_codec_lines_act: lines_on {
+ pinmux {
+ function = "gpio";
+ pins = "gpio67";
+ };
+ pinconf {
+ pins = "gpio67";
+ drive-strength = <8>;
+ bias-disable;
+ output-high;
+ };
+ };
+ ext_codec_lines_sus: lines_off {
+ pinmux {
+ function = "gpio";
+ pins = "gpio67";
+ };
+ pinconf {
+ pins = "gpio67";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cdc-pdm-lines {
+ cdc_pdm_lines_act: pdm_lines_on {
+ pinmux {
+ function = "cdc_pdm0";
+ pins = "gpio63", "gpio64", "gpio65", "gpio66",
+ "gpio67", "gpio68";
+ };
+ pinconf {
+ pins = "gpio63", "gpio64", "gpio65", "gpio66",
+ "gpio67", "gpio68";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+ cdc_pdm_lines_sus: pdm_lines_off {
+ pinmux {
+ function = "cdc_pdm0";
+ pins = "gpio63", "gpio64", "gpio65", "gpio66",
+ "gpio67", "gpio68";
+ };
+ pinconf {
+ pins = "gpio63", "gpio64", "gpio65", "gpio66",
+ "gpio67", "gpio68";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ ext-pri-tlmm-lines {
+ ext_pri_tlmm_lines_act: ext_pa_on {
+ pinmux {
+ function = "pri_mi2s";
+ pins = "gpio113", "gpio114", "gpio115",
+ "gpio116";
+ };
+ pinconf {
+ pins = "gpio113", "gpio114", "gpio115",
+ "gpio116";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+
+ ext_pri_tlmm_lines_sus: ext_pa_off {
+ pinmux {
+ function = "pri_mi2s";
+ pins = "gpio113", "gpio114", "gpio115",
+ "gpio116";
+ };
+ pinconf {
+ pins = "gpio113", "gpio114", "gpio115",
+ "gpio116";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ ext-pri-ws-line {
+ ext_pri_ws_act: ext_pa_on {
+ pinmux {
+ function = "pri_mi2s_ws";
+ pins = "gpio110";
+ };
+ pinconf {
+ pins = "gpio110";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+
+ ext_pri_ws_sus: ext_pa_off {
+ pinmux {
+ function = "pri_mi2s_ws";
+ pins = "gpio110";
+ };
+ pinconf {
+ pins = "gpio110";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ ext-mclk-tlmm-lines {
+ ext_mclk_tlmm_lines_act: mclk_lines_on {
+ pinmux {
+ function = "pri_mi2s";
+ pins = "gpio116";
+ };
+ pinconf {
+ pins = "gpio116";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+ ext_mclk_tlmm_lines_sus: mclk_lines_off {
+ pinmux {
+ function = "pri_mi2s";
+ pins = "gpio116";
+ };
+ pinconf {
+ pins = "gpio116";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* secondary Mi2S */
+ ext-sec-tlmm-lines {
+ ext_sec_tlmm_lines_act: tlmm_lines_on {
+ pinmux {
+ function = "sec_mi2s";
+ pins = "gpio112", "gpio117", "gpio118",
+ "gpio119";
+ };
+ pinconf {
+ pins = "gpio112", "gpio117", "gpio118",
+ "gpio119";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+ ext_sec_tlmm_lines_sus: tlmm_lines_off {
+ pinmux {
+ function = "sec_mi2s";
+ pins = "gpio112", "gpio117", "gpio118",
+ "gpio119";
+ };
+ pinconf {
+ pins = "gpio112", "gpio117", "gpio118",
+ "gpio119";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cdc-dmic-lines {
+ cdc_dmic_lines_act: dmic_lines_on {
+ pinmux_dmic0_clk {
+ function = "dmic0_clk";
+ pins = "gpio0";
+ };
+ pinmux_dmic0_data {
+ function = "dmic0_data";
+ pins = "gpio1";
+ };
+ pinconf {
+ pins = "gpio0", "gpio1";
+ drive-strength = <8>;
+ };
+ };
+ cdc_dmic_lines_sus: dmic_lines_off {
+ pinconf {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cross-conn-det {
+ cross_conn_det_act: lines_on {
+ pinmux {
+ function = "gpio";
+ pins = "gpio120";
+ };
+ pinconf {
+ pins = "gpio120";
+ drive-strength = <8>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+ cross_conn_det_sus: lines_off {
+ pinmux {
+ function = "gpio";
+ pins = "gpio120";
+ };
+ pinconf {
+ pins = "gpio120";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ wcnss_default: wcnss_default {
+ pinmux2 {
+ function = "wcss_wlan";
+ pins = "gpio40";
+ };
+ pinmux1 {
+ function = "wcss_wlan";
+ pins = "gpio41";
+ };
+ pinmux0 {
+ function = "wcss_wlan";
+ pins = "gpio42";
+ };
+ pinmux {
+ function = "wcss_wlan";
+ pins = "gpio43", "gpio44";
+ };
+ pinconf {
+ pins = "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 5911de008dd5..3416cccf26c3 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -14,10 +14,19 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8916.h>
#include <dt-bindings/reset/qcom,gcc-msm8916.h>
+#include <dt-bindings/clock/qcom,rpmcc-msm8916.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/arm/qcom-ids.h>
/ {
model = "Qualcomm Technologies, Inc. MSM8916";
compatible = "qcom,msm8916";
+ qcom,msm-id = <QCOM_ID_MSM8916 0>,
+ <QCOM_ID_MSM8216 0>,
+ <QCOM_ID_MSM8116 0>,
+ <QCOM_ID_MSM8616 0>,
+ <QCOM_ID_APQ8016 0>;
+
interrupt-parent = <&intc>;
@@ -37,6 +46,32 @@
reg = <0 0 0 0>;
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ reserve_aligned@86000000 {
+ reg = <0x0 0x86000000 0x0 0x0300000>;
+ no-map;
+ };
+
+ smem_mem: smem_region@86300000 {
+ reg = <0x0 0x86300000 0x0 0x0100000>;
+ no-map;
+ };
+
+ hypervisor_mem: hypervisor_region@86400000 {
+ no-map;
+ reg = <0x0 0x86400000 0x0 0x0400000>;
+ };
+
+ peripheral_mem: peripheral_region@8b600000 {
+ no-map;
+ reg = <0x0 0x8b600000 0x0 0x0600000>;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -45,24 +80,130 @@
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0>;
+ enable-method = "qcom,arm-cortex-acc";
+ qcom,acc = <&acc0>;
+ next-level-cache = <&L2_0>;
+ clocks = <&a53cc 1>;
+ clock-latency = <200000>;
+ cpu-supply = <&pm8916_s2>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
+ L2_0: l2-cache {
+ compatible = "arm,arch-cache";
+ cache-level = <2>;
+ power-domain = <&l2ccc_0>;
+ };
};
CPU1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x1>;
+ enable-method = "qcom,arm-cortex-acc";
+ qcom,acc = <&acc1>;
+ next-level-cache = <&L2_0>;
+ clocks = <&a53cc 1>;
+ clock-latency = <200000>;
+ cpu-supply = <&pm8916_s2>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
};
CPU2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x2>;
+ enable-method = "qcom,arm-cortex-acc";
+ qcom,acc = <&acc2>;
+ next-level-cache = <&L2_0>;
+ clocks = <&a53cc 1>;
+ clock-latency = <200000>;
+ cpu-supply = <&pm8916_s2>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
};
CPU3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x3>;
+ enable-method = "qcom,arm-cortex-acc";
+ qcom,acc = <&acc3>;
+ next-level-cache = <&L2_0>;
+ clocks = <&a53cc 1>;
+ clock-latency = <200000>;
+ cpu-supply = <&pm8916_s2>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
+ };
+ };
+
+ cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 GIC_CPU_MASK_SIMPLE(4)>;
+ };
+
+ thermal-zones {
+ cpu-thermal0 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 4>;
+
+ trips {
+ cpu_alert0: trip@0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit0: trip@1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ cpu-thermal1 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 3>;
+
+ trips {
+ cpu_alert1: trip@0 {
+ temperature = <100000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit1: trip@1 {
+ temperature = <125000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
};
@@ -74,6 +215,15 @@
<GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
+ clocks {
+ xo_board: xo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ clock-output-names = "xo_board";
+ };
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -95,19 +245,229 @@
#interrupt-cells = <2>;
};
+ tcsr_mutex_regs: syscon@1905000 {
+ compatible = "syscon";
+ reg = <0x1905000 0x20000>;
+ };
+
+ tcsr_mutex: hwlock {
+ compatible = "qcom,tcsr-mutex";
+ syscon = <&tcsr_mutex_regs 0 0x1000>;
+ #hwlock-cells = <1>;
+ };
+
+ smem {
+ compatible = "qcom,smem";
+ reg = <0x60000 0x8000>;
+ reg-names = "aux-mem1";
+
+ memory-region = <&smem_mem>;
+
+ hwlocks = <&tcsr_mutex 3>;
+ };
+
+
+ apcs: syscon@b011000 {
+ compatible = "syscon";
+ reg = <0x0b011000 0x1000>;
+ };
+
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <0 168 1>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+ qcom,remote-pid = <0xffffffff>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-msm8916";
+ qcom,smd-channels = "rpm_requests";
+
+ rpmcc: qcom,rpmcc {
+ compatible = "qcom,rpmcc-msm8916";
+ #clock-cells = <1>;
+ };
+
+ pm8916-regulators {
+ compatible = "qcom,rpm-pm8916-regulators";
+
+ vdd_l1_l2_l3-supply = <&pm8916_s3>;
+ vdd_l5-supply = <&pm8916_s3>;
+ vdd_l4_l5_l6-supply = <&pm8916_s4>;
+ vdd_l7-supply = <&pm8916_s4>;
+
+ pm8916_s1: s1 {
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <1562000>;
+ };
+ s2 {
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <1562000>;
+ };
+ pm8916_s3: s3 {
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <1562000>;
+ };
+ pm8916_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ pm8916_l1: l1 {
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <1525000>;
+ };
+ pm8916_l2: l2 {
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <1525000>;
+ };
+ pm8916_l3: l3 {
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <1525000>;
+ };
+ pm8916_l4: l4 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l5: l5 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l6: l6 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l7: l7 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l8: l8 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l9: l9 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l10: l10 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l11: l11 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l12: l12 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l13: l13 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l14: l14 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l15: l15 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l16: l16 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l17: l17 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ pm8916_l18: l18 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3337000>;
+ };
+ };
+ };
+ };
+
+ pronto_smd_edge: pronto {
+ interrupts = <0 142 1>;
+
+ qcom,ipc = <&apcs 8 17>;
+ qcom,smd-edge = <6>;
+ qcom,remote-pid = <4>;
+
+ bt {
+ compatible = "qcom,hci-smd";
+ qcom,smd-channels = "APPS_RIVA_BT_CMD", "APPS_RIVA_BT_ACL";
+ qcom,smd-channel-names = "event", "data";
+ };
+
+ ipcrtr {
+ compatible = "qcom,ipcrtr";
+ qcom,smd-channels = "IPCRTR";
+ };
+
+ wifi {
+ compatible = "qcom,wlan-ctrl";
+ qcom,smd-channels = "WLAN_CTRL";
+
+ interrupts = <0 145 0>, <0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,wcnss_mmio = <0xfb000000 0x21b000>;
+
+ // qcom,tx-enable-gpios = <&apps_smsm 10 0>;
+ // qcom,tx-rings-empty-gpios = <&apps_smsm 9 0>;
+ };
+
+ wcnss_ctrl {
+ compatible = "qcom,wcnss-ctrl";
+ qcom,smd-channels = "WCNSS_CTRL";
+
+ qcom,wcnss_mmio = <0xfb21b000 0x3000>;
+ };
+ };
+ };
+
gcc: qcom,gcc@1800000 {
compatible = "qcom,gcc-msm8916";
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
reg = <0x1800000 0x80000>;
};
+ a53cc: qcom,a53cc@0b016000 {
+ compatible = "qcom,clock-a53-msm8916";
+ reg = <0x0b016000 0x40>;
+ #clock-cells = <1>;
+ qcom,apcs = <&apcs>;
+ };
+
+ blsp1_uart1: serial@78af000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78af000 0x200>;
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>,
+ <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ dmas = <&blsp_dma 1>, <&blsp_dma 0>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
blsp1_uart2: serial@78b0000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78b0000 0x200>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
+ dmas = <&blsp_dma 3>, <&blsp_dma 2>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -224,6 +584,21 @@
status = "disabled";
};
+ blsp_i2c2: i2c@78b6000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x78b6000 0x1000>;
+ interrupts = <GIC_SPI 96 0>;
+ clocks = <&gcc GCC_BLSP1_AHB_CLK>,
+ <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>;
+ clock-names = "iface", "core";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c2_default>;
+ pinctrl-1 = <&i2c2_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
blsp_i2c4: i2c@78b8000 {
compatible = "qcom,i2c-qup-v2.2.1";
reg = <0x78b8000 0x1000>;
@@ -239,6 +614,21 @@
status = "disabled";
};
+ blsp_i2c6: i2c@78ba000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x78ba000 0x1000>;
+ interrupts = <GIC_SPI 100 0>;
+ clocks = <&gcc GCC_BLSP1_AHB_CLK>,
+ <&gcc GCC_BLSP1_QUP6_I2C_APPS_CLK>;
+ clock-names = "iface", "core";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c6_default>;
+ pinctrl-1 = <&i2c6_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
sdhc_1: sdhci@07824000 {
compatible = "qcom,sdhci-msm-v4";
reg = <0x07824900 0x11c>, <0x07824000 0x800>;
@@ -291,10 +681,13 @@
interrupts = <GIC_SPI 134 IRQ_TYPE_EDGE_BOTH>,
<GIC_SPI 140 IRQ_TYPE_EDGE_RISING>;
+ v1p8-supply = <&pm8916_l7>;
+ v3p3-supply = <&pm8916_l13>;
qcom,vdd-levels = <1 5 7>;
qcom,phy-init-sequence = <0x44 0x6B 0x24 0x13>;
dr_mode = "peripheral";
qcom,otg-control = <2>; // PMIC
+ qcom,manual-pullup;
clocks = <&gcc GCC_USB_HS_AHB_CLK>,
<&gcc GCC_USB_HS_SYSTEM_CLK>,
@@ -314,6 +707,11 @@
reg = <0x0b000000 0x1000>, <0x0b002000 0x1000>;
};
+ l2ccc_0: clock-controller@b011000 {
+ compatible = "qcom,8916-l2ccc";
+ reg = <0x0b011000 0x1000>;
+ };
+
timer@b020000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -390,7 +788,244 @@
interrupt-controller;
#interrupt-cells = <4>;
};
+
+ acc0: clock-controller@b088000 {
+ compatible = "qcom,arm-cortex-acc";
+ reg = <0x0b088000 0x1000>,
+ <0x0b008000 0x1000>;
+ };
+
+ acc1: clock-controller@b098000 {
+ compatible = "qcom,arm-cortex-acc";
+ reg = <0x0b098000 0x1000>,
+ <0x0b008000 0x1000>;
+ };
+
+ acc2: clock-controller@b0a8000 {
+ compatible = "qcom,arm-cortex-acc";
+ reg = <0x0b0a8000 0x1000>,
+ <0x0b008000 0x1000>;
+ };
+
+ acc3: clock-controller@b0b8000 {
+ compatible = "qcom,arm-cortex-acc";
+ reg = <0x0b0b8000 0x1000>,
+ <0x0b008000 0x1000>;
+ };
+
+ /* Audio */
+
+ wcd_digital: codec-digital{
+ compatible = "syscon", "qcom,apq8016-wcd-digital-codec";
+ reg = <0x0771c000 0x400>;
+ };
+
+ lpass: lpass-cpu@07700000 {
+ status = "disabled";
+ compatible = "qcom,lpass-cpu-apq8016";
+ clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>,
+ <&gcc GCC_ULTAUDIO_PCNOC_MPORT_CLK>,
+ <&gcc GCC_ULTAUDIO_PCNOC_SWAY_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_PRI_I2S_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_SEC_I2S_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_AUX_I2S_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_AUX_I2S_CLK>;
+
+ clock-names = "ahbix-clk",
+ "pcnoc-mport-clk",
+ "pcnoc-sway-clk",
+ "mi2s-bit-clk0",
+ "mi2s-bit-clk1",
+ "mi2s-bit-clk2",
+ "mi2s-bit-clk3";
+ #sound-dai-cells = <1>;
+
+ interrupts = <0 160 0>;
+ interrupt-names = "lpass-irq-lpaif";
+ reg = <0x07708000 0x10000>, <0x07702000 0x4>, <0x07702004 0x4>;
+ reg-names = "lpass-lpaif", "mic-iomux", "spkr-iomux";
+ };
+
+ sound: sound {
+ status = "disabled";
+ compatible = "qcom,apq8016-sbc-sndcard";
+ reg = <0x07702000 0x4>, <0x07702004 0x4>;
+ reg-names = "mic-iomux", "spkr-iomux";
+ };
+
+ tcsr: syscon@1937000 {
+ compatible = "qcom,tcsr-msm8916", "syscon";
+ reg = <0x1937000 0x30000>;
+ };
+
+ uqfprom: eeprom@58000 {
+ compatible = "qcom,qfprom-msm8916";
+ reg = <0x58000 0x7000>;
+ };
+
+ cpr@b018000 {
+ compatible = "qcom,cpr";
+ reg = <0xb018000 0x1000>;
+ interrupts = <0 15 1>, <0 16 1>, <0 17 1>;
+ vdd-mx-supply = <&pm8916_l3>;
+ acc-syscon = <&tcsr>;
+ eeprom = <&uqfprom>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay-us = <5000>;
+ qcom,cpr-timer-cons-up = <0>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <15>;
+ qcom,cpr-gcnt-us = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-cpus = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ };
+
+ qfprom: qfprom@5c000 {
+ compatible = "qcom,qfprom";
+ reg = <0x5c000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ tsens_caldata: caldata@d0 {
+ reg = <0xd0 0x8>;
+ };
+ tsens_calsel: calsel@ec {
+ reg = <0xec 0x4>;
+ };
+ };
+
+ tsens: thermal-sensor@4a8000 {
+ compatible = "qcom,msm8916-tsens";
+ reg = <0x4a8000 0x2000>;
+ nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+ nvmem-cell-names = "calib", "calib_sel";
+ qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
+ qcom,sensor-id = <0 1 2 4 5>;
+ #thermal-sensor-cells = <1>;
+ };
+
+ wcnss-smp2p {
+ compatible = "qcom,smp2p";
+ qcom,smem = <451>, <431>;
+
+ interrupts = <0 143 1>;
+
+ qcom,ipc = <&apcs 8 18>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <4>;
+
+ wcnss_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ qcom,outbound;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ wcnss_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+ qcom,inbound;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pronto_rproc:pronto_rproc {
+ compatible = "qcom,tz-pil";
+
+ interrupts-extended = <&intc 0 149 1>,
+ <&wcnss_smp2p_in 0 0>,
+ <&wcnss_smp2p_in 1 0>,
+ <&wcnss_smp2p_in 2 0>,
+ <&wcnss_smp2p_in 3 0>;
+ interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
+
+ clocks = <&gcc GCC_CRYPTO_CLK>,
+ <&gcc GCC_CRYPTO_AHB_CLK>,
+ <&gcc GCC_CRYPTO_AXI_CLK>,
+ <&gcc CRYPTO_CLK_SRC>;
+ clock-names = "scm_core_clk", "scm_iface_clk", "scm_bus_clk", "scm_src_clk";
+
+ qcom,firmware-name = "wcnss";
+ qcom,pas-id = <6>;
+
+ qcom,crash-reason = <422>;
+ qcom,smd-edges = <&pronto_smd_edge>;
+
+ qcom,pll-supply = <&pm8916_l7>;
+ qcom,pll-uV = <1800000>;
+ qcom,pll-uA = <18000>;
+
+ qcom,stop-gpio = <&wcnss_smp2p_out 0 0>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcnss_default>;
+
+ memory-region = <&peripheral_mem>;
+ };
+
+ qcom,wcn36xx@0a000000 {
+ compatible = "qcom,wcn3620";
+ reg = <0x0a000000 0x280000>,
+ <0xb011008 0x04>,
+ <0x0a21b000 0x3000>,
+ <0x03204000 0x00000100>,
+ <0x03200800 0x00000200>,
+ <0x0A100400 0x00000200>,
+ <0x0A205050 0x00000200>,
+ <0x0A219000 0x00000020>,
+ <0x0A080488 0x00000008>,
+ <0x0A080fb0 0x00000008>,
+ <0x0A08040c 0x00000008>,
+ <0x0A0120a8 0x00000008>,
+ <0x0A012448 0x00000008>,
+ <0x0A080c00 0x00000001>;
+
+ reg-names = "wcnss_mmio", "wcnss_fiq",
+ "pronto_phy_base", "riva_phy_base",
+ "riva_ccu_base", "pronto_a2xb_base",
+ "pronto_ccpu_base", "pronto_saw2_base",
+ "wlan_tx_phy_aborts","wlan_brdg_err_source",
+ "wlan_tx_status", "alarms_txctl",
+ "alarms_tactl", "pronto_mcu_base";
+
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ // qcom,pronto-vddmx-supply = <&pm8916_l3>;
+ // qcom,pronto-vddcx-supply = <&pm8916_s1_corner>;
+ // qcom,pronto-vddpx-supply = <&pm8916_l7>;
+ // qcom,iris-vddxo-supply = <&pm8916_l7>;
+ // qcom,iris-vddrfa-supply = <&pm8916_s3>;
+ // qcom,iris-vddpa-supply = <&pm8916_l9>;
+ // qcom,iris-vdddig-supply = <&pm8916_l5>;
+
+ pinctrl-names = "wcnss_default";
+ // pinctrl-names = "wcnss_default", "wcnss_sleep",
+ // "wcnss_gpio_default";
+ pinctrl-0 = <&wcnss_default>;
+ // pinctrl-1 = <&wcnss_sleep>;
+ // pinctrl-2 = <&wcnss_gpio_default>;
+
+ // clocks = <&rpmcc RPM_XO_CLK_SRC>,
+ // <&rpmcc RPM_RF_CLK2>;
+ //clock-names = "xo", "rf_clk";
+
+ rproc = <&pronto_rproc>;
+ qcom,has-autodetect-xo;
+ qcom,wlan-rx-buff-count = <512>;
+ qcom,is-pronto-vt;
+ qcom,has-pronto-hw;
+ // qcom,wcnss-adc_tm = <&pm8916_adc_tm>;
+ };
};
};
#include "msm8916-pins.dtsi"
+#include "msm8916-iommu.dtsi"
+#include "msm8916-coresight.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
index b222ece7e3d2..5f6a92516eab 100644
--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -95,5 +95,131 @@
reg = <0x1 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ regulators {
+ compatible = "qcom,pm8916-regulators";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ s1@1400 {
+ reg = <0x1400 0x300>;
+ status = "disabled";
+ };
+
+ pm8916_s2: s2@1700 {
+ reg = <0x1700 0x300>;
+ status = "ok";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ s3@1a00 {
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+ };
+
+ s4@1d00 {
+ reg = <0x1d00 0x300>;
+ status = "disabled";
+ };
+
+ l1@4000 {
+ reg = <0x4000 0x100>;
+ status = "disabled";
+ };
+
+ l2@4100 {
+ reg = <0x4100 0x100>;
+ status = "disabled";
+ };
+
+ l3@4200 {
+ reg = <0x4200 0x100>;
+ status = "disabled";
+ };
+
+ l4@4300 {
+ reg = <0x4300 0x100>;
+ status = "disabled";
+ };
+
+ l5@4400 {
+ reg = <0x4400 0x100>;
+ status = "disabled";
+ };
+
+ l6@4500 {
+ reg = <0x4500 0x100>;
+ status = "disabled";
+ };
+
+ l7@4600 {
+ reg = <0x4600 0x100>;
+ status = "disabled";
+ };
+
+ l8@4700 {
+ reg = <0x4700 0x100>;
+ status = "disabled";
+ };
+
+ l9@4800 {
+ reg = <0x4800 0x100>;
+ status = "disabled";
+ };
+
+ l10@4900 {
+ reg = <0x4900 0x100>;
+ status = "disabled";
+ };
+
+ l11@4a00 {
+ reg = <0x4a00 0x100>;
+ status = "disabled";
+ };
+
+ l12@4b00 {
+ reg = <0x4b00 0x100>;
+ status = "disabled";
+ };
+
+ l13@4c00 {
+ reg = <0x4c00 0x100>;
+ status = "disabled";
+ };
+
+ l14@4d00 {
+ reg = <0x4d00 0x100>;
+ status = "disabled";
+ };
+
+ l15@4e00 {
+ reg = <0x4e00 0x100>;
+ status = "disabled";
+ };
+
+ l16@4f00 {
+ reg = <0x4f00 0x100>;
+ status = "disabled";
+ };
+
+ l17@5000 {
+ reg = <0x5000 0x100>;
+ status = "disabled";
+ };
+
+ l18@5100 {
+ reg = <0x5100 0x100>;
+ status = "disabled";
+ };
+ };
+
+ wcd_codec: codec@f000 {
+ compatible = "qcom,apq8016-wcd-codec";
+ reg = <0xf000 0x200>;
+ #sound-dai-cells = <0>;
+ vddio-supply = <&pm8916_l5>;
+ vdd-pa-supply = <&pm8916_s4>;
+ };
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 34d71dd86781..8f084e81cf14 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -23,7 +23,6 @@ CONFIG_CGROUP_HUGETLB=y
# CONFIG_NET_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_ALL=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_JUMP_LABEL=y
@@ -38,10 +37,10 @@ CONFIG_ARCH_FSL_LS2085A=y
CONFIG_ARCH_HISI=y
CONFIG_ARCH_MEDIATEK=y
CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_QCOM=y
CONFIG_ARCH_SEATTLE=y
CONFIG_ARCH_TEGRA=y
CONFIG_ARCH_TEGRA_132_SOC=y
-CONFIG_ARCH_QCOM=y
CONFIG_ARCH_SPRD=y
CONFIG_ARCH_THUNDER=y
CONFIG_ARCH_VEXPRESS=y
@@ -60,6 +59,14 @@ CONFIG_CMDLINE="console=ttyAMA0"
CONFIG_COMPAT=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_CPUIDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPUFREQ_DT=y
+# CONFIG_ARM_TEGRA_CPUFREQ is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -70,7 +77,19 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
CONFIG_BPF_JIT=y
-# CONFIG_WIRELESS is not set
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIBTUSB=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_QCOMSMD=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
# CONFIG_TEGRA_AHB is not set
@@ -78,6 +97,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=64
CONFIG_BLK_DEV_LOOP=y
CONFIG_VIRTIO_BLK=y
# CONFIG_SCSI_PROC_FS is not set
@@ -97,7 +117,12 @@ CONFIG_NET_XGENE=y
CONFIG_SKY2=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
-# CONFIG_WLAN is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_DM9601=y
+CONFIG_USB_NET_PLUSB=y
+CONFIG_ATH_CARDS=y
+CONFIG_WCN36XX=m
+CONFIG_WCN36XX_DEBUGFS=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_SERIO_SERPORT is not set
@@ -116,51 +141,125 @@ CONFIG_SERIAL_XILINX_PS_UART=y
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
+CONFIG_SPI_QUP=m
+CONFIG_SPMI=y
CONFIG_PINCTRL_MSM8916=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_PL061=y
+CONFIG_GPIO_QCOM_SMSM=y
+CONFIG_GPIO_QCOM_SMP2P=y
CONFIG_GPIO_XGENE=y
+CONFIG_POWER_RESET_MSM=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_AVS=y
+CONFIG_QCOM_CPR=y
# CONFIG_HWMON is not set
-CONFIG_REGULATOR=y
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_QCOM_TSENS=y
+CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
-CONFIG_FB=y
+CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SMD_RPM=y
+CONFIG_REGULATOR_QCOM_SPMI=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_DRM=y
+CONFIG_DRM_I2C_ADV7511=y
+# CONFIG_DRM_I2C_ADV7511_SLAVE_ENCODER is not set
CONFIG_FB_ARMCLCD=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_QCOM=y
+CONFIG_SND_SOC_APQ8016_SBC=y
+CONFIG_SND_SOC_MSM8x16_WCD=y
CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_PRINTER=y
+CONFIG_USB_WDM=y
CONFIG_USB_STORAGE=y
+CONFIG_USB_UAS=y
+CONFIG_USBIP_CORE=y
+CONFIG_USBIP_HOST=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_ISP1760=y
-CONFIG_USB_ULPI=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_TEST=m
+CONFIG_USB_HSIC_USB3503=y
+CONFIG_USB_MSM_OTG=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_VERBOSE=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SPI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_EFI=y
CONFIG_RTC_DRV_XGENE=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_BAM_DMA=y
+CONFIG_QCOM_ADM=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_MMIO=y
CONFIG_COMMON_CLK_QCOM=y
+CONFIG_QCOM_CLK_SMD_RPM=y
+CONFIG_QCOM_RPMCC=y
CONFIG_MSM_GCC_8916=y
-# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_MSM_RPMCC_8064=y
+CONFIG_QCOM_A53=y
+CONFIG_QCOM_IOMMU_V1=y
+CONFIG_QCOM_GSBI=y
+CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMEM=y
+CONFIG_EXTCON_USB_GPIO=y
+CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_QCOM_Q6V5_PIL=y
+CONFIG_QCOM_TZ_PIL=y
CONFIG_PHY_XGENE=y
+CONFIG_NVMEM=y
+CONFIG_QCOM_QFPROM=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
@@ -173,7 +272,6 @@ CONFIG_AUTOFS4_FS=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=y
CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
CONFIG_HUGETLBFS=y
CONFIG_EFIVAR_FS=y
# CONFIG_MISC_FILESYSTEMS is not set
@@ -183,17 +281,24 @@ CONFIG_ROOT_NFS=y
CONFIG_9P_FS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
-CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_PROVE_LOCKING=y
# CONFIG_FTRACE is not set
CONFIG_MEMTEST=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SINK_TPIU=y
+CONFIG_CORESIGHT_SINK_ETBV10=y
+CONFIG_CORESIGHT_SOURCE_ETM4X=y
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_ARM64_CRYPTO=y
diff --git a/arch/arm64/configs/qcom_defconfig b/arch/arm64/configs/qcom_defconfig
new file mode 100644
index 000000000000..6ece7d6477f5
--- /dev/null
+++ b/arch/arm64/configs/qcom_defconfig
@@ -0,0 +1,274 @@
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_CMA=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_FREQ=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_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_NAT_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=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_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
+CONFIG_DMA_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_VERITY=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PHYLIB=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_PINCTRL_MSM8916=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_THERMAL=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_FAN53555=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_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_RTC_CLASS=y
+CONFIG_UIO=y
+CONFIG_STAGING=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_COMMON_CLK_QCOM=y
+CONFIG_MSM_GCC_8916=y
+CONFIG_PWM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index c75b8d027eb1..12137e615cf9 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -85,6 +85,12 @@ static inline void flush_cache_page(struct vm_area_struct *vma,
extern void __dma_map_area(const void *, size_t, int);
extern void __dma_unmap_area(const void *, size_t, int);
extern void __dma_flush_range(const void *, const void *);
+extern void __dma_inv_range(const void *, const void *);
+extern void __dma_clean_range(const void *, const void *);
+
+#define dmac_flush_range __dma_flush_range
+#define dmac_inv_range __dma_inv_range
+#define dmac_clean_range __dma_clean_range
/*
* Copy user data from/to a page which is mapped into a different
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h
index 8f03446cf89f..41bf609206ed 100644
--- a/arch/arm64/include/asm/cpu_ops.h
+++ b/arch/arm64/include/asm/cpu_ops.h
@@ -71,4 +71,9 @@ static inline void __init cpu_read_bootcpu_ops(void)
cpu_read_ops(0);
}
+#define CPU_METHOD_OF_DECLARE(name, __ops) \
+ static const struct cpu_operations *__cpu_method_table_##name \
+ __used __section(__cpu_method_of_table) \
+ = __ops;
+
#endif /* ifndef __ASM_CPU_OPS_H */
diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h
index 243ef256b8c9..908a6a53ed49 100644
--- a/arch/arm64/include/asm/device.h
+++ b/arch/arm64/include/asm/device.h
@@ -22,9 +22,18 @@ struct dev_archdata {
void *iommu; /* private IOMMU data */
#endif
bool dma_coherent;
+#ifdef CONFIG_ARM64_DMA_USE_IOMMU
+ struct dma_iommu_mapping *mapping;
+#endif
};
struct pdev_archdata {
};
+#ifdef CONFIG_ARM64_DMA_USE_IOMMU
+#define to_dma_iommu_mapping(dev) ((dev)->archdata.mapping)
+#else
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
#endif
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
new file mode 100644
index 000000000000..a8c56acc8c98
--- /dev/null
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -0,0 +1,36 @@
+#ifndef ASMARM_DMA_IOMMU_H
+#define ASMARM_DMA_IOMMU_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm_types.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/kmemcheck.h>
+#include <linux/kref.h>
+
+struct dma_iommu_mapping {
+ /* iommu specific data */
+ struct iommu_domain *domain;
+
+ void *bitmap;
+ size_t bits;
+ unsigned int order;
+ dma_addr_t base;
+
+ spinlock_t lock;
+ struct kref kref;
+};
+
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+ int order);
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping);
+void arm_iommu_detach_device(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/arch/arm64/include/asm/smp_plat.h b/arch/arm64/include/asm/smp_plat.h
index af58dcdefb21..63bea4f70a74 100644
--- a/arch/arm64/include/asm/smp_plat.h
+++ b/arch/arm64/include/asm/smp_plat.h
@@ -36,6 +36,7 @@ static inline u32 mpidr_hash_size(void)
return 1 << mpidr_hash.bits;
}
+extern void secondary_holding_pen(void);
/*
* Logical CPU mapping.
*/
@@ -55,5 +56,6 @@ static inline int get_logical_index(u64 mpidr)
return cpu;
return -EINVAL;
}
+extern volatile unsigned long secondary_holding_pen_release;
#endif /* __ASM_SMP_PLAT_H */
diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
index b6bd7d447768..3c63506b6437 100644
--- a/arch/arm64/kernel/cpu_ops.c
+++ b/arch/arm64/kernel/cpu_ops.c
@@ -35,16 +35,18 @@ static const struct cpu_operations *supported_cpu_ops[] __initconst = {
NULL,
};
+extern struct cpu_operations __cpu_method_of_table[];
+static const struct cpu_operations *__cpu_method_of_table_sentinel
+ __used __section(__cpu_method_of_table_end);
+
static const struct cpu_operations * __init cpu_get_ops(const char *name)
{
- const struct cpu_operations **ops = supported_cpu_ops;
-
- while (*ops) {
- if (!strcmp(name, (*ops)->name))
- return *ops;
+ const struct cpu_operations **start = (void *)__cpu_method_of_table;
- ops++;
- }
+ for (; *start; start++) {
+ if (!strcmp((*start)->name, name))
+ return *start;
+ };
return NULL;
}
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index aa94a88f6279..d8f6991fc9c8 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -235,3 +235,4 @@ const struct cpu_operations cpu_psci_ops = {
#endif
};
+CPU_METHOD_OF_DECLARE(psci, &cpu_psci_ops);
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index dbdaacddd9a5..38d3b6bf27ac 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -63,6 +63,7 @@
* where to place its SVC stack
*/
struct secondary_data secondary_data;
+volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
enum ipi_msg_type {
IPI_RESCHEDULE,
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index aef3605a8c47..3d5325d99e8e 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -28,9 +28,6 @@
#include <asm/io.h>
#include <asm/smp_plat.h>
-extern void secondary_holding_pen(void);
-volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
-
static phys_addr_t cpu_release_addr[NR_CPUS];
/*
@@ -125,9 +122,10 @@ static int smp_spin_table_cpu_boot(unsigned int cpu)
return 0;
}
-const struct cpu_operations smp_spin_table_ops = {
+static const struct cpu_operations smp_spin_table_ops = {
.name = "spin-table",
.cpu_init = smp_spin_table_cpu_init,
.cpu_prepare = smp_spin_table_cpu_prepare,
.cpu_boot = smp_spin_table_cpu_boot,
};
+CPU_METHOD_OF_DECLARE(spin_table, &smp_spin_table_ops);
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index eb48d5df4a0f..a17430174087 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -113,7 +113,7 @@ ENTRY(__inval_cache_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-__dma_inv_range:
+ENTRY(__dma_inv_range)
dcache_line_size x2, x3
sub x3, x2, #1
tst x1, x3 // end cache line aligned?
@@ -139,7 +139,7 @@ ENDPROC(__dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-__dma_clean_range:
+ENTRY(__dma_clean_range)
dcache_line_size x2, x3
sub x3, x2, #1
bic x0, x0, x3
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index d895529268a6..2ae5dbbe0d86 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -23,10 +23,15 @@
#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
+#include <linux/mm.h>
+#include <linux/iommu.h>
#include <linux/vmalloc.h>
#include <linux/swiotlb.h>
#include <asm/cacheflush.h>
+#include <asm/dma-iommu.h>
+
+#include "mm.h"
struct dma_map_ops *dma_ops;
EXPORT_SYMBOL(dma_ops);
@@ -34,7 +39,11 @@ EXPORT_SYMBOL(dma_ops);
static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
bool coherent)
{
- if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+ if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+ return pgprot_writecombine(prot);
+ else if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
+ prot = pgprot_noncached(prot);
+ else if (!coherent)
return pgprot_writecombine(prot);
return prot;
}
@@ -533,3 +542,1031 @@ static int __init dma_debug_do_init(void)
return 0;
}
fs_initcall(dma_debug_do_init);
+
+#ifdef CONFIG_ARM64_DMA_USE_IOMMU
+
+/*
+ * Make an area consistent for devices.
+ * Note: Drivers should NOT use this function directly, as it will break
+ * platforms with CONFIG_DMABOUNCE.
+ * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ */
+static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ __dma_map_area(page_address(page) + off, size, dir);
+}
+
+static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ __dma_unmap_area(page_address(page) + off, size, dir);
+
+ /*
+ * Mark the D-cache clean for this page to avoid extra flushing.
+ */
+ if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
+ set_bit(PG_dcache_clean, &page->flags);
+}
+
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
+{
+ if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+ *dev->dma_mask = dma_mask;
+
+ return 0;
+}
+
+/* IOMMU */
+
+static void __dma_clear_buffer(struct page *page, size_t size,
+ struct dma_attrs *attrs)
+{
+ /*
+ * Ensure that the allocated pages are zeroed, and that any data
+ * lurking in the kernel direct-mapped region is invalidated.
+ */
+ void *ptr = page_address(page);
+ if (!dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs))
+ memset(ptr, 0, size);
+ dmac_flush_range(ptr, ptr + size);
+}
+
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+ size_t size)
+{
+ unsigned int order = get_order(size);
+ unsigned int align = 0;
+ unsigned int count, start;
+ unsigned long flags;
+
+ if (order > CONFIG_ARM64_DMA_IOMMU_ALIGNMENT)
+ order = CONFIG_ARM64_DMA_IOMMU_ALIGNMENT;
+
+ count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ if (order > mapping->order)
+ align = (1 << (order - mapping->order)) - 1;
+
+ spin_lock_irqsave(&mapping->lock, flags);
+ start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+ count, align);
+ if (start > mapping->bits) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return DMA_ERROR_CODE;
+ }
+
+ bitmap_set(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
+
+ return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+}
+
+static inline void __free_iova(struct dma_iommu_mapping *mapping,
+ dma_addr_t addr, size_t size)
+{
+ unsigned int start = (addr - mapping->base) >>
+ (mapping->order + PAGE_SHIFT);
+ unsigned int count = ((size >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mapping->lock, flags);
+ bitmap_clear(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
+}
+
+static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
+ gfp_t gfp, struct dma_attrs *attrs)
+{
+ struct page **pages;
+ int count = size >> PAGE_SHIFT;
+ int array_size = count * sizeof(struct page *);
+ int i = 0;
+
+ if (array_size <= PAGE_SIZE)
+ pages = kzalloc(array_size, gfp);
+ else
+ pages = vzalloc(array_size);
+ if (!pages)
+ return NULL;
+
+ if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
+ unsigned long order = get_order(size);
+ struct page *page;
+
+ page = dma_alloc_from_contiguous(dev, count, order);
+ if (!page)
+ goto error;
+
+ __dma_clear_buffer(page, size, attrs);
+
+ for (i = 0; i < count; i++)
+ pages[i] = page + i;
+
+ return pages;
+ }
+
+ /*
+ * IOMMU can map any pages, so himem can also be used here
+ */
+ gfp |= __GFP_NOWARN | __GFP_HIGHMEM;
+
+ while (count) {
+ int j, order = __fls(count);
+
+ pages[i] = alloc_pages(gfp, order);
+ while (!pages[i] && order)
+ pages[i] = alloc_pages(gfp, --order);
+ if (!pages[i])
+ goto error;
+
+ if (order) {
+ split_page(pages[i], order);
+ j = 1 << order;
+ while (--j)
+ pages[i + j] = pages[i] + j;
+ }
+
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs);
+ i += 1 << order;
+ count -= 1 << order;
+ }
+
+ return pages;
+error:
+ while (i--)
+ if (pages[i])
+ __free_pages(pages[i], 0);
+ if (array_size <= PAGE_SIZE)
+ kfree(pages);
+ else
+ vfree(pages);
+ return NULL;
+}
+
+static int __iommu_free_buffer(struct device *dev, struct page **pages,
+ size_t size, struct dma_attrs *attrs)
+{
+ int count = size >> PAGE_SHIFT;
+ int array_size = count * sizeof(struct page *);
+ int i;
+
+ if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
+ dma_release_from_contiguous(dev, pages[0], count);
+ } else {
+ for (i = 0; i < count; i++)
+ if (pages[i])
+ __free_pages(pages[i], 0);
+ }
+
+ if (array_size <= PAGE_SIZE)
+ kfree(pages);
+ else
+ vfree(pages);
+ return 0;
+}
+
+/*
+ * Create a CPU mapping for a specified pages
+ */
+static void *
+__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
+ const void *caller)
+{
+ return dma_common_pages_remap(pages, size, VM_USERMAP, prot, caller);
+}
+
+/*
+ * Create a mapping in device IO address space for specified pages
+ */
+static dma_addr_t
+__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ dma_addr_t dma_addr, iova;
+ int i, ret;
+
+ dma_addr = __alloc_iova(mapping, size);
+ if (dma_addr == DMA_ERROR_CODE)
+ return dma_addr;
+
+ iova = dma_addr;
+ for (i = 0; i < count; ) {
+ unsigned int next_pfn = page_to_pfn(pages[i]) + 1;
+ phys_addr_t phys = page_to_phys(pages[i]);
+ unsigned int len, j;
+
+ for (j = i + 1; j < count; j++, next_pfn++)
+ if (page_to_pfn(pages[j]) != next_pfn)
+ break;
+
+ len = (j - i) << PAGE_SHIFT;
+ ret = iommu_map(mapping->domain, iova, phys, len,
+ IOMMU_READ|IOMMU_WRITE);
+ if (ret < 0)
+ goto fail;
+ iova += len;
+ i = j;
+ }
+ return dma_addr;
+fail:
+ iommu_unmap(mapping->domain, dma_addr, iova-dma_addr);
+ __free_iova(mapping, dma_addr, size);
+ return DMA_ERROR_CODE;
+}
+
+static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova,
+ size_t size)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+ /*
+ * add optional in-page offset from iova to size and align
+ * result to page size
+ */
+ size = PAGE_ALIGN((iova & ~PAGE_MASK) + size);
+ iova &= PAGE_MASK;
+
+ iommu_unmap(mapping->domain, iova, size);
+ __free_iova(mapping, iova, size);
+ return 0;
+}
+
+static struct page **__atomic_get_pages(void *addr)
+{
+ struct page *page;
+ phys_addr_t phys;
+
+ phys = gen_pool_virt_to_phys(atomic_pool, (unsigned long)addr);
+ page = phys_to_page(phys);
+
+ return (struct page **)page;
+}
+
+static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
+{
+ struct vm_struct *area;
+
+ if (__in_atomic_pool(cpu_addr, PAGE_SIZE))
+ return __atomic_get_pages(cpu_addr);
+
+ if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+ return cpu_addr;
+
+ area = find_vm_area(cpu_addr);
+ if (area)
+ return area->pages;
+ return NULL;
+}
+
+static void *__iommu_alloc_atomic(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t flags)
+{
+ struct page *page;
+ void *addr;
+
+ addr = __alloc_from_pool(size, &page, flags);
+ if (!addr)
+ return NULL;
+
+ *handle = __iommu_create_mapping(dev, &page, size);
+ if (*handle == DMA_ERROR_CODE)
+ goto err_mapping;
+
+ return addr;
+
+err_mapping:
+ __free_from_pool(addr, size);
+ return NULL;
+}
+
+static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
+ dma_addr_t handle, size_t size)
+{
+ __iommu_remove_mapping(dev, handle, size);
+ __free_from_pool(cpu_addr, size);
+}
+
+static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL,
+ is_device_dma_coherent(dev));
+ struct page **pages;
+ void *addr = NULL;
+
+ *handle = DMA_ERROR_CODE;
+ size = PAGE_ALIGN(size);
+
+ if (!(gfp & __GFP_WAIT))
+ return __iommu_alloc_atomic(dev, size, handle, gfp);
+
+ /*
+ * Following is a work-around (a.k.a. hack) to prevent pages
+ * with __GFP_COMP being passed to split_page() which cannot
+ * handle them. The real problem is that this flag probably
+ * should be 0 on ARM as it is not supported on this
+ * platform; see CONFIG_HUGETLBFS.
+ */
+ gfp &= ~(__GFP_COMP);
+
+ pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
+ if (!pages)
+ return NULL;
+
+ *handle = __iommu_create_mapping(dev, pages, size);
+ if (*handle == DMA_ERROR_CODE)
+ goto err_buffer;
+
+ if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+ return pages;
+
+ addr = __iommu_alloc_remap(pages, size, gfp, prot,
+ __builtin_return_address(0));
+ if (!addr)
+ goto err_mapping;
+
+ return addr;
+
+err_mapping:
+ __iommu_remove_mapping(dev, *handle, size);
+err_buffer:
+ __iommu_free_buffer(dev, pages, size, attrs);
+ return NULL;
+}
+
+static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ unsigned long uaddr = vma->vm_start;
+ unsigned long usize = vma->vm_end - vma->vm_start;
+ struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
+ is_device_dma_coherent(dev));
+
+ if (!pages)
+ return -ENXIO;
+
+ do {
+ int ret = vm_insert_page(vma, uaddr, *pages++);
+ if (ret) {
+ pr_err("Remapping memory failed: %d\n", ret);
+ return ret;
+ }
+ uaddr += PAGE_SIZE;
+ usize -= PAGE_SIZE;
+ } while (usize > 0);
+
+ return 0;
+}
+
+/*
+ * free a page as defined by the above mapping.
+ * Must not be called with IRQs disabled.
+ */
+void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs)
+{
+ struct page **pages;
+ size = PAGE_ALIGN(size);
+
+ if (__in_atomic_pool(cpu_addr, size)) {
+ __iommu_free_atomic(dev, cpu_addr, handle, size);
+ return;
+ }
+
+ pages = __iommu_get_pages(cpu_addr, attrs);
+ if (!pages) {
+ WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+ return;
+ }
+
+ if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+ dma_common_free_remap(cpu_addr, size, VM_USERMAP);
+
+ __iommu_remove_mapping(dev, handle, size);
+ __iommu_free_buffer(dev, pages, size, attrs);
+}
+
+int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t dma_addr,
+ size_t size, struct dma_attrs *attrs)
+{
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+
+ if (!pages)
+ return -ENXIO;
+
+ return sg_alloc_table_from_pages(sgt, pages, count, 0, size,
+ GFP_KERNEL);
+}
+
+static int __dma_direction_to_prot(enum dma_data_direction dir)
+{
+ int prot;
+
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ prot = IOMMU_READ | IOMMU_WRITE;
+ break;
+ case DMA_TO_DEVICE:
+ prot = IOMMU_READ;
+ break;
+ case DMA_FROM_DEVICE:
+ prot = IOMMU_WRITE;
+ break;
+ default:
+ prot = 0;
+ }
+
+ return prot;
+}
+
+/*
+ * Map a part of the scatter-gather list into contiguous io address space
+ */
+static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
+ size_t size, dma_addr_t *handle,
+ enum dma_data_direction dir, struct dma_attrs *attrs,
+ bool is_coherent)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova, iova_base;
+ int ret = 0;
+ unsigned int count;
+ struct scatterlist *s;
+ int prot;
+
+ size = PAGE_ALIGN(size);
+ *handle = DMA_ERROR_CODE;
+
+ iova_base = iova = __alloc_iova(mapping, size);
+ if (iova == DMA_ERROR_CODE)
+ return -ENOMEM;
+
+ for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
+ phys_addr_t phys = page_to_phys(sg_page(s));
+ unsigned int len = PAGE_ALIGN(s->offset + s->length);
+
+ if (!is_coherent &&
+ !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length,
+ dir);
+
+ prot = __dma_direction_to_prot(dir);
+
+ ret = iommu_map(mapping->domain, iova, phys, len, prot);
+ if (ret < 0)
+ goto fail;
+ count += len >> PAGE_SHIFT;
+ iova += len;
+ }
+ *handle = iova_base;
+
+ return 0;
+fail:
+ iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE);
+ __free_iova(mapping, iova_base, size);
+ return ret;
+}
+
+static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs,
+ bool is_coherent)
+{
+ struct scatterlist *s = sg, *dma = sg, *start = sg;
+ int i, count = 0;
+ unsigned int offset = s->offset;
+ unsigned int size = s->offset + s->length;
+ unsigned int max = dma_get_max_seg_size(dev);
+
+ for (i = 1; i < nents; i++) {
+ s = sg_next(s);
+
+ s->dma_address = DMA_ERROR_CODE;
+ s->dma_length = 0;
+
+ if (s->offset || (size & ~PAGE_MASK)
+ || size + s->length > max) {
+ if (__map_sg_chunk(dev, start, size, &dma->dma_address,
+ dir, attrs, is_coherent) < 0)
+ goto bad_mapping;
+
+ dma->dma_address += offset;
+ dma->dma_length = size - offset;
+
+ size = offset = s->offset;
+ start = s;
+ dma = sg_next(dma);
+ count += 1;
+ }
+ size += s->length;
+ }
+ if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs,
+ is_coherent) < 0)
+ goto bad_mapping;
+
+ dma->dma_address += offset;
+ dma->dma_length = size - offset;
+
+ return count+1;
+
+bad_mapping:
+ for_each_sg(sg, s, count, i)
+ __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+ return 0;
+}
+
+/**
+ * arm_coherent_iommu_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of i/o coherent buffers described by scatterlist in streaming
+ * mode for DMA. The scatter gather list elements are merged together (if
+ * possible) and tagged with the appropriate dma address and length. They are
+ * obtained via sg_dma_{address,length}.
+ */
+int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ return __iommu_map_sg(dev, sg, nents, dir, attrs, true);
+}
+
+static int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+ struct scatterlist *sg, unsigned int len, int opt)
+{
+ s32 ret = 0;
+ u32 offset = 0;
+ u32 start_iova = iova;
+
+ BUG_ON(iova & (~PAGE_MASK));
+
+ while (offset < len) {
+ phys_addr_t phys = page_to_phys(sg_page(sg));
+ u32 page_len = PAGE_ALIGN(sg->offset + sg->length);
+
+ ret = iommu_map(domain, iova, phys, page_len, opt);
+ if (ret)
+ goto fail;
+
+ iova += page_len;
+ offset += page_len;
+ if (offset < len)
+ sg = sg_next(sg);
+ }
+
+ goto out;
+
+fail:
+ /* undo mappings already done in case of error */
+ iommu_unmap(domain, start_iova, offset);
+out:
+
+ return ret;
+}
+
+/**
+ * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * The scatter gather list elements are merged together (if possible) and
+ * tagged with the appropriate dma address and length. They are obtained via
+ * sg_dma_{address,length}.
+ */
+int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int ret, i;
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int iova, total_length = 0, current_offset = 0;
+ int prot = __dma_direction_to_prot(dir);
+
+ for_each_sg(sg, s, nents, i)
+ total_length += s->length;
+
+ iova = __alloc_iova(mapping, total_length);
+ ret = iommu_map_range(mapping->domain, iova, sg, total_length, prot);
+ if (ret) {
+ __free_iova(mapping, iova, total_length);
+ return 0;
+ }
+
+ for_each_sg(sg, s, nents, i) {
+ s->dma_address = iova + current_offset;
+ s->dma_length = total_length - current_offset;
+ current_offset += s->length;
+ }
+
+ return nents;
+}
+
+static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs,
+ bool is_coherent)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ if (sg_dma_len(s))
+ __iommu_remove_mapping(dev, sg_dma_address(s),
+ sg_dma_len(s));
+ if (!is_coherent &&
+ !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
+ }
+}
+
+/**
+ * arm_coherent_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations. Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ __iommu_unmap_sg(dev, sg, nents, dir, attrs, true);
+}
+
+/**
+ * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations. Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int total_length = sg_dma_len(sg);
+ unsigned int iova = sg_dma_address(sg);
+
+ total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length);
+ iova &= PAGE_MASK;
+
+ iommu_unmap(mapping->domain, iova, total_length);
+ __free_iova(mapping, iova, total_length);
+}
+
+/**
+ * arm_iommu_sync_sg_for_cpu
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i)
+ __dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
+
+}
+
+/**
+ * arm_iommu_sync_sg_for_device
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i)
+ __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+}
+
+
+/**
+ * arm_coherent_iommu_map_page
+ * @dev: valid struct device pointer
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Coherent IOMMU aware version of arm_dma_map_page()
+ */
+static dma_addr_t arm_coherent_iommu_map_page(struct device *dev,
+ struct page *page, unsigned long offset, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t dma_addr;
+ int ret, prot, len = PAGE_ALIGN(size + offset);
+
+ dma_addr = __alloc_iova(mapping, len);
+ if (dma_addr == DMA_ERROR_CODE)
+ return dma_addr;
+
+ prot = __dma_direction_to_prot(dir);
+
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len,
+ prot);
+ if (ret < 0)
+ goto fail;
+
+ return dma_addr + offset;
+fail:
+ __free_iova(mapping, dma_addr, len);
+ return DMA_ERROR_CODE;
+}
+
+/**
+ * arm_iommu_map_page
+ * @dev: valid struct device pointer
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * IOMMU aware version of arm_dma_map_page()
+ */
+static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+
+ return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
+}
+
+/**
+ * arm_coherent_iommu_unmap_page
+ * @dev: valid struct device pointer
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * Coherent IOMMU aware version of arm_dma_unmap_page()
+ */
+static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ int offset = handle & ~PAGE_MASK;
+ int len = PAGE_ALIGN(size + offset);
+
+ if (!iova)
+ return;
+
+ iommu_unmap(mapping->domain, iova, len);
+ __free_iova(mapping, iova, len);
+}
+
+/**
+ * arm_iommu_unmap_page
+ * @dev: valid struct device pointer
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * IOMMU aware version of arm_dma_unmap_page()
+ */
+static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(
+ mapping->domain, iova));
+ int offset = handle & ~PAGE_MASK;
+ int len = PAGE_ALIGN(size + offset);
+
+ if (!iova)
+ return;
+
+ if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+
+ iommu_unmap(mapping->domain, iova, len);
+ __free_iova(mapping, iova, len);
+}
+
+static void arm_iommu_sync_single_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(
+ mapping->domain, iova));
+ unsigned int offset = handle & ~PAGE_MASK;
+
+ if (!iova)
+ return;
+
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_iommu_sync_single_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(
+ mapping->domain, iova));
+ unsigned int offset = handle & ~PAGE_MASK;
+
+ if (!iova)
+ return;
+
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+const struct dma_map_ops iommu_ops = {
+ .alloc = arm_iommu_alloc_attrs,
+ .free = arm_iommu_free_attrs,
+ .mmap = arm_iommu_mmap_attrs,
+ .get_sgtable = arm_iommu_get_sgtable,
+
+ .map_page = arm_iommu_map_page,
+ .unmap_page = arm_iommu_unmap_page,
+ .sync_single_for_cpu = arm_iommu_sync_single_for_cpu,
+ .sync_single_for_device = arm_iommu_sync_single_for_device,
+
+ .map_sg = arm_iommu_map_sg,
+ .unmap_sg = arm_iommu_unmap_sg,
+ .sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu,
+ .sync_sg_for_device = arm_iommu_sync_sg_for_device,
+
+ .set_dma_mask = arm_dma_set_mask,
+};
+
+const struct dma_map_ops iommu_coherent_ops = {
+ .alloc = arm_iommu_alloc_attrs,
+ .free = arm_iommu_free_attrs,
+ .mmap = arm_iommu_mmap_attrs,
+ .get_sgtable = arm_iommu_get_sgtable,
+
+ .map_page = arm_coherent_iommu_map_page,
+ .unmap_page = arm_coherent_iommu_unmap_page,
+
+ .map_sg = arm_coherent_iommu_map_sg,
+ .unmap_sg = arm_coherent_iommu_unmap_sg,
+
+ .set_dma_mask = arm_dma_set_mask,
+};
+
+/**
+ * arm_iommu_create_mapping
+ * @bus: pointer to the bus holding the client device (for IOMMU calls)
+ * @base: start address of the valid IO address space
+ * @size: size of the valid IO address space
+ * @order: accuracy of the IO addresses allocations
+ *
+ * Creates a mapping structure which holds information about used/unused
+ * IO address ranges, which is required to perform memory allocation and
+ * mapping with IOMMU aware functions.
+ *
+ * The client device need to be attached to the mapping with
+ * arm_iommu_attach_device function.
+ */
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+ int order)
+{
+ unsigned int count = size >> (PAGE_SHIFT + order);
+ unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ struct dma_iommu_mapping *mapping;
+ int err = -ENOMEM;
+
+ if (!count)
+ return ERR_PTR(-EINVAL);
+
+ mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
+ if (!mapping)
+ goto err;
+
+ mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mapping->bitmap)
+ goto err2;
+
+ mapping->base = base;
+ mapping->bits = BITS_PER_BYTE * bitmap_size;
+ mapping->order = order;
+ spin_lock_init(&mapping->lock);
+
+ mapping->domain = iommu_domain_alloc(bus);
+ if (!mapping->domain)
+ goto err3;
+
+ kref_init(&mapping->kref);
+ return mapping;
+err3:
+ kfree(mapping->bitmap);
+err2:
+ kfree(mapping);
+err:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(arm_iommu_create_mapping);
+
+static void release_iommu_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ iommu_domain_free(mapping->domain);
+ kfree(mapping->bitmap);
+ kfree(mapping);
+}
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+ if (mapping)
+ kref_put(&mapping->kref, release_iommu_mapping);
+}
+EXPORT_SYMBOL(arm_iommu_release_mapping);
+
+/**
+ * arm_iommu_attach_device
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure (returned from
+ * arm_iommu_create_mapping)
+ *
+ * Attaches specified io address space mapping to the provided device,
+ * this replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version. More than one client might be attached to
+ * the same io address space mapping.
+ */
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ int err;
+
+ err = iommu_attach_device(mapping->domain, dev);
+ if (err)
+ return err;
+
+ kref_get(&mapping->kref);
+ dev->archdata.mapping = mapping;
+ dev->archdata.dma_ops = &iommu_ops;
+ pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
+ return 0;
+}
+EXPORT_SYMBOL(arm_iommu_attach_device);
+
+/**
+ * arm_iommu_detach_device
+ * @dev: valid struct device pointer
+ *
+ * Detaches the provided device from a previously attached map.
+ * This voids the dma operations (dma_map_ops pointer)
+ */
+void arm_iommu_detach_device(struct device *dev)
+{
+ struct dma_iommu_mapping *mapping;
+
+ mapping = to_dma_iommu_mapping(dev);
+ if (!mapping) {
+ dev_warn(dev, "Not attached\n");
+ return;
+ }
+
+ iommu_detach_device(mapping->domain, dev);
+ kref_put(&mapping->kref, release_iommu_mapping);
+ dev->archdata.mapping = NULL;
+ dev->archdata.dma_ops = NULL;
+
+ pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
+}
+EXPORT_SYMBOL(arm_iommu_detach_device);
+
+#endif