diff options
author | Andy Green <andy.green@linaro.org> | 2014-12-04 11:32:29 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2014-12-04 19:00:45 +0800 |
commit | 5cde20a8d186df94e7c1c6c931a7a7180c16a75d (patch) | |
tree | c48359cedd0c1ea9c56a7c3cfe60e318fb09d80c | |
parent | a717d8b580c536b0b60206489a373c18df927e20 (diff) |
delta arch armmainline-basis-test-2014-12-04-2
Signed-off-by: Andy Green <andy.green@linaro.org>
159 files changed, 24061 insertions, 336 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 89c4b5ccc68d..f65f744418d6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -217,6 +217,9 @@ config NEED_RET_TO_USER config ARCH_MTD_XIP bool +config ARCH_WANT_KMAP_ATOMIC_FLUSH + bool + config VECTORS_BASE hex default 0xffff0000 if MMU || CPU_HIGH_VECTOR @@ -283,6 +286,24 @@ config GENERIC_BUG def_bool y depends on BUG +config ARM_USER_ACCESSIBLE_TIMER_BASE + hex "Base address of user-accessible timer counter page" + default 0xfffef000 + depends on ARM_USE_USER_ACCESSIBLE_TIMERS + help + Specify the base user-space virtual address where the user-accessible + timer counter page should be mapped by the kernel. User-space apps + will read directly from the page at this address. + +config ARCH_RANDOM + bool "SOC specific random number generation" + help + Allow the kernel to use an architecture specific implementation for + random number generation + + If unsure, say N + + source "init/Kconfig" source "kernel/Kconfig.freezer" @@ -639,9 +660,22 @@ config ARCH_PXA config ARCH_MSM bool "Qualcomm MSM (non-multiplatform)" + select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select COMMON_CLK select GENERIC_CLOCKEVENTS + select GENERIC_GPIO + select GENERIC_TIME + select GENERIC_ALLOCATOR + select HAVE_CLK + select HAVE_CLK_PREPARE + select NEED_MACH_MEMORY_H + select NEED_MACH_IO_H + select NEED_MACH_GPIO_H + select SOC_BUS + select MULTI_IRQ_HANDLER + select SPARSE_IRQ + select USE_OF help Support for Qualcomm MSM/QSD based systems. This runs on the apps processor of the MSM/QSD and depends on a shared memory @@ -1009,6 +1043,15 @@ source "arch/arm/firmware/Kconfig" source arch/arm/mm/Kconfig +config RESERVE_FIRST_PAGE + bool + default n + help + Reserve the first page at PHYS_OFFSET. The first + physical page is used by many platforms for warm + boot operations. Reserve this page so that it is + not allocated by the kernel. + config IWMMXT bool "Enable iWMMXt support" depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4 || CPU_PJ4B @@ -1253,6 +1296,12 @@ config ARM_ERRATA_773022 loop buffer may deliver incorrect instructions. This workaround disables the loop buffer to avoid the erratum. +config PERFMAP + tristate "Perfmap support (EXPERIMENTAL)" + depends on ARCH_MSM_KRAIT + help + Perfmap: memory mapped interface for performance monitors. + endmenu source "arch/arm/common/Kconfig" @@ -1707,6 +1756,42 @@ config ARCH_WANT_GENERAL_HUGETLB source "mm/Kconfig" +config ARCH_MEMORY_PROBE + def_bool n + +config ARCH_MEMORY_REMOVE + def_bool n + +config ENABLE_DMM + def_bool n + +choice + prompt "Virtual Memory Reclaim" + default NO_VM_RECLAIM + help + Select the method of reclaiming virtual memory + +config ENABLE_VMALLOC_SAVING + bool "Reclaim memory for each subsystem" + help + Enable this config to reclaim the virtual space belonging + to any subsystem which is expected to have a lifetime of + the entire system. This feature allows lowmem to be non- + contiguous. + +config NO_VM_RECLAIM + bool "Do not reclaim memory" + help + Do not reclaim any memory. This might result in less lowmem + and wasting virtual memory space which could otherwise be + reclaimed by using any of the other two config options. + +endchoice + +config HOLES_IN_ZONE + def_bool n + depends on SPARSEMEM + config FORCE_MAX_ZONEORDER int "Maximum zone order" if ARCH_SHMOBILE_LEGACY range 11 64 if ARCH_SHMOBILE_LEGACY @@ -1790,6 +1875,26 @@ config XEN help Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. +config CP_ACCESS + tristate "CP register access tool" + default m + help + Provide support for Coprocessor register access using /sys + interface. Read and write to CP registers from userspace + through sysfs interface. A sys file (cp_rw) will be created under + /sys/devices/cpaccess/cpaccess0. + + If unsure, say N. + +config ARM_FLUSH_CONSOLE_ON_RESTART + bool "Force flush the console on restart" + help + If the console is locked while the system is rebooted, the messages + in the temporary logbuffer would not have propogated to all the + console drivers. This option forces the console lock to be + released if it failed to be acquired, which will cause all the + pending messages to be flushed. + endmenu menu "Boot options" @@ -1820,6 +1925,21 @@ config DEPRECATED_PARAM_STRUCT This was deprecated in 2001 and announced to live on for 5 years. Some old boot loaders still use this way. +config BUILD_ARM_APPENDED_DTB_IMAGE + bool "Build a concatenated zImage/dtb by default" + depends on OF + help + Enabling this option will cause a concatenated zImage and list of + DTBs to be built by default (instead of a standalone zImage.) + The image will built in arch/arm/boot/zImage-dtb + +config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES + string "Default dtb names" + depends on BUILD_ARM_APPENDED_DTB_IMAGE + help + Space separated list of names of dtbs to append when + building a concatenated zImage-dtb. + # Compressed boot loader in ROM. Yes, we really want to ask about # TEXT and BSS so we preserve their values in the config files. config ZBOOT_ROM_TEXT @@ -2043,6 +2163,17 @@ config AUTO_ZRELADDR 0xf8000000. This assumes the zImage being placed in the first 128MB from start of memory. +config ARM_DECOMPRESSOR_LIMIT + hex "Limit the decompressor memory area" + default 0x10000000 + help + Allows overriding of the memory size that decompressor maps with + read, write and execute permissions to avoid speculative prefetch. + + By default ARM_DECOMPRESSOR_LIMIT maps first 1GB of memory + with read, write and execute permissions and reset of the memory + as strongly ordered. + endmenu menu "CPU Power Management" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index d8f6a2ec3d4e..797730343ae6 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -75,6 +75,29 @@ config DEBUG_USER 8 - SIGSEGV faults 16 - SIGBUS faults +config FORCE_PAGES + bool "Force lowmem to be mapped with 4K pages" + help + There are some advanced debug features that can only be done when + memory is mapped with pages instead of sections. Enable this option + to always map lowmem pages with pages. This may have a performance + cost due to increased TLB pressure. + + If unsure say N. + +config FREE_PAGES_RDONLY + bool "Set pages as read only while on the buddy list" + select FORCE_PAGES + select PAGE_POISONING + help + Pages are always mapped in the kernel. This means that anyone + can write to the page if they have the address. Enable this option + to mark pages as read only to trigger a fault if any code attempts + to write to a page on the buddy list. This may have a performance + impact. + + If unsure, say N. + # These options are only for real kernel hackers who want to get their hands dirty. config DEBUG_LL bool "Kernel low-level debugging functions (read help!)" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 034a94904d69..4d21d84ba867 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -70,6 +70,18 @@ arch-$(CONFIG_CPU_32v3) =-D__LINUX_ARM_ARCH__=3 -march=armv3 # Evaluate arch cc-option calls now arch-y := $(arch-y) +# Since 'cortex-a15' is a superset of the 'armv7-a' arch spec, we need to +# explicitly redefine the arch options to not include '-march=armv7-a' when +# generating code for Krait, which is compatible with the instruction set of the +# Cortex-A15, because GCC will warn us about ambiguous ISA restrictions caused +# by seemingly conflicting -march and -mcpu options. +# If $(CC) does not support the -mcpu=cortex-a15 option, fall back on passing +# -march=armv7-a to specify the ISA restriction, though this is suboptimal. To +# keep things simpler, we don't bother with a fallback option if the compiler +# doesn't even support -march=armv7-a, since in that situation we would have +# bigger problems. +arch-$(CONFIG_ARCH_MSM_KRAIT) :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-mcpu=cortex-a15,-march=armv7-a) + # This selects how we optimise for the processor. tune-$(CONFIG_CPU_ARM7TDMI) =-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM720T) =-mtune=arm7tdmi @@ -278,6 +290,8 @@ libs-y := arch/arm/lib/ $(libs-y) # Default target when executing plain make ifeq ($(CONFIG_XIP_KERNEL),y) KBUILD_IMAGE := xipImage +else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y) +KBUILD_IMAGE := zImage-dtb else KBUILD_IMAGE := zImage endif @@ -315,6 +329,9 @@ PHONY += dtbs dtbs_install dtbs dtbs_install: prepare scripts $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@ +zImage-dtb: vmlinux scripts dtbs + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ + # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore index 3c79f85975aa..ad7a0253ea96 100644 --- a/arch/arm/boot/.gitignore +++ b/arch/arm/boot/.gitignore @@ -4,3 +4,4 @@ xipImage bootpImage uImage *.dtb +zImage-dtb
\ No newline at end of file diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index ec2f8065f955..13ccec54b094 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -27,6 +27,14 @@ export ZRELADDR INITRD_PHYS PARAMS_PHYS targets := Image zImage xipImage bootpImage uImage +DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES)) +ifneq ($(DTB_NAMES),) +DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) +else +DTB_LIST := $(dtb-y) +endif +DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST)) + ifeq ($(CONFIG_XIP_KERNEL),y) $(obj)/xipImage: vmlinux FORCE @@ -55,6 +63,12 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) @$(kecho) ' Kernel: $@ is ready' +$(obj)/zImage-dtb: $(obj)/zImage $(DTB_OBJS) FORCE + @echo 1 + $(call if_changed,cat) + @echo 2 + @echo ' Kernel: $@ is ready' + endif ifneq ($(LOADADDR),) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 68be9017593d..e9e0284fc8f2 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -639,7 +639,7 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size mov r0, r3 mov r9, r0, lsr #18 mov r9, r9, lsl #18 @ start of RAM - add r10, r9, #0x10000000 @ a reasonable RAM size + add r10, r9, #CONFIG_ARM_DECOMPRESSOR_LIMIT mov r1, #0x12 @ XN|U + section mapping orr r1, r1, #3 << 10 @ AP=11 add r2, r3, #16384 @@ -730,6 +730,8 @@ __armv7_mmu_cache_on: bic r6, r6, #1 << 31 @ 32-bit translation system bic r6, r6, #3 << 0 @ use only ttbr0 mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer + mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + mcr p15, 0, r0, c7, c5, 4 @ ISB mcrne p15, 0, r1, c3, c0, 0 @ load domain access control mcrne p15, 0, r6, c2, c0, 2 @ load ttb control #endif diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 38c89cafa1ab..c0ae2c8f1ab5 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -519,11 +519,23 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aquaris5.dtb targets += dtbs dtbs_install targets += $(dtb-y) +DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES)) +ifneq ($(DTB_NAMES),) +DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) +else +DTB_LIST := $(dtb-y) +endif + +targets += dtbs +targets += $(DTB_LIST) + +#used for cleaning - not building +subdir- := qcom endif # *.dtb used to be generated in the directory above. Clean out the # old build results so people don't accidentally use them. -dtbs: $(addprefix $(obj)/, $(dtb-y)) +dtbs: $(addprefix $(obj)/, $(DTB_LIST)) $(Q)rm -f $(obj)/../*.dtb clean-files := *.dtb diff --git a/arch/arm/boot/dts/msm-gdsc-8916.dtsi b/arch/arm/boot/dts/msm-gdsc-8916.dtsi new file mode 100644 index 000000000000..891e59867d8f --- /dev/null +++ b/arch/arm/boot/dts/msm-gdsc-8916.dtsi @@ -0,0 +1,63 @@ +/* + * 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 { + gdsc_venus: qcom,gdsc@184c018 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus"; + reg = <0x184c018 0x4>; + status = "disabled"; + }; + + gdsc_mdss: qcom,gdsc@184d078 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_mdss"; + reg = <0x184d078 0x4>; + status = "disabled"; + }; + + gdsc_jpeg: qcom,gdsc@185701c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_jpeg"; + reg = <0x185701c 0x4>; + status = "disabled"; + }; + + gdsc_vfe: qcom,gdsc@1858034 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vfe"; + reg = <0x1858034 0x4>; + status = "disabled"; + }; + + gdsc_oxili_gx: qcom,gdsc@185901c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_oxili_gx"; + reg = <0x185901c 0x4>; + status = "disabled"; + }; + + gdsc_venus_core0: qcom,gdsc@184c028 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core0"; + reg = <0x184c028 0x4>; + status = "disabled"; + }; + + gdsc_venus_core1: qcom,gdsc@184c030 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core1"; + reg = <0x184c030 0x4>; + status = "disabled"; + }; +}; diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi new file mode 100644 index 000000000000..9a1f32eb0c7a --- /dev/null +++ b/arch/arm/boot/dts/msm-gdsc.dtsi @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2012-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 { + gdsc_venus: qcom,gdsc@fd8c1024 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus"; + reg = <0xfd8c1024 0x4>; + status = "disabled"; + }; + + gdsc_venus_core0: qcom,gdsc@fd8c1040 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core0"; + reg = <0xfd8c1040 0x4>; + status = "disabled"; + }; + + gdsc_venus_core1: qcom,gdsc@fd8c1044 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core1"; + reg = <0xfd8c1044 0x4>; + status = "disabled"; + }; + + gdsc_venus_core2: qcom,gdsc@fd8c1050 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core2"; + reg = <0xfd8c1050 0x4>; + status = "disabled"; + }; + + gdsc_vpu: qcom,gdsc@fd8c1404 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vpu"; + reg = <0xfd8c1404 0x4>; + status = "disabled"; + }; + + gdsc_camss_top: qcom,gdsc@fd8c34a0 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_camss_top"; + reg = <0xfd8c34a0 0x4>; + status = "disabled"; + }; + + gdsc_mdss: qcom,gdsc@fd8c2304 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_mdss"; + reg = <0xfd8c2304 0x4>; + status = "disabled"; + }; + + gdsc_jpeg: qcom,gdsc@fd8c35a4 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_jpeg"; + reg = <0xfd8c35a4 0x4>; + status = "disabled"; + }; + + gdsc_vfe: qcom,gdsc@fd8c36a4 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vfe"; + reg = <0xfd8c36a4 0x4>; + status = "disabled"; + }; + + gdsc_cpp: qcom,gdsc@fd8c36d4 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_cpp"; + reg = <0xfd8c36d4 0x4>; + status = "disabled"; + }; + + gdsc_oxili_gx: qcom,gdsc@fd8c4024 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_oxili_gx"; + reg = <0xfd8c4024 0x4>; + status = "disabled"; + }; + + gdsc_oxili_cx: qcom,gdsc@fd8c4034 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_oxili_cx"; + reg = <0xfd8c4034 0x4>; + status = "disabled"; + }; + + gdsc_usb_hsic: qcom,gdsc@fc400404 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_usb_hsic"; + reg = <0xfc400404 0x4>; + status = "disabled"; + }; + + gdsc_pcie: qcom,gdsc@0xfc401e18 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_pcie"; + reg = <0xfc401e18 0x4>; + status = "disabled"; + }; + + gdsc_pcie_0: qcom,gdsc@fc401ac4 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_pcie_0"; + reg = <0xfc401ac4 0x4>; + status = "disabled"; + }; + + gdsc_pcie_1: qcom,gdsc@fc401b44 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_pcie_1"; + reg = <0xfc401b44 0x4>; + status = "disabled"; + }; + + gdsc_usb30: qcom,gdsc@fc401e84 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_usb30"; + reg = <0xfc401e84 0x4>; + status = "disabled"; + }; + + gdsc_usb30_sec: qcom,gdsc@fc401ec0 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_usb30_sec"; + reg = <0xfc401ec0 0x4>; + status = "disabled"; + }; + + gdsc_vcap: qcom,gdsc@fd8c1804 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vcap"; + reg = <0xfd8c1804 0x4>; + status = "disabled"; + }; + + gdsc_bcss: qcom,gdsc@fc744128 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_bcss"; + reg = <0xfc744128 0x4>; + status = "disabled"; + }; + + gdsc_ufs: qcom,gdsc@fc401d44 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_ufs"; + reg = <0xfc401d44 0x4>; + status = "disabled"; + }; + + gdsc_fd: qcom,gdsc@fd8c3b64 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_fd"; + reg = <0xfd8c3b64 0x4>; + status = "disabled"; + }; +}; diff --git a/arch/arm/boot/dts/msm-pm8916-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8916-rpm-regulator.dtsi new file mode 100644 index 000000000000..d5b7ea55c72b --- /dev/null +++ b/arch/arm/boot/dts/msm-pm8916-rpm-regulator.dtsi @@ -0,0 +1,365 @@ +/* Copyright (c) 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. + */ + +&rpm_bus { + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <4>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <4>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <9>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa14 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <14>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l14 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l14"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa15 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <15>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l15 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l15"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa16 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <16>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l16 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l16"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa17 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <17>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l17 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l17"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa18 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <18>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l18 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l18"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/msm-pm8916.dtsi b/arch/arm/boot/dts/msm-pm8916.dtsi new file mode 100644 index 000000000000..1a738de55bb4 --- /dev/null +++ b/arch/arm/boot/dts/msm-pm8916.dtsi @@ -0,0 +1,632 @@ +/* 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. + */ + +&spmi_bus { + + qcom,pm8916@0 { + spmi-slave-container; + reg = <0x0>; + #address-cells = <1>; + #size-cells = <1>; + + pm8916_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pm8916_pon: qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0>, + <0x0 0x8 0x1>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,system-reset; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,support-reset = <1>; + qcom,pull-up = <1>; + qcom,s1-timer = <10256>; + qcom,s2-timer = <2000>; + qcom,s2-type = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm8916_mpps: mpps { + compatible = "qcom,qpnp-pin"; + spmi-dev-container; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pm8916-mpp"; + + mpp@a000 { + reg = <0xa000 0x100>; + qcom,pin-num = <1>; + }; + + mpp@a100 { + reg = <0xa100 0x100>; + qcom,pin-num = <2>; + }; + + mpp@a200 { + reg = <0xa200 0x100>; + qcom,pin-num = <3>; + }; + + mpp@a300 { + reg = <0xa300 0x100>; + qcom,pin-num = <4>; + }; + }; + + pm8916_gpios: gpios { + compatible = "qcom,qpnp-pin"; + spmi-dev-container; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pm8916-gpio"; + + gpio@c000 { + reg = <0xc000 0x100>; + qcom,pin-num = <1>; + }; + + gpio@c100 { + reg = <0xc100 0x100>; + qcom,pin-num = <2>; + }; + + gpio@c200 { + reg = <0xc200 0x100>; + qcom,pin-num = <3>; + }; + + gpio@c300 { + reg = <0xc300 0x100>; + qcom,pin-num = <4>; + }; + }; + + pm8916_rtc: qcom,pm8916_rtc { + spmi-dev-container; + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8916_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + qcom,pm8916_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1>; + }; + }; + + pm8916_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + qcom,pmic-revid = <&pm8916_revid>; + + chan@8 { + label = "die_temp"; + reg = <8>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + }; + + pm8916_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0>; + label = "pm8916_tz"; + qcom,channel-num = <8>; + qcom,threshold-set = <0>; + qcom,temp_alarm-vadc = <&pm8916_vadc>; + }; + + pm8916_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0>, + <0x0 0x34 0x3>, + <0x0 0x34 0x4>; + interrupt-names = "eoc-int-en-set", + "high-thr-en-set", + "low-thr-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,adc_tm-vadc = <&pm8916_vadc>; + }; + + pm8916_chg: qcom,charger { + spmi-dev-container; + compatible = "qcom,qpnp-linear-charger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,vddmax-mv = <4200>; + qcom,vddsafe-mv = <4200>; + qcom,vinmin-mv = <4308>; + qcom,ibatsafe-ma = <1440>; + qcom,thermal-mitigation = <1440 720 630 0>; + qcom,cool-bat-decidegc = <100>; + qcom,warm-bat-decidegc = <450>; + qcom,cool-bat-mv = <4100>; + qcom,warm-bat-mv = <4100>; + qcom,ibatmax-warm-ma = <360>; + qcom,ibatmax-cool-ma = <360>; + qcom,batt-hot-percentage = <25>; + qcom,batt-cold-percentage = <80>; + qcom,tchg-mins = <232>; + qcom,resume-soc = <99>; + qcom,chg-vadc = <&pm8916_vadc>; + qcom,chg-adc_tm = <&pm8916_adc_tm>; + + status = "disabled"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x0 0x10 0x7>, + <0x0 0x10 0x6>, + <0x0 0x10 0x5>, + <0x0 0x10 0x0>; + interrupt-names = "chg-done", + "chg-failed", + "fast-chg-on", + "vbat-det-lo"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x0 0x12 0x1>, + <0x0 0x12 0x0>; + interrupt-names = "bat-temp-ok", + "batt-pres"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0 0x13 0x4>, + <0 0x13 0x2>, + <0 0x13 0x1>; + interrupt-names = "usb-over-temp", + "chg-gone", + "usbin-valid"; + }; + + qcom,chg-misc@1600 { + reg = <0x1600 0x100>; + }; + }; + + pm8916_bms: qcom,vmbms { + spmi-dev-container; + compatible = "qcom,qpnp-vm-bms"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + qcom,v-cutoff-uv = <3400000>; + qcom,max-voltage-uv = <4200000>; + qcom,r-conn-mohm = <0>; + qcom,shutdown-soc-valid-limit = <100>; + qcom,low-soc-calculate-soc-threshold = <15>; + qcom,low-voltage-calculate-soc-ms = <1000>; + qcom,low-soc-calculate-soc-ms = <5000>; + qcom,calculate-soc-ms = <20000>; + qcom,volatge-soc-timeout-ms = <60000>; + qcom,low-voltage-threshold = <3450000>; + qcom,s3-ocv-tolerence-uv = <1200>; + qcom,low-soc-fifo-length = <2>; + qcom,bms-vadc = <&pm8916_vadc>; + qcom,bms-adc_tm = <&pm8916_adc_tm>; + qcom,pmic-revid = <&pm8916_revid>; + + qcom,force-s3-on-suspend; + qcom,force-s2-in-charging; + qcom,report-charger-eoc; + + qcom,batt-pres-status@1208 { + reg = <0x1208 0x1>; + }; + + qcom,qpnp-chg-pres@1008 { + reg = <0x1008 0x1>; + }; + + qcom,vm-bms@4000 { + reg = <0x4000 0x100>; + interrupts = <0x0 0x40 0x0>, + <0x0 0x40 0x1>, + <0x0 0x40 0x2>, + <0x0 0x40 0x3>, + <0x0 0x40 0x4>, + <0x0 0x40 0x5>; + + interrupt-names = "leave_cv", + "enter_cv", + "good_ocv", + "ocv_thr", + "fifo_update_done", + "fsm_state_change"; + }; + }; + + pm8916_leds: qcom,leds@a100 { + compatible = "qcom,leds-qpnp"; + reg = <0xa100 0x100>; + label = "mpp"; + }; + }; + + qcom,pm8916@1 { + spmi-slave-container; + reg = <0x1>; + #address-cells = <1>; + #size-cells = <1>; + + regulator@1400 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_s1"; + spmi-dev-container; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1400 0x300>; + status = "disabled"; + + qcom,ctl@1400 { + reg = <0x1400 0x100>; + }; + qcom,ps@1500 { + reg = <0x1500 0x100>; + }; + qcom,freq@1600 { + reg = <0x1600 0x100>; + }; + }; + + regulator@1700 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_s2"; + spmi-dev-container; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1700 0x300>; + status = "disabled"; + + qcom,ctl@1700 { + reg = <0x1700 0x100>; + }; + qcom,ps@1800 { + reg = <0x1800 0x100>; + }; + qcom,freq@1900 { + reg = <0x1900 0x100>; + }; + }; + + regulator@1a00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_s3"; + spmi-dev-container; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1a00 0x300>; + status = "disabled"; + + qcom,ctl@1a00 { + reg = <0x1a00 0x100>; + }; + qcom,ps@1b00 { + reg = <0x1b00 0x100>; + }; + qcom,freq@1c00 { + reg = <0x1c00 0x100>; + }; + }; + + regulator@1d00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_s4"; + spmi-dev-container; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1d00 0x300>; + status = "disabled"; + + qcom,ctl@1d00 { + reg = <0x1d00 0x100>; + }; + qcom,ps@1e00 { + reg = <0x1e00 0x100>; + }; + qcom,freq@1f00 { + reg = <0x1f00 0x100>; + }; + }; + + regulator@4000 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l1"; + reg = <0x4000 0x100>; + status = "disabled"; + }; + + regulator@4100 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l2"; + reg = <0x4100 0x100>; + status = "disabled"; + }; + + regulator@4200 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l3"; + reg = <0x4200 0x100>; + status = "disabled"; + }; + + regulator@4300 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l4"; + reg = <0x4300 0x100>; + status = "disabled"; + }; + + regulator@4400 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l5"; + reg = <0x4400 0x100>; + status = "disabled"; + }; + + regulator@4500 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l6"; + reg = <0x4500 0x100>; + status = "disabled"; + }; + + regulator@4600 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l7"; + reg = <0x4600 0x100>; + status = "disabled"; + }; + + regulator@4700 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l8"; + reg = <0x4700 0x100>; + status = "disabled"; + }; + + regulator@4800 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l9"; + reg = <0x4800 0x100>; + status = "disabled"; + }; + + regulator@4900 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l10"; + reg = <0x4900 0x100>; + status = "disabled"; + }; + + regulator@4a00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l11"; + reg = <0x4a00 0x100>; + status = "disabled"; + }; + + regulator@4b00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l12"; + reg = <0x4b00 0x100>; + status = "disabled"; + }; + + regulator@4c00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l13"; + reg = <0x4c00 0x100>; + status = "disabled"; + }; + + regulator@4d00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l14"; + reg = <0x4d00 0x100>; + status = "disabled"; + }; + + regulator@4e00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l15"; + reg = <0x4e00 0x100>; + status = "disabled"; + }; + + regulator@4f00 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l16"; + reg = <0x4f00 0x100>; + status = "disabled"; + }; + + regulator@5000 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l17"; + reg = <0x5000 0x100>; + status = "disabled"; + }; + + regulator@5100 { + compatible = "qcom,qpnp-regulator"; + regulator-name = "8916_l18"; + reg = <0x5100 0x100>; + status = "disabled"; + }; + + pm8916_pwm: pwm@bc00 { + compatible = "qcom,qpnp-pwm"; + reg = <0xbc00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + }; + + pm8916_vib: qcom,vibrator@c000 { + compatible = "qcom,qpnp-vibrator"; + reg = <0xc000 0x100>; + label = "vibrator"; + status = "disabled"; + }; + + pm8916_tombak_dig: msm8x16_wcd_codec@f000{ + compatible = "qcom,wcd-spmi"; + reg = <0xf000 0x100>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf0 0x0>, + <0x1 0xf0 0x1>, + <0x1 0xf0 0x2>, + <0x1 0xf0 0x3>, + <0x1 0xf0 0x4>, + <0x1 0xf0 0x5>, + <0x1 0xf0 0x6>, + <0x1 0xf0 0x7>; + interrupt-names = "spk_cnp_int", + "spk_clip_int", + "spk_ocp_int", + "ins_rem_det1", + "but_rel_det", + "but_press_det", + "ins_rem_det", + "mbhc_int"; + + cdc-vdda-cp-supply = <&pm8916_s4>; + qcom,cdc-vdda-cp-voltage = <1800000 2200000>; + qcom,cdc-vdda-cp-current = <770000>; + + cdc-vdda-h-supply = <&pm8916_l5>; + qcom,cdc-vdda-h-voltage = <1800000 1800000>; + qcom,cdc-vdda-h-current = <20000>; + + cdc-vdd-px-supply = <&pm8916_s4>; + qcom,cdc-vdd-px-voltage = <1800000 2200000>; + qcom,cdc-vdd-px-current = <770000>; + + cdc-vdd-pa-supply = <&pm8916_l5>; + qcom,cdc-vdd-pa-voltage = <1800000 1800000>; + qcom,cdc-vdd-pa-current = <5000>; + + cdc-vdd-mic-bias-supply = <&pm8916_l13>; + qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>; + qcom,cdc-vdd-mic-bias-current = <25000>; + + qcom,cdc-mclk-clk-rate = <9600000>; + + qcom,cdc-static-supplies = "cdc-vdda-h", + "cdc-vdd-px", + "cdc-vdd-pa", + "cdc-vdda-cp"; + + qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias"; + }; + + pm8916_tombak_analog: msm8x16_wcd_codec@f100{ + compatible = "qcom,wcd-spmi"; + reg = <0xf100 0x100>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf1 0x0>, + <0x1 0xf1 0x1>, + <0x1 0xf1 0x2>, + <0x1 0xf1 0x3>, + <0x1 0xf1 0x4>, + <0x1 0xf1 0x5>; + interrupt-names = "ear_ocp_int", + "hphr_ocp_int", + "hphl_ocp_det", + "ear_cnp_int", + "hphr_cnp_int", + "hphl_cnp_int"; + }; + + pm8916_bcm: qpnp-buck-current-monitor@1800 { + compatible = "qcom,qpnp-buck-current-monitor"; + reg = <0x1800 0x100>; + interrupts = <1 0x18 0>, <1 0x18 1>; + interrupt-names = "iwarning", "icritical"; + qcom,enable-current-monitor; + qcom,icrit-init-threshold-pc = <90>; + qcom,iwarn-init-threshold-pc = <70>; + qcom,icrit-polling-delay-msec = <1000>; + qcom,iwarn-polling-delay-msec = <2000>; + + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/msm-rdbg.dtsi b/arch/arm/boot/dts/msm-rdbg.dtsi new file mode 100644 index 000000000000..f7f52bed111c --- /dev/null +++ b/arch/arm/boot/dts/msm-rdbg.dtsi @@ -0,0 +1,75 @@ +/* Copyright (c) 2013, 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 { + smp2pgpio_rdbg_2_in: qcom,smp2pgpio-rdbg-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_2_in { + compatible = "qcom,smp2pgpio_client_rdbg_2_in"; + gpios = <&smp2pgpio_rdbg_2_in 0 0>; + }; + + smp2pgpio_rdbg_2_out: qcom,smp2pgpio-rdbg-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_2_out { + compatible = "qcom,smp2pgpio_client_rdbg_2_out"; + gpios = <&smp2pgpio_rdbg_2_out 0 0>; + }; + + smp2pgpio_rdbg_1_in: qcom,smp2pgpio-rdbg-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_1_in { + compatible = "qcom,smp2pgpio_client_rdbg_1_in"; + gpios = <&smp2pgpio_rdbg_1_in 0 0>; + }; + + smp2pgpio_rdbg_1_out: qcom,smp2pgpio-rdbg-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_1_out { + compatible = "qcom,smp2pgpio_client_rdbg_1_out"; + gpios = <&smp2pgpio_rdbg_1_out 0 0>; + }; +}; diff --git a/arch/arm/boot/dts/msm8916-bus.dtsi b/arch/arm/boot/dts/msm8916-bus.dtsi new file mode 100644 index 000000000000..21ae7a929d1d --- /dev/null +++ b/arch/arm/boot/dts/msm8916-bus.dtsi @@ -0,0 +1,877 @@ +/* Copyright (c) 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 <dt-bindings/msm/msm-bus-rule-ops.h> + +&soc { + ad_hoc_bus: ad-hoc-bus { }; + + static-rules { + compatible = "qcom,msm-bus-static-bw-rules"; + + rule0 { + qcom,src-nodes = <&mas_apss>; + qcom,src-field = <FLD_IB>; + qcom,src-op = <OP_LE>; + qcom,thresh = <1600000>; + qcom,mode = <THROTTLE_ON>; + qcom,dest-node = <&mas_apss>; + qcom,dest-bw = <600000>; + }; + + + rule1 { + qcom,src-nodes = <&mas_apss>; + qcom,src-field = <FLD_IB>; + qcom,src-op = <OP_LE>; + qcom,thresh = <3200000>; + qcom,mode = <THROTTLE_ON>; + qcom,dest-node = <&mas_apss>; + qcom,dest-bw = <1200000>; + }; + + rule2 { + qcom,src-nodes = <&mas_apss>; + qcom,src-field = <FLD_IB>; + qcom,src-op = <OP_GT>; + qcom,thresh = <3200000>; + qcom,mode = <THROTTLE_OFF>; + qcom,dest-node = <&mas_apss>; + }; + + rule3 { + qcom,src-nodes = <&mas_gfx>; + qcom,src-field = <FLD_IB>; + qcom,src-op = <OP_LE>; + qcom,thresh = <1600000>; + qcom,mode = <THROTTLE_ON>; + qcom,dest-node = <&mas_gfx>; + qcom,dest-bw = <600000>; + }; + + rule4 { + qcom,src-nodes = <&mas_gfx>; + qcom,src-field = <FLD_IB>; + qcom,src-op = <OP_LE>; + qcom,thresh = <3200000>; + qcom,mode = <THROTTLE_ON>; + qcom,dest-node = <&mas_gfx>; + qcom,dest-bw = <1200000>; + }; + + rule5 { + qcom,src-nodes = <&mas_gfx>; + qcom,src-field = <FLD_IB>; + qcom,src-op = <OP_GT>; + qcom,thresh = <3200000>; + qcom,mode = <THROTTLE_OFF>; + qcom,dest-node = <&mas_gfx>; + }; + }; +}; + +&ad_hoc_bus { + compatible = "qcom,msm-bus-device"; + reg = <0x580000 0x14000>, + <0x400000 0x62000>, + <0x500000 0x11000>; + reg-names = "snoc-base", "bimc-base", "pnoc-base"; + + fab_snoc: fab-snoc { + cell-id = <1024>; + label = "fab-snoc"; + qcom,fab-dev; + qcom,base-name = "snoc-base"; + qcom,base-offset = <0x7000>; + qcom,qos-off = <0x1000>; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpm clk_snoc_msmbus_clk>, + <&clock_rpm clk_snoc_msmbus_a_clk>; + + coresight-id = <50>; + coresight-name = "coresight-snoc"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in2>; + coresight-child-ports = <5>; + }; + + fab_bimc: fab-bimc { + cell-id = <0>; + label = "fab-bimc"; + qcom,fab-dev; + qcom,base-name = "bimc-base"; + qcom,bus-type = <2>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpm clk_bimc_msmbus_clk>, + <&clock_rpm clk_bimc_msmbus_a_clk>; + + coresight-id = <55>; + coresight-name = "coresight-bimc"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in2>; + coresight-child-ports = <3>; + }; + + fab_pnoc: fab-pnoc { + cell-id = <4096>; + label = "fab-pnoc"; + qcom,fab-dev; + qcom,base-name = "pnoc-base"; + qcom,base-offset = <0x7000>; + qcom,qos-delta = <0x1000>; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpm clk_pcnoc_msmbus_clk>, + <&clock_rpm clk_pcnoc_msmbus_a_clk>; + + coresight-id = <54>; + coresight-name = "coresight-pnoc"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in2>; + coresight-child-ports = <6>; + }; + + /* SNOC Devices */ + mas_video: mas-video { + cell-id = <63>; + label = "mas-video"; + qcom,qport = <8>; + qcom,ap-owned; + qcom,connections = <&mm_int_0 &mm_int_2>; + qcom,bus-dev = <&fab_snoc>; + qcom,qos-mode = "bypass"; + qcom,buswidth = <16>; + }; + + mas_jpeg: mas-jpeg { + cell-id = <62>; + label = "mas-jpeg"; + qcom,ap-owned; + qcom,qport = <6>; + qcom,connections = <&mm_int_0 &mm_int_2>; + qcom,bus-dev = <&fab_snoc>; + qcom,qos-mode = "bypass"; + qcom,buswidth = <16>; + }; + + mas_vfe: mas-vfe { + cell-id = <29>; + label = "mas-vfe"; + qcom,ap-owned; + qcom,qport = <9>; + qcom,connections = <&mm_int_1 &mm_int_2>; + qcom,bus-dev = <&fab_snoc>; + qcom,qos-mode = "bypass"; + qcom,buswidth = <16>; + }; + + mas_mdp: mas-mdp { + cell-id = <22>; + label = "mas-mdp"; + qcom,ap-owned; + qcom,connections = <&mm_int_0 &mm_int_2>; + qcom,qport = <7>; + qcom,bus-dev = <&fab_snoc>; + qcom,qos-mode = "bypass"; + qcom,buswidth = <16>; + }; + + mas_qdss_bam: mas-qdss-bam { + cell-id = <53>; + label = "mas-qdss-bam"; + qcom,connections = <&qdss_int>; + qcom,qport = <11>; + qcom,bus-dev = <&fab_snoc>; + qom,buswidth = <4>; + qcom,ap-owned; + qcom,qos-mode = "fixed"; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + }; + + mas_snoc_cfg: mas-snoc-cfg { + cell-id = <54>; + label = "mas-snoc-cfg"; + qcom,connections = <&qdss_int>; + qcom,bus-dev = <&fab_snoc>; + qcom,qos-mode = "bypass"; + qom,buswidth = <4>; + qcom,mas-rpm-id = <20>; + }; + + mas_qdss_etr: mas-qdss-etr { + cell-id = <60>; + label = "mas-qdss-etr"; + qcom,connections = <&qdss_int>; + qcom,qport = <10>; + qcom,bus-dev = <&fab_snoc>; + qcom,qos-mode = "fixed"; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qom,buswidth = <8>; + qcom,ap-owned; + }; + + mm_int_0: mm-int-0 { + cell-id = <10000>; + label = "mm-int-0"; + qcom,ap-owned; + qcom,connections = <&mm_int_bimc>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <16>; + }; + + mm_int_1: mm-int-1 { + cell-id = <10001>; + label = "mm-int1"; + qcom,ap-owned; + qcom,connections = <&mm_int_bimc>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <16>; + }; + + mm_int_2: mm-int-2 { + cell-id = <10002>; + label = "mm-int2"; + qcom,ap-owned; + qcom,connections = <&snoc_int_0>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <16>; + }; + + mm_int_bimc: mm-int-bimc { + cell-id = <10003>; + label = "mm-int-bimc"; + qcom,ap-owned; + qcom,connections = <&snoc_bimc_1_mas>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <16>; + }; + + snoc_int_0: snoc-int-0 { + cell-id = <10004>; + label = "snoc-int-0"; + qcom,connections = <&slv_qdss_stm &slv_imem &snoc_pnoc_mas>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = <99>; + qcom,slv-rpm-id = <130>; + qcom,buswidth = <8>; + }; + + snoc_int_1: snoc-int-1 { + cell-id = <10005>; + label = "snoc-int-1"; + qcom,connections = <&slv_apss &slv_cats_0 &slv_cats_1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = <100>; + qcom,slv-rpm-id = <131>; + qcom,buswidth = <8>; + }; + + snoc_int_bimc: snoc-int-bmc { + cell-id = <10006>; + label = "snoc-bimc"; + qcom,connections = <&snoc_bimc_0_mas>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = <101>; + qcom,slv-rpm-id = <132>; + qcom,buswidth = <8>; + }; + + snoc_bimc_0_mas: snoc-bimc-0-mas { + cell-id = <10007>; + label = "snoc-bimc-0-mas"; + qcom,connections = <&snoc_bimc_0_slv>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = <3>; + qcom,buswidth = <8>; + }; + + snoc_bimc_1_mas: snoc-bimc-1-mas { + cell-id = <10008>; + label = "snoc-bimc-1-mas"; + qcom,connections = <&snoc_bimc_1_slv>; + qcom,bus-dev = <&fab_snoc>; + qcom,ap-owned; + qcom,buswidth = <16>; + }; + + qdss_int: qdss-int { + cell-id = <10009>; + label = "qdss-int"; + qcom,ap-owned; + qcom,connections = <&snoc_int_0 &snoc_int_bimc>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <8>; + }; + + bimc_snoc_slv: bimc-snoc-slv { + cell-id = <10017>; + label = "bimc_snoc_slv"; + qcom,ap-owned; + qcom,connections = <&snoc_int_0 &snoc_int_1>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <8>; + }; + + snoc_pnoc_mas: snoc-pnoc-mas { + cell-id = <10027>; + label = "snoc-pnoc-mas"; + qcom,connections = <&snoc_pnoc_slv>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <8>; + }; + + pnoc_snoc_slv: pnoc-snoc-slv { + cell-id = <10011>; + label = "snoc-pnoc"; + qcom,connections = <&snoc_int_0 &snoc_int_bimc &snoc_int_1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = <45>; + qcom,buswidth = <8>; + }; + + slv_srvc_snoc: slv-srvc-snoc { + cell-id = <587>; + label = "snoc-srvc-snoc"; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = <29>; + qcom,buswidth = <8>; + }; + + slv_qdss_stm: slv-qdss-stm { + cell-id = <588>; + label = "snoc-qdss-stm"; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <4>; + qcom,slv-rpm-id = <30>; + }; + + slv_imem: slv-imem { + cell-id = <519>; + label = "slv_imem"; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <8>; + qcom,slv-rpm-id = <26>; + }; + + slv_apss: slv-apss { + cell-id = <517>; + label = "slv_apss"; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = <20>; + qcom,buswidth = <4>; + }; + + slv_cats_0: slv-cats-0 { + cell-id = <663>; + label = "slv-cats-0"; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = <106>; + qcom,buswidth = <16>; + }; + + slv_cats_1: slv-cats-1 { + cell-id = <664>; + label = "slv-cats-1"; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = <107>; + qcom,buswidth = <8>; + }; + + /* BIMC nodes */ + mas_apss: mas-apss { + cell-id = <1>; + label = "mas-apss"; + qcom,ap-owned; + qcom,connections = <&slv_ebi_ch0 &bimc_snoc_mas &slv_apps_l2>; + qcom,qport = <0>; + qcom,bus-dev = <&fab_bimc>; + qcom,qos-mode = "fixed"; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,ws = <10000>; + qcom,gp = <5000>; + qcom,thmp = <50>; + qom,buswidth = <8>; + }; + + mas_tcu0: mas-tcu0 { + cell-id = <104>; + label = "mas-tcu0"; + qcom,ap-owned; + qcom,connections = <&slv_ebi_ch0 &bimc_snoc_mas &slv_apps_l2>; + qcom,qport = <5>; + qcom,bus-dev = <&fab_bimc>; + qcom,qos-mode = "fixed"; + qcom,prio-lvl = <2>; + qcom,prio-rd = <2>; + qcom,prio-wr = <2>; + qom,buswidth = <8>; + }; + + mas_tcu1: mas-tcu1 { + cell-id = <105>; + label = "mas-tcu1"; + qcom,ap-owned; + qcom,connections = <&slv_ebi_ch0 &bimc_snoc_mas &slv_apps_l2>; + qcom,qport = <6>; + qcom,bus-dev = <&fab_bimc>; + qcom,qos-mode = "fixed"; + qcom,prio-lvl = <2>; + qcom,prio-rd = <2>; + qcom,prio-wr = <2>; + qom,buswidth = <8>; + }; + + mas_gfx: mas-gfx { + cell-id = <26>; + label = "mas-gfx"; + qcom,ap-owned; + qcom,connections = <&slv_ebi_ch0 &bimc_snoc_mas &slv_apps_l2>; + qcom,qport = <2>; + qcom,bus-dev = <&fab_bimc>; + qcom,qos-mode = "fixed"; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qom,buswidth = <8>; + qcom,ws = <10000>; + qcom,gp = <5000>; + qcom,thmp = <50>; + }; + + bimc_snoc_mas: bimc-snoc-mas { + cell-id = <10016>; + label = "bimc_snoc_mas"; + qcom,ap-owned; + qcom,bus-dev = <&fab_bimc>; + qcom,connections = <&bimc_snoc_slv>; + qom,buswidth = <8>; + }; + + snoc_bimc_0_slv: snoc-bimc-0-slv { + cell-id = <10025>; + label = "snoc_bimc_0_slv"; + qcom,connections = <&slv_ebi_ch0>; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = <24>; + qom,buswidth = <8>; + }; + + snoc_bimc_1_slv: snoc_bimc_1_slv { + cell-id = <10026>; + label = "snoc_bimc_1_slv"; + qcom,connections = <&slv_ebi_ch0>; + qcom,ap-owned; + qcom,bus-dev = <&fab_bimc>; + qom,buswidth = <8>; + }; + + slv_ebi_ch0: slv-ebi-ch0 { + cell-id = <512>; + label = "slv-ebi-ch0"; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = <0>; + qom,buswidth = <8>; + }; + + slv_apps_l2: slv-apps-l2 { + cell-id = <514>; + label = "slv-apps-l2"; + qcom,bus-dev = <&fab_bimc>; + qom,buswidth = <8>; + }; + + /* PNOC nodes */ + snoc_pnoc_slv: snoc-pnoc-slv { + cell-id = <10028>; + label = "snoc-pnoc-slv"; + qcom,connections = <&pnoc_int_0>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <8>; + }; + + pnoc_int_0: pnoc-int-0 { + cell-id = <10012>; + label = "pnoc-int-0"; + qcom,connections = <&pnoc_snoc_mas &pnoc_s_0 &pnoc_s_1 &pnoc_s_2 + &pnoc_s_3 &pnoc_s_4 &pnoc_s_8 &pnoc_s_9>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <8>; + }; + + pnoc_int_1: pnoc-int-1 { + cell-id = <10013>; + label = "pnoc-int-1"; + qcom,connections = <&pnoc_snoc_mas>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <8>; + }; + + pnoc_m_0: pnoc-m-0 { + cell-id = <10014>; + label = "pnoc-m-0"; + qcom,connections = <&pnoc_int_0>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <8>; + }; + + pnoc_m_1: pnoc-m-1 { + cell-id = <10015>; + label = "pnoc-m-1"; + qcom,connections = <&pnoc_snoc_mas>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <8>; + }; + + pnoc_s_0: pnoc-s-0 { + cell-id = <10018>; + label = "pnoc-s-0"; + qcom,connections = <&slv_clk_ctl &slv_tlmm &slv_tcsr + &slv_security &slv_mss>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <4>; + }; + + pnoc_s_1: pnoc-s-1 { + cell-id = <10019>; + label = "pnoc-s-1"; + qcom,connections = <&slv_imem_cfg &slv_crypto_0_cfg + &slv_msg_ram &slv_pdm &slv_prng>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <4>; + }; + + pnoc_s_2: pnoc-s-2 { + cell-id = <10020>; + label = "pnoc-s-2"; + qcom,connections = <&slv_spdm &slv_boot_rom &slv_bimc_cfg + &slv_pnoc_cfg &slv_pmic_arb>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <4>; + }; + + pnoc_s_3: pnoc-s-3 { + cell-id = <10021>; + label = "pnoc-s-3"; + qcom,connections = <&slv_mpm &slv_snoc_cfg &slv_rbcpr_cfg + &slv_qdss_cfg &slv_dehr_cfg>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <4>; + }; + + pnoc_s_4: pnoc-s-4 { + cell-id = <10022>; + label = "pnoc-s-4"; + qcom,connections = <&slv_venus_cfg &slv_camera_cfg + &slv_display_cfg>; + qcom,bus-dev = <&fab_pnoc>; + }; + + pnoc_s_8: pnoc-s-8 { + cell-id = <10023>; + label = "pnoc-s-8"; + qcom,connections = <&slv_usb_hs &slv_sdcc_1 &slv_blsp_1>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <4>; + }; + + pnoc_s_9: pnoc-s-9 { + cell-id = <10024>; + label = "pnoc-s-9"; + qcom,connections = <&slv_sdcc_2 &slv_audio &slv_gfx_cfg>; + qcom,bus-dev = <&fab_pnoc>; + qom,buswidth = <4>; + }; + + slv_imem_cfg: slv-imem-cfg { + cell-id = <627>; + label = "slv-imem-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_crypto_0_cfg: slv-crypto-0-cfg { + cell-id = <625>; + label = "slv-crypto-0-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_msg_ram: slv-msg-ram { + cell-id = <535>; + label = "slv-msg-ram"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_pdm: slv-pdm { + cell-id = <577>; + label = "slv-pdm"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_prng: slv-prng { + cell-id = <618>; + label = "slv-prng"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_clk_ctl: slv-clk-ctl { + cell-id = <620>; + label = "slv-clk-ctl"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_mss: slv-mss { + cell-id = <521>; + label = "slv-mss"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_tlmm: slv-tlmm { + cell-id = <624>; + label = "slv-tlmm"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_tcsr: slv-tcsr { + cell-id = <579>; + label = "slv-tcsr"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_security: slv-security { + cell-id = <622>; + label = "slv-security"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_spdm: slv-spdm { + cell-id = <533>; + label = "slv-spdm"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_pnoc_cfg: slv-pnoc-cfg { + cell-id = <641>; + label = "slv-pnoc-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_pmic_arb: slv-pmic-arb { + cell-id = <632>; + label = "slv-pmic-arb"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_bimc_cfg: slv-bimc-cfg { + cell-id = <629>; + label = "slv-bimc-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_boot_rom: slv-boot-rom { + cell-id = <630>; + label = "slv-boot-rom"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_mpm: slv-mpm { + cell-id = <536>; + label = "slv-mpm"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_qdss_cfg: slv-qdss-cfg { + cell-id = <635>; + label = "slv-qdss-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_rbcpr_cfg: slv-rbcpr-cfg { + cell-id = <636>; + label = "slv-rbcpr-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_snoc_cfg: slv-snoc-cfg { + cell-id = <647>; + label = "slv-snoc-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_dehr_cfg: slv-dehr-cfg { + cell-id = <634>; + label = "slv-dehr-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_venus_cfg: slv-venus-cfg { + cell-id = <596>; + label = "slv-venus-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_display_cfg: slv-display-cfg { + cell-id = <590>; + label = "slv-display-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_camera_cfg: slv-camera-cfg { + cell-id = <589>; + label = "slv-camer-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_usb_hs: slv-usb-hs { + cell-id = <614>; + label = "slv-usb-hs"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_sdcc_1: slv-sdcc-1 { + cell-id = <606>; + label = "slv-sdcc-1"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_blsp_1: slv-blsp-1 { + cell-id = <613>; + label = "slv-blsp-1"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_sdcc_2: slv-sdcc-2 { + cell-id = <609>; + label = "slv-sdcc-2"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_gfx_cfg: slv-gfx-cfg { + cell-id = <598>; + label = "slv-gfx-cfg"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + slv_audio: slv-audio { + cell-id = <522>; + label = "slv-audio"; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + mas_blsp_1: mas-blsp_1 { + cell-id = <86>; + label = "mas-blsp-1"; + qcom,connections = <&pnoc_m_1>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + mas_spdm: mas-spdm { + cell-id = <36>; + label = "mas-spdm"; + qcom,connections = <&pnoc_m_0>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + mas_dehr: mas-dehr { + cell-id = <75>; + label = "mas-dehr"; + qcom,connections = <&pnoc_m_0>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + mas_audio: mas-audio { + cell-id = <15>; + label = "mas-audio"; + qcom,connections = <&pnoc_m_0>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + mas_usb_hs: mas-usb-hs { + cell-id = <87>; + label = "mas-usb-hs"; + qcom,connections = <&pnoc_m_1>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <4>; + }; + + mas_pnoc_crypto_0: mas-pnoc-crypto-0 { + cell-id = <55>; + label = "mas-pnoc-crypto-0"; + qcom,connections = <&pnoc_int_1>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <8>; + }; + + mas_pnoc_sdcc_1: mas-pnoc-sdcc-1 { + cell-id = <78>; + label = "mas-pnoc-sdcc-1"; + qcom,connections = <&pnoc_int_1>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <8>; + }; + + mas_pnoc_sdcc_2: mas-pnoc-sdcc-2 { + cell-id = <81>; + label = "mas-pnoc-sdcc-2"; + qcom,connections = <&pnoc_int_1>; + qcom,bus-dev = <&fab_pnoc>; + qcom,buswidth = <8>; + }; + + pnoc_snoc_mas: pnoc-snoc-mas { + cell-id = <10010>; + label = "pnoc-snoc-mas"; + qcom,connections = <&pnoc_snoc_slv>; + qcom,bus-dev = <&fab_pnoc>; + qcom,mas-rpm-id = <29>; + qcom,buswidth = <8>; + }; +}; diff --git a/arch/arm/boot/dts/msm8916-ipcrouter.dtsi b/arch/arm/boot/dts/msm8916-ipcrouter.dtsi new file mode 100644 index 000000000000..3b59d159ea8d --- /dev/null +++ b/arch/arm/boot/dts/msm8916-ipcrouter.dtsi @@ -0,0 +1,37 @@ +/* Copyright (c) 2013, 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 { + qcom,ipc_router { + compatible = "qcom,ipc_router"; + qcom,node-id = <1>; + }; + + qcom,ipc_router_modem_xprt { + compatible = "qcom,ipc_router_smd_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "modem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,ipc_router_wcnss_xprt { + compatible = "qcom,ipc_router_smd_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "wcnss"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + +}; diff --git a/arch/arm/boot/dts/msm8916-memory.dtsi b/arch/arm/boot/dts/msm8916-memory.dtsi new file mode 100644 index 000000000000..5f8302741f66 --- /dev/null +++ b/arch/arm/boot/dts/msm8916-memory.dtsi @@ -0,0 +1,45 @@ +/* Copyright (c) 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 "msm8916-ion.dtsi" + +/ { + memory { + #address-cells = <2>; + #size-cells = <2>; + + external_image_mem: external_image__region@0 { + linux,reserve-contiguous-region; + linux,reserve-region; + linux,remove-completely; + reg = <0x0 0x86000000 0x0 0x0800000>; + label = "external_image_mem"; + }; + + modem_adsp_mem: modem_adsp_region@0 { + linux,reserve-contiguous-region; + linux,reserve-region; + linux,remove-completely; + reg = <0x0 0x86800000 0x0 0x04e00000>; + label = "modem_adsp_mem"; + }; + + peripheral_mem: pheripheral_region@0 { + linux,reserve-contiguous-region; + linux,reserve-region; + linux,remove-completely; + reg = <0x0 0x8b600000 0x0 0x0600000>; + label = "peripheral_mem"; + }; + + }; +}; diff --git a/arch/arm/boot/dts/msm8916-pinctrl.dtsi b/arch/arm/boot/dts/msm8916-pinctrl.dtsi new file mode 100644 index 000000000000..dbcaa9824e4f --- /dev/null +++ b/arch/arm/boot/dts/msm8916-pinctrl.dtsi @@ -0,0 +1,1374 @@ +/* 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 { + tlmm_pinmux: pinctrl@1000000 { + compatible = "qcom,msm-tlmm-v4"; + reg = <0x1000000 0x300000>; + interrupts = <0 208 0>; + + /*General purpose pins*/ + gp: gp { + qcom,pin-type-gp; + qcom,num-pins = <122>; + #qcom,pin-cells = <1>; + msm_gpio: msm_gpio { + compatible = "qcom,msm-tlmmv4-gp-intc"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + num_irqs = <122>; + }; + }; + + ext-cdc-tlmm-lines { + qcom,pins = <&gp 116>, <&gp 112>, <&gp 117>, + <&gp 118>, <&gp 119>; + qcom,num-grp-pins = <5>; + qcom,pin-func = <1>; + label = "ext-cdc-tlmm-lines"; + ext_cdc_tlmm_lines_act: tlmm_lines_on { + drive-strength = <8>; + bias-pull-none; + }; + ext_cdc_tlmm_lines_sus: tlmm_lines_off { + drive-strength = <2>; + bias-disable; + }; + }; + + ext-codec-lines { + qcom,pins = <&gp 67>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "ext-codec-lines"; + ext_codec_lines_act: lines_on { + drive-strength = <8>; + bias-disable; + output-high; + }; + ext_codec_lines_sus: lines_off { + drive-strength = <2>; + bias-disable; + }; + }; + + cdc-pdm-lines { + qcom,pins = <&gp 63>, <&gp 64>, <&gp 65>, + <&gp 66>, <&gp 67>, <&gp 68>; + qcom,num-grp-pins = <6>; + qcom,pin-func = <1>; + label = "cdc-pdm-lines"; + cdc_pdm_lines_act: pdm_lines_on { + drive-strength = <8>; + bias-pull-none; + }; + cdc_pdm_lines_sus: pdm_lines_off { + drive-strength = <2>; + bias-disable; + }; + }; + + cdc-ext-pa-lines { + qcom,pins = <&gp 113>, <&gp 114>, + <&gp 115>, <&gp 116>; + qcom,num-grp-pins = <4>; + qcom,pin-func = <1>; + label = "cdc-ext-pa-lines"; + cdc_ext_pa_act: ext_pa_on { + drive-strength = <8>; + bias-pull-none; + }; + cdc_ext_pa_sus: ext_pa_off { + drive-strength = <2>; + bias-disable; + }; + }; + + cdc-ext-pa-ws-line { + qcom,pins = <&gp 110>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "cdc-ext-pa-ws-line"; + cdc_ext_pa_ws_act: ext_pa_on { + drive-strength = <8>; + bias-pull-none; + }; + cdc_ext_pa_ws_sus: ext_pa_off { + drive-strength = <2>; + bias-disable; + }; + }; + + cross-conn-det { + qcom,pins = <&gp 120>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "cross-conn-det-sw"; + cross_conn_det_act: lines_on { + drive-strength = <8>; + bias-pull-none; + }; + cross_conn_det_sus: lines_off { + drive-strength = <2>; + bias-disable; + }; + }; + pmx-uartconsole { + qcom,pins = <&gp 4>, <&gp 5>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <2>; + label = "uart-console"; + + uart_console_sleep: uart-console { + drive-strength = <2>; + bias-pull-down; + }; + }; + + blsp1_uart1_active { + qcom,pins = <&gp 0>, <&gp 1>, <&gp 2>, <&gp 3>; + qcom,num-grp-pins = <4>; + qcom,pin-func = <2>; + label = "blsp1_uart1_active"; + + hsuart_active: default { + drive-strength = <16>; + bias-disable; + }; + }; + + blsp1_uart1_sleep { + qcom,pins = <&gp 0>, <&gp 1>, <&gp 2>, <&gp 3>; + qcom,num-grp-pins = <4>; + qcom,pin-func = <0>; + label = "blsp1_uart1_sleep"; + + hsuart_sleep: sleep { + drive-strength = <2>; + bias-disable; + }; + }; + + sdhc2_cd_pin { + qcom,pins = <&gp 38>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "cd-gpio"; + sdc2_cd_on: cd_on { + drive-strength = <2>; + bias-pull-up; + }; + sdc2_cd_off: cd_off { + drive-strength = <2>; + bias-disable; + }; + }; + + /* SDC pin type */ + sdc: sdc { + qcom,pin-type-sdc; + /* 0-2 for sdc1 4-6 for sdc2 */ + qcom,num-pins = <7>; + /* Order of pins */ + /* SDC1: CLK -> 0, CMD -> 1, DATA -> 2 */ + /* SDC2: CLK -> 4, CMD -> 5, DATA -> 6 */ + #qcom,pin-cells = <1>; + }; + + pmx_sdc1_clk { + qcom,pins = <&sdc 0>; + qcom,num-grp-pins = <1>; + label = "sdc1-clk"; + sdc1_clk_on: clk_on { + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + sdc1_clk_off: clk_off { + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + pmx_sdc1_cmd { + qcom,pins = <&sdc 1>; + qcom,num-grp-pins = <1>; + label = "sdc1-cmd"; + sdc1_cmd_on: cmd_on { + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + sdc1_cmd_off: cmd_off { + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + pmx_sdc1_data { + qcom,pins = <&sdc 2>; + qcom,num-grp-pins = <1>; + label = "sdc1-data"; + sdc1_data_on: data_on { + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + sdc1_data_off: data_off { + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + pmx_sdc2_clk { + qcom,pins = <&sdc 4>; + qcom,num-grp-pins = <1>; + label = "sdc2-clk"; + sdc2_clk_on: clk_on { + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + sdc2_clk_off: clk_off { + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + pmx_sdc2_cmd { + qcom,pins = <&sdc 5>; + qcom,num-grp-pins = <1>; + label = "sdc2-cmd"; + sdc2_cmd_on: cmd_on { + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + sdc2_cmd_off: cmd_off { + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + pmx_sdc2_data { + qcom,pins = <&sdc 6>; + qcom,num-grp-pins = <1>; + label = "sdc2-data"; + sdc2_data_on: data_on { + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + sdc2_data_off: data_off { + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + usb-id-pin { + qcom,pins = <&gp 110>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "usb-id-pin"; + usbid_default: default { + drive-strength = <8>; + bias-pull-up; + }; + }; + + spi0_active { + /* MOSI, MISO, CLK */ + qcom,pins = <&gp 8>, <&gp 9>, <&gp 11>; + qcom,num-grp-pins = <3>; + qcom,pin-func = <1>; + label = "spi0-active"; + /* active state */ + spi0_default: default { + drive-strength = <12>; /* 12 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + spi0_suspend { + /* MOSI, MISO, CLK */ + qcom,pins = <&gp 8>, <&gp 9>, <&gp 11>; + qcom,num-grp-pins = <3>; + qcom,pin-func = <0>; + label = "spi0-suspend"; + /* suspended state */ + spi0_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* pull down */ + }; + }; + spi0_cs0_active { + /* CS */ + qcom,pins = <&gp 10>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <1>; + label = "spi0-cs0-active"; + spi0_cs0_active: cs0_active { + drive-strength = <2>; + bias-disable = <0>; + }; + }; + + + spi0_cs0_suspend { + /* CS */ + qcom,pins = <&gp 10>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "spi0-cs0-suspend"; + spi0_cs0_sleep: cs0_sleep { + drive-strength = <2>; + bias-disable = <0>; + }; + }; + + ice40-spi-usb-pins { + qcom,pins = <&gp 0>, <&gp 1>, <&gp 3>, <&gp 114>; + qcom,num-grp-pins = <4>; + qcom,pin-func = <0>; + label = "ice40-spi-usb-pins"; + + /* active state */ + ice40_default: default { + drive-strength = <8>; + bias-disable; + }; + + /* sleep state */ + ice40_sleep: sleep { + drive-strength = <2>; + bias-pull-down; + }; + }; + + + pmx_i2c_0 { + /* CLK, DATA */ + qcom,pins = <&gp 7>, <&gp 6>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <3>; + label = "pmx_i2c_0"; + + i2c_0_active: i2c_0_active { + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + + i2c_0_sleep: i2c_0_sleep { + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + pmx_i2c_5 { + /* CLK, DATA */ + qcom,pins = <&gp 19>, <&gp 18>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <2>; + label = "pmx_i2c_5"; + + i2c_5_active: i2c_5_active { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + + i2c_5_sleep: i2c_5_sleep { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + /* QDSD pin type */ + qdsd: qdsd { + qcom,pin-type-qdsd; + /* 0-> clk, 1 -> cmd, 2->data0, 3->data1, 4->data2, 5->data3 */ + qcom,num-pins = <6>; + + #qcom,pin-cells = <1>; + }; + + pmx_qdsd_clk { + qcom,pins = <&qdsd 0>; + qcom,num-grp-pins = <1>; + label = "qdsd-clk"; + qdsd_clk_sdcard: clk_sdcard { + bias-disable; /* NO pull */ + drive-strength = <7>; /* 7 MA */ + }; + qdsd_clk_trace: clk_trace { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_clk_swdtrc: clk_swdtrc { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_clk_spmi: clk_spmi { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + }; + + pmx_qdsd_cmd { + qcom,pins = <&qdsd 1>; + qcom,num-grp-pins = <1>; + label = "qdsd-cmd"; + qdsd_cmd_sdcard: cmd_sdcard { + bias-pull-down; /* pull down */ + drive-strength = <3>; /* 3 MA */ + }; + qdsd_cmd_trace: cmd_trace { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_cmd_swduart: cmd_uart { + bias-pull-up; /* pull up */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_cmd_swdtrc: cmd_swdtrc { + bias-pull-up; /* pull up */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_cmd_jtag: cmd_jtag { + bias-disable; /* NO pull */ + drive-strength = <3>; /* 3 MA */ + }; + qdsd_cmd_spmi: cmd_spmi { + bias-pull-down; /* pull down */ + drive-strength = <4>; /* 4 MA */ + }; + }; + + pmx_qdsd_data0 { + qcom,pins = <&qdsd 2>; + qcom,num-grp-pins = <1>; + label = "qdsd-data0"; + qdsd_data0_sdcard: data0_sdcard { + bias-pull-down; /* pull down */ + drive-strength = <3>; /* 3 MA */ + }; + qdsd_data0_trace: data0_trace { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data0_swduart: data0_uart { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data0_swdtrc: data0_swdtrc { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data0_jtag: data0_jtag { + bias-pull-up; /* pull up */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data0_spmi: data0_spmi { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + }; + + pmx_qdsd_data1 { + qcom,pins = <&qdsd 3>; + qcom,num-grp-pins = <1>; + label = "qdsd-data1"; + qdsd_data1_sdcard: data1_sdcard { + bias-pull-down; /* pull down */ + drive-strength = <3>; /* 3 MA */ + }; + qdsd_data1_trace: data1_trace { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data1_swduart: data1_uart { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data1_swdtrc: data1_swdtrc { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data1_jtag: data1_jtag { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + }; + + pmx_qdsd_data2 { + qcom,pins = <&qdsd 4>; + qcom,num-grp-pins = <1>; + label = "qdsd-data2"; + qdsd_data2_sdcard: data2_sdcard { + bias-pull-down; /* pull down */ + drive-strength = <3>; /* 3 MA */ + }; + qdsd_data2_trace: data2_trace { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data2_swduart: data2_uart { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data2_swdtrc: data2_swdtrc { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data2_jtag: data2_jtag { + bias-pull-up; /* pull up */ + drive-strength = <3>; /* 3 MA */ + }; + }; + + pmx_qdsd_data3 { + qcom,pins = <&qdsd 5>; + qcom,num-grp-pins = <1>; + label = "qdsd-data3"; + qdsd_data3_sdcard: data3_sdcard { + bias-pull-down; /* pull down */ + drive-strength = <3>; /* 3 MA */ + }; + qdsd_data3_trace: data3_trace { + bias-pull-down; /* pull down */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data3_swduart: data3_uart { + bias-pull-up; /* pull up */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data3_swdtrc: data3_swdtrc { + bias-pull-up; /* pull up */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data3_jtag: data3_jtag { + bias-pull-up; /* pull up */ + drive-strength = <0>; /* 0 MA */ + }; + qdsd_data3_spmi: data3_spmi { + bias-pull-down; /* pull down */ + drive-strength = <3>; /* 3 MA */ + }; + }; + + pmx_mdss: pmx_mdss { + label = "mdss-pins"; + qcom,pin-func = <0>; + mdss_dsi_active: active { + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + output-high; + }; + mdss_dsi_suspend: suspend { + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + output-low; + }; + }; + + wcnss_pmux_5wire: wcnss_pmux_5wire { + /* Uses general purpose pins */ + qcom,pins = <&gp 40>, <&gp 41>, + <&gp 42>, <&gp 43>, + <&gp 44>; + qcom,num-grp-pins = <5>; + qcom,pin-func = <1>; + label = "wcnss_5wire_pins"; + /* Active configuration of bus pins */ + wcnss_default: wcnss_default { + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + wcnss_sleep: wcnss_sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + + wcnss_pmux_gpio: wcnss_pmux_gpio { + /* Uses general purpose pins */ + qcom,pins = <&gp 40>, <&gp 41>, + <&gp 42>, <&gp 43>, + <&gp 44>; + qcom,num-grp-pins = <5>; + qcom,pin-func = <0>; + label = "wcnss_5gpio_pins"; + /* Active configuration of bus pins */ + wcnss_gpio_default: wcnss_gpio_default { + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + + pmx_i2c_6 { + /* CLK, DATA */ + qcom,pins = <&gp 22>, <&gp 23>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <2>; + label = "pmx_i2c_6"; + /* active state */ + i2c_6_active: i2c_6_active{ + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + /*suspended state */ + i2c_6_sleep: i2c_6_sleep { + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + pmx_rd_nfc_int{ + qcom,pins = <&gp 21>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_nfc_int"; + + nfc_int_active: active { + drive-strength = <6>; + bias-pull-up; + }; + + nfc_int_suspend: suspend { + drive-strength = <6>; + bias-pull-up; + }; + }; + + pmx_nfc_reset{ + qcom,pins = <&gp 20>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_nfc_disable"; + + nfc_disable_active: active { + drive-strength = <6>; + bias-pull-up; + }; + + nfc_disable_suspend: suspend { + drive-strength = <6>; + bias-disable; + }; + }; + + pmx_mdss_te: pmx_mdss_te { + label = "mdss-te-pin"; + qcom,pin-func = <1>; + mdss_te_active: active { + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-debounce = <0>; + }; + mdss_te_suspend: suspend { + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-debounce = <0>; + }; + }; + + /* CoreSight */ + tpiu_seta_1 { + qcom,pins = <&gp 8>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <3>; + label = "tpiu-seta-1"; + seta_1: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_2 { + qcom,pins = <&gp 9>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-2"; + seta_2: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_3 { + qcom,pins = <&gp 10>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <3>; + label = "tpiu-seta-3"; + seta_3: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_4 { + qcom,pins = <&gp 39>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-4"; + seta_4: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_5 { + qcom,pins = <&gp 40>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-5"; + seta_5: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_6 { + qcom,pins = <&gp 41>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-6"; + seta_6: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_7 { + qcom,pins = <&gp 42>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-7"; + seta_7: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_8 { + qcom,pins = <&gp 43>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <3>; + label = "tpiu-seta-8"; + seta_8: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_9 { + qcom,pins = <&gp 45>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <3>; + label = "tpiu-seta-9"; + seta_9: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_10 { + qcom,pins = <&gp 46>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-10"; + seta_10: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_11 { + qcom,pins = <&gp 47>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <3>; + label = "tpiu-seta-11"; + seta_11: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_12 { + qcom,pins = <&gp 48>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-12"; + seta_12: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_13 { + qcom,pins = <&gp 62>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-13"; + seta_13: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_14 { + qcom,pins = <&gp 69>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "tpiu-seta-14"; + seta_14: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_15 { + qcom,pins = <&gp 112>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <5>; + label = "tpiu-seta-15"; + seta_15: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_16 { + qcom,pins = <&gp 113>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <9>; + label = "tpiu-seta-16"; + seta_16: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_17 { + qcom,pins = <&gp 114>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <8>; + label = "tpiu-seta-17"; + seta_17: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_seta_18 { + qcom,pins = <&gp 115>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <8>; + label = "tpiu-seta-18"; + seta_18: seta { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_1 { + qcom,pins = <&gp 4>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <5>; + label = "tpiu-setb-1"; + setb_1: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_2 { + qcom,pins = <&gp 5>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <5>; + label = "tpiu-setb-2"; + setb_2: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_3 { + qcom,pins = <&gp 26>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <7>; + label = "tpiu-setb-3"; + setb_3: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_4 { + qcom,pins = <&gp 27>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <9>; + label = "tpiu-setb-4"; + setb_4: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_5 { + qcom,pins = <&gp 28>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <7>; + label = "tpiu-setb-5"; + setb_5: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_6 { + qcom,pins = <&gp 29>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <7>; + label = "tpiu-setb-6"; + setb_6: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_7 { + qcom,pins = <&gp 30>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <9>; + label = "tpiu-setb-7"; + setb_7: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_8 { + qcom,pins = <&gp 31>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <10>; + label = "tpiu-setb-8"; + setb_8: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_9 { + qcom,pins = <&gp 32>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <10>; + label = "tpiu-setb-9"; + setb_9: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_10 { + qcom,pins = <&gp 33>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <9>; + label = "tpiu-setb-10"; + setb_10: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_11 { + qcom,pins = <&gp 34>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <9>; + label = "tpiu-setb-11"; + setb_11: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_12 { + qcom,pins = <&gp 35>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <9>; + label = "tpiu-setb-12"; + setb_12: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_13 { + qcom,pins = <&gp 36>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <8>; + label = "tpiu-setb-13"; + setb_13: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_14 { + qcom,pins = <&gp 37>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <7>; + label = "tpiu-setb-14"; + setb_14: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_15 { + qcom,pins = <&gp 110>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <4>; + label = "tpiu-setb-15"; + setb_15: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_16 { + qcom,pins = <&gp 111>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <1>; + label = "tpiu-setb-16"; + setb_16: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_17 { + qcom,pins = <&gp 120>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <10>; + label = "tpiu-setb-17"; + setb_17: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tpiu_setb_18 { + qcom,pins = <&gp 121>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <11>; + label = "tpiu-setb-18"; + setb_18: setb { + drive-strength = <16>; + bias-disable; + }; + }; + + tlmm_gpio_key { + qcom,pins = <&gp 107>, <&gp 108>, <&gp 109>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <3>; + label = "tlmm_gpio_key"; + gpio_key_active: gpio_key_active { + drive-strength = <2>; + bias-pull-up; + }; + gpio_key_suspend: gpio_key_suspend { + drive-strength = <2>; + bias-pull-up; + }; + }; + + gpio_led_pins { + qcom,pins = <&gp 8>, <&gp 9>, <&gp 10>; + qcom,num-grp-pins = <3>; + label = "gpio-led-pins"; + gpio_led_off: led_off { + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* add pingrp for touchscreen */ + pmx_ts_int_active { + qcom,pins = <&gp 13>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_ts_int_active"; + + ts_int_active: ts_int_active { + drive-strength = <16>; + bias-pull-up; + }; + }; + + pmx_ts_int_suspend { + qcom,pins = <&gp 13>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_ts_int_suspend"; + + ts_int_suspend: ts_int_suspend { + drive-strength = <2>; + bias-pull-down; + }; + }; + + pmx_ts_reset_active { + qcom,pins = <&gp 12>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_ts_reset_active"; + + ts_reset_active: ts_reset_active { + drive-strength = <16>; + bias-pull-up; + }; + }; + + pmx_ts_reset_suspend { + qcom,pins = <&gp 12>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_ts_reset_suspend"; + + ts_reset_suspend: ts_reset_suspend { + drive-strength = <2>; + bias-pull-down; + }; + }; + + cci0_pinmux { + /* CLK, DATA */ + qcom,pins = <&gp 29>, <&gp 30>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <1>; + label = "cci0"; + /* active state */ + cci0_default: default { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + /*suspended state */ + cci0_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + cam_sensor_mclk0 { + /* MCLK */ + qcom,pins = <&gp 26>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <1>; + label = "cam-sensor-mclk0"; + /* active state */ + cam_sensor_mclk0_default: default { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + cam_sensor_mclk0_sleep { + /* MCLK */ + qcom,pins = <&gp 26>; + qcom,num-grp-pins = <1>; + label = "cam-sensor-mclk0-sleep"; + /* suspend state */ + cam_sensor_mclk0_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + cam_sensor_mclk1 { + /* MCLK */ + qcom,pins = <&gp 27>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <1>; + label = "cam-sensor-mclk1"; + /* active state */ + cam_sensor_mclk1_default: default { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + cam_sensor_mclk1_sleep { + /* MCLK */ + qcom,pins = <&gp 27>; + qcom,num-grp-pins = <1>; + label = "cam-sensor-mclk1-sleep"; + /* suspend state */ + cam_sensor_mclk1_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + cam_sensor_rear { + /* RESET, STANDBY */ + qcom,pins = <&gp 35>, <&gp 34>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "cam-sensor-rear"; + /* active state */ + cam_sensor_rear_default: default { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + cam_sensor_rear_sleep { + /* RESET, STANDBY */ + qcom,pins = <&gp 35>, <&gp 34>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "cam-sensor-rear-sleep"; + /*suspended state */ + cam_sensor_rear_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + cam_sensor_front { + /* RESET, STANDBY */ + qcom,pins = <&gp 28>, <&gp 33>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "cam_sensor_front"; + /* active state */ + cam_sensor_front_default: default { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + cam_sensor_front_sleep { + /* RESET, STANDBY */ + qcom,pins = <&gp 28>, <&gp 33>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "cam_sensor_front"; + /*suspended state */ + cam_sensor_front_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down = <0>; /* PULL DOWN */ + }; + }; + + cam_sensor_flash { + /* FLSH_RESET,FLASH_EN,FLASH_NOW */ + qcom,pins = <&gp 36>, <&gp 31>,<&gp 32> ; + qcom,num-grp-pins = <3>; + qcom,pin-func = <0>; + label = "cam_sensor_flash"; + /* active state */ + cam_sensor_flash_default: default { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + /*suspended state */ + cam_sensor_flash_sleep: sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down = <0>; /* PULL DOWN */ + }; + }; + + pmx_i2c_4 { + /* CLK, DATA */ + qcom,pins = <&gp 14>, <&gp 15>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <2>; + label = "pmx_i2c_4"; + + i2c_4_active: i2c_4_active { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + + i2c_4_sleep: i2c_4_sleep { + drive-strength = <2>; /* 2 MA */ + bias-disable = <0>; /* No PULL */ + }; + + }; + + smb_int_pin { + qcom,pins = <&gp 62>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "smb1360_int_gpio"; + smb_int_default: smb_int_default { + drive-strength = <2>; /* 2 MA */ + bias-pull-up; /* PULL UP*/ + }; + }; + + button_backlight_pin { + qcom,pins = <&gp 119>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "button-backlight-pin"; + button_backlight_off: button_backlight_off { + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + mpu6050_int_pin { + qcom,pins = <&gp 115>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "mpu6050-irq"; + mpu6050_default: mpu6050_default { + drive-strength = <6>; + bias-pull-up; + }; + mpu6050_sleep: mpu6050_sleep { + drive-strength = <2>; + }; + }; + + apds99xx_int_pin { + qcom,pins = <&gp 113>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "apds99xx-irq"; + apds99xx_default: apds99xx_default { + drive-strength = <6>; + bias-pull-up; + }; + apds99xx_sleep: apds99xx_sleep { + drive-strength = <2>; + bias-pull-down; + }; + }; + ak8963_int_pin { + qcom,pins = <&gp 69>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "ak8963-irq"; + ak8963_default: ak8963_default { + drive-strength = <6>; + bias-pull-up; + }; + ak8963_sleep: ak8963_sleep { + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/msm8916-pm.dtsi b/arch/arm/boot/dts/msm8916-pm.dtsi new file mode 100644 index 000000000000..b060b77be254 --- /dev/null +++ b/arch/arm/boot/dts/msm8916-pm.dtsi @@ -0,0 +1,345 @@ +/* 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 { + qcom,spm@b089000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb089000 0x1000>; + qcom,core-id = <0>; + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x14>; + qcom,saw2-spm-dly= <0x3C102800>; + qcom,saw2-spm-ctl = <0xe>; + qcom,saw2-spm-cmd-wfi = [60 03 60 0B 0f]; + qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + }; + + qcom,spm@b099000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb099000 0x1000>; + qcom,core-id = <1>; + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x14>; + qcom,saw2-spm-dly= <0x3c102800>; + qcom,saw2-spm-ctl = <0xe>; + qcom,saw2-spm-cmd-wfi = [60 03 60 0B 0f]; + qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + }; + + qcom,spm@b0a9000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb0a9000 0x1000>; + qcom,core-id = <2>; + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x14>; + qcom,saw2-spm-dly= <0x3c102800>; + qcom,saw2-spm-ctl = <0xe>; + qcom,saw2-spm-cmd-wfi = [60 03 60 0B 0f]; + qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + }; + + qcom,spm@b0b9000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb0b9000 0x1000>; + qcom,core-id = <3>; + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x14>; + qcom,saw2-spm-dly= <0x3c102800>; + qcom,saw2-spm-ctl = <0xe>; + qcom,saw2-spm-cmd-wfi = [60 03 60 0B 0f]; + qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3B 76 76 0B + 94 5B 80 10 26 30 0f]; + }; + + qcom,spm@b012000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb012000 0x1000>; + qcom,core-id = <0xffff>; /* L2/APCS SAW */ + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x1F>; + qcom,saw2-spm-dly= <0x3C102800>; + qcom,saw2-spm-ctl = <0xe>; + qcom,saw2-pmic-data0 = <0x04030080>; + qcom,saw2-pmic-data1 = <0x01030000>; + qcom,vctl-timeout-us = <50>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,pfm-port = <0x2>; + qcom,saw2-spm-cmd-ret = [00 03 00 0f]; + qcom,saw2-spm-cmd-gdhs = [00 20 32 6B C0 E0 D0 42 F0 03 50 4E + 02 02 D0 E0 C0 22 6B 02 32 52 F0 0F]; + qcom,saw2-spm-cmd-pc = [00 32 B0 10 E0 D0 6B C0 42 11 07 01 + B0 50 4E 02 02 C0 D0 12 E0 6B 02 32 50 0F]; + qcom,L2-spm-is-apcs-master; + }; + + + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + qcom,default-l2-state = "l2_cache_active"; + qcom,allow-synced-levels; + #address-cells = <1>; + #size-cells = <0>; + + qcom,cpu-modes { + compatible = "qcom,cpu-modes"; + + qcom,cpu-mode@0 { + qcom,mode = "wfi"; + qcom,latency-us = <1>; + qcom,ss-power = <560>; + qcom,energy-overhead = <12000>; + qcom,time-overhead = <20>; + }; + + qcom,cpu-mode@1 { + qcom,mode = "standalone_pc"; + qcom,latency-us = <180>; + qcom,ss-power = <550>; + qcom,energy-overhead = <160000>; + qcom,time-overhead = <280>; + qcom,use-broadcast-timer; + }; + + qcom,cpu-mode@2 { + qcom,mode = "pc"; + qcom,latency-us = <230>; + qcom,ss-power = <535>; + qcom,energy-overhead = <200000>; + qcom,time-overhead = <330>; + qcom,use-broadcast-timer; + }; + }; + + qcom,system-modes { + compatible = "qcom,system-modes"; + + qcom,system-mode@0 { + qcom,l2 = "l2_cache_gdhs"; + qcom,latency-us = <240>; + qcom,ss-power = <530>; + qcom,energy-overhead = <210000>; + qcom,time-overhead = <350>; + qcom,min-cpu-mode= "standalone_pc"; + qcom,sync-mode; + }; + + qcom,system-mode@1 { + qcom,l2 = "l2_cache_pc"; + qcom,latency-us = <10900>; + qcom,ss-power = <490>; + qcom,energy-overhead = <1030563>; + qcom,time-overhead = <1656>; + qcom,min-cpu-mode= "pc"; + qcom,send-rpm-sleep-set; + qcom,sync-mode; + }; + }; + }; + qcom,pm-boot { + compatible = "qcom,pm-boot"; + qcom,mode = "tz"; + }; + + qcom,mpm@601d0 { + + status = "disabled"; + + compatible = "qcom,mpm-v2"; + reg = <0x601d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */ + <0xb011008 0x4>; + reg-names = "vmpm", "ipc"; + interrupts = <0 171 1>; + clocks = <&clock_rpm clk_xo_lpm_clk>; + clock-names = "xo"; + + qcom,ipc-bit-offset = <1>; + + qcom,gic-parent = <&intc>; + qcom,gic-map = <2 216>, /* tsens_upper_lower_int */ + <50 172>, /* usb1_hs_async_wakeup_irq */ + <53 104>, /* mdss_irq */ + <62 222>, /* ee0_krait_hlos_spmi_periph_irq */ + <0xff 18>, /* APC_qgicQTmrSecPhysIrptReq */ + <0xff 19>, /* APC_qgicQTmrNonSecPhysIrptReq */ + <0xff 20>, /* qgicQTmrVirtIrptReq */ + <0xff 35>, /* WDT_barkInt */ + <0xff 39>, /* arch_mem_timer */ + <0xff 40>, /* qtmr_phy_irq[0] */ + <0xff 47>, /* rbif_irq[0] */ + <0xff 56>, /* q6_wdog_expired_irq */ + <0xff 57>, /* mss_to_apps_irq(0) */ + <0xff 58>, /* mss_to_apps_irq(1) */ + <0xff 59>, /* mss_to_apps_irq(2) */ + <0xff 60>, /* mss_to_apps_irq(3) */ + <0xff 61>, /* mss_a2_bam_irq */ + <0xff 65>, /* o_gc_sys_irq[0] */ + <0xff 74>, /* venus0_mmu_cirpt[1] */ + <0xff 75>, /* venus0_mmu_cirpt[0] */ + <0xff 78>, /* mdss_mmu_cirpt[0] */ + <0xff 79>, /* mdss_mmu_cirpt[1] */ + <0xff 97>, /* camss_vfe_mmu_cirpt[1] */ + <0xff 102>, /* camss_jpeg_mmu_cirpt[1] */ + <0xff 109>, /* ocmem_dm_nonsec_irq */ + <0xff 131>, /* blsp1_qup_5_irq */ + <0xff 140>, /* blsp1_uart_3_irq */ + <0xff 166>, /* usb_hs_irq */ + <0xff 155>, /* sdc1_irq(0) */ + <0xff 157>, /* sdc2_irq(0) */ + <0xff 170>, /* sdc1_pwr_cmd_irq */ + <0xff 173>, /* o_wcss_apss_smd_hi */ + <0xff 174>, /* o_wcss_apss_smd_med */ + <0xff 175>, /* o_wcss_apss_smd_low */ + <0xff 176>, /* o_wcss_apss_smsm_irq */ + <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */ + <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */ + <0xff 179>, /* o_wcss_apss_asic_intr */ + <0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */ + + <0xff 188>, /* lpass_irq_out_apcs(0) */ + <0xff 189>, /* lpass_irq_out_apcs(1) */ + <0xff 190>, /* lpass_irq_out_apcs(2) */ + <0xff 191>, /* lpass_irq_out_apcs(3) */ + <0xff 192>, /* lpass_irq_out_apcs(4) */ + <0xff 193>, /* lpass_irq_out_apcs(5) */ + <0xff 194>, /* lpass_irq_out_apcs(6) */ + <0xff 195>, /* lpass_irq_out_apcs(7) */ + <0xff 196>, /* lpass_irq_out_apcs(8) */ + <0xff 197>, /* lpass_irq_out_apcs(9) */ + <0xff 198>, /* coresight-tmc-etr interrupt */ + <0xff 200>, /* rpm_ipc(4) */ + <0xff 201>, /* rpm_ipc(5) */ + <0xff 202>, /* rpm_ipc(6) */ + <0xff 203>, /* rpm_ipc(7) */ + <0xff 204>, /* rpm_ipc(24) */ + <0xff 205>, /* rpm_ipc(25) */ + <0xff 206>, /* rpm_ipc(26) */ + <0xff 207>, /* rpm_ipc(27) */ + <0xff 239>, /* crypto_bam_irq[1]*/ + <0xff 240>, /* summary_irq_kpss */ + <0xff 253>, /* sdc2_pwr_cmd_irq */ + <0xff 263>, /* msm_iommu_global_client_irq */ + <0xff 269>, /* rpm_wdog_expired_irq */ + <0xff 270>, /* blsp1_bam_irq[0] */ + <0xff 275>, /* rpm_ipc(30) */ + <0xff 276>; /* rpm_ipc(31) */ + + qcom,gpio-parent = <&msm_gpio>; + qcom,gpio-map = <3 108 >, + <4 1 >, + <5 5 >, + <6 9 >, + <7 107>, + <8 98>, + <9 97>, + <10 11>, + <11 69>, + <12 12>, + <13 13>, + <14 20>, + <15 62>, + <16 54>, + <17 21>, + <18 52>, + <19 25>, + <20 51>, + <21 50>, + <22 28>, + <23 31>, + <24 34>, + <25 35>, + <26 36>, + <27 37>, + <28 38>, + <29 49>, + <30 109>, + <31 110>, + <32 111>, + <33 112>, + <34 113>, + <35 114>, + <36 115>, + <37 117>, + <38 118>, + <39 120>, + <40 121>, + <50 66>, + <51 68>; + }; + + qcom,pm@8600664 { + compatible = "qcom,pm"; + reg = <0x8600664 0x40>; + qcom,pc-mode = "tz_l2_int"; + qcom,use-sync-timer; + qcom,synced-clocks; + }; + + qcom,cpu-sleep-status@b088008{ + compatible = "qcom,cpu-sleep-status"; + reg = <0xb088008 0x100>; + qcom,cpu-alias-addr = <0x10000>; + qcom,sleep-status-mask= <0x40000>; + }; + + qcom,rpm-log@29dc00 { + compatible = "qcom,rpm-log"; + reg = <0x29dc00 0x4000>; + qcom,rpm-addr-phys = <0xfc000000>; + qcom,offset-version = <4>; + qcom,offset-page-buffer-addr = <36>; + qcom,offset-log-len = <40>; + qcom,offset-log-len-mask = <44>; + qcom,offset-page-indices = <56>; + }; + + qcom,rpm-stats@29dba0 { + compatible = "qcom,rpm-stats"; + reg = <0x29dba0 0x1000>; + reg-names = "phys_addr_base"; + qcom,sleep-stats-version = <2>; + }; + + qcom,rpm-master-stats@60150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x60150 0x2030>; + qcom,masters = "APSS", "MPSS", "PRONTO"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; + qcom,rpm-rbcpr-stats@0x29daa0 { + compatible = "qcom,rpmrbcpr-stats"; + reg = <0x29daa0 0x1a0000>; + qcom,start-offset = <0x190010>; + }; +}; diff --git a/arch/arm/boot/dts/msm8916-qrd-skui.dts b/arch/arm/boot/dts/msm8916-qrd-skui.dts new file mode 100644 index 000000000000..6f409f7f8dc9 --- /dev/null +++ b/arch/arm/boot/dts/msm8916-qrd-skui.dts @@ -0,0 +1,36 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; + +#include "msm8916-qrd-skui.dtsi" +#include "msm8916-memory.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8916 QRD SKUI"; + compatible = "qcom,msm8916-qrd-skui", "qcom,msm8916-qrd", "qcom,msm8916", "qcom,qrd"; + qcom,board-id = <0x1000b 5> , <0x1010b 5> , <0x3010b 5>; +}; + +&soc { + gen-vkeys { + compatible = "qcom,gen-vkeys"; + label = "ft5x06_ts"; + qcom,disp-maxx = <480>; + qcom,disp-maxy = <854>; + qcom,panel-maxx = <480>; + qcom,panel-maxy = <946>; + qcom,key-codes = <139 172 158>; + qcom,y-offset = <0>; + }; +}; + diff --git a/arch/arm/boot/dts/msm8916-qrd-skui.dtsi b/arch/arm/boot/dts/msm8916-qrd-skui.dtsi new file mode 100644 index 000000000000..e3c1b467af3b --- /dev/null +++ b/arch/arm/boot/dts/msm8916-qrd-skui.dtsi @@ -0,0 +1,67 @@ +/* Copyright (c) 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 "msm8916-qrd.dtsi" + +&tlmm_pinmux { + ocp8110_pins { + qcom,pins = <&gp 31>, <&gp 32>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "ocp8110_pins"; + ocp8110_default: en_default { + drive-strength = <2>; + bias-pull-down; + }; + }; + + bma2x2_int1_pin { + qcom,pins = <&gp 112>; + qcom,num-grp-pins = <1>; + label = "bma2x2_int1_pin"; + bma2x2_int1_default: int1_default { + drive-strength = <6>; + bias-pull-up; + }; + }; + + bma2x2_int2_pin { + qcom,pins = <&gp 114>; + qcom,num-grp-pins = <1>; + label = "bma2x2_int2_pin"; + bma2x2_int2_default: int2_default { + drive-strength = <6>; + bias-pull-up; + }; + }; +}; + +&sdc2_cd_on { + /delete-property/ bias-pull-up; + bias-pull-down; +}; + +&sdc2_cd_off { + /delete-property/ bias-disable; + bias-pull-down; +}; + +&sdhc_2 { + qcom,nonremovable; + + interrupts = <0 1>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + /delete-property/ cd-gpios; +}; + diff --git a/arch/arm/boot/dts/msm8916-qrd.dtsi b/arch/arm/boot/dts/msm8916-qrd.dtsi new file mode 100644 index 000000000000..445dca98a888 --- /dev/null +++ b/arch/arm/boot/dts/msm8916-qrd.dtsi @@ -0,0 +1,137 @@ +/* Copyright (c) 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 "msm8916.dtsi" +#include "msm8916-pinctrl.dtsi" + +/ { + aliases { + serial0 = &blsp1_uart2; + }; +}; + + +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_sleep>; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend"; + pinctrl-0 = <&gpio_key_active>; + pinctrl-1 = <&gpio_key_suspend>; + + vol_up { + label = "volume_up"; + gpios = <&msm_gpio 107 0x1>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; +}; + +&pm8916_gpios { + gpio@c000 { /* GPIO 1 */ + /* Battery UICC Alarm */ + status = "disabled"; + }; + + gpio@c100 { /* GPIO 2 */ + /* NFC_CLK_REQ */ + qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */ + qcom,pull = <5>; /* QPNP_PIN_PULL_NO */ + qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */ + qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */ + qcom,master-en = <1>; + }; + + gpio@c200 { /* GPIO 3 */ + /* External regulator control for WTR */ + status = "disabled"; + }; + + gpio@c300 { /* GPIO 4 */ + /* External regulator control for APC */ + status = "disabled"; + }; +}; + +&sdhc_1 { + vdd-supply = <&pm8916_l8>; + qcom,vdd-voltage-level = <2900000 2900000>; + qcom,vdd-current-level = <200 400000>; + + vdd-io-supply = <&pm8916_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 60000>; + + 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>; + + qcom,nonremovable; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8916_l11>; + qcom,vdd-voltage-level = <2800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + vdd-io-supply = <&pm8916_l12>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 50000>; + + 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 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&msm_gpio 38 0x0>; + + status = "ok"; +}; + +&spmi_bus { + qcom,pm8916@1 { + qcom,vibrator@c000 { + status = "okay"; + qcom,vib-timeout-ms = <15000>; + qcom,vib-vtg-level-mV = <3100>; + }; + }; +}; + +&qcom_tzlog { + status = "okay"; +}; + + + + diff --git a/arch/arm/boot/dts/msm8916-regulator.dtsi b/arch/arm/boot/dts/msm8916-regulator.dtsi new file mode 100644 index 000000000000..7fe4f6d9906b --- /dev/null +++ b/arch/arm/boot/dts/msm8916-regulator.dtsi @@ -0,0 +1,373 @@ +/* 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. + */ + +/* SPM controlled regulators */ +&spmi_bus { + qcom,pm8916@1 { + pm8916_s2: spm-regulator@1700 { + compatible = "qcom,spm-regulator"; + regulator-name = "8916_s2"; + reg = <0x1700 0x100>; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1350000>; + }; + }; +}; + +/* CPR controlled regulator */ + +&soc { + mem_acc_vreg_corner: regulator@1946000 { + compatible = "qcom,mem-acc-regulator"; + reg = <0x1946000 0x4>, <0x1946000 0x4>, <0x58000 0x1000>; + reg-names = "acc-sel-l1", "acc-sel-l2", "efuse_addr"; + regulator-name = "mem_acc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <3>; + + qcom,acc-sel-l1-bit-pos = <0>; + qcom,acc-sel-l2-bit-pos = <8>; + qcom,corner-acc-map = <0 1 1>; + qcom,l1-config-skip-fuse-sel = <0 52 1 1 0>; + }; + + apc_vreg_corner: regulator@b018000 { + compatible = "qcom,cpr-regulator"; + reg = <0xb018000 0x1000>, <0xb011064 4>, <0x58000 0x1000>; + reg-names = "rbcpr", "rbcpr_clk", "efuse_addr"; + interrupts = <0 15 0>; + regulator-name = "apc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,cpr-voltage-ceiling = <1050000 1150000 1350000>; + qcom,cpr-voltage-floor = <1050000 1050000 1162500>; + vdd-apc-supply = <&pm8916_s2>; + + qcom,vdd-mx-corner-map = <4 5 7>; + qcom,vdd-mx-vmin-method = <4>; + vdd-mx-supply = <&pm8916_l3_corner_ao>; + qcom,vdd-mx-vmax = <7>; + + mem-acc-supply = <&mem_acc_vreg_corner>; + + qcom,cpr-ref-clk = <19200>; + qcom,cpr-timer-delay = <5000>; + qcom,cpr-timer-cons-up = <0>; + qcom,cpr-timer-cons-down = <2>; + qcom,cpr-irq-line = <0>; + qcom,cpr-step-quotient = <26>; + qcom,cpr-up-threshold = <0>; + qcom,cpr-down-threshold = <2>; + qcom,cpr-idle-clocks = <15>; + qcom,cpr-gcnt-time = <1>; + qcom,vdd-apc-step-up-limit = <1>; + qcom,vdd-apc-step-down-limit = <1>; + qcom,cpr-apc-volt-step = <12500>; + + qcom,cpr-fuse-row = <27 0>; + qcom,cpr-fuse-target-quot = <42 24 6>; + qcom,cpr-fuse-ro-sel = <54 54 54>; + qcom,cpr-fuse-bp-cpr-disable = <57>; + qcom,cpr-fuse-init-voltage = + <27 36 6 0>, + <27 18 6 0>, + <27 0 6 0>; + qcom,cpr-init-voltage-step = <10000>; + qcom,cpr-corner-map = <1 1 2 2 3 3 3>; + qcom,cpr-corner-frequency-map = + <1 200000000>, + <2 400000000>, + <3 533330000>, + <4 800000000>, + <5 998400000>, + <6 1094400000>, + <7 1190400000>; + qcom,speed-bin-fuse-sel = <1 34 3 0>; + qcom,cpr-speed-bin-max-corners = + <0 0 2 4 7>; + qcom,cpr-quot-adjust-scaling-factor-max = <650>; + qcom,cpr-enable; + }; +}; + + +/* RPM controlled regulators */ +&rpm_bus { + + /* PM8916 S1 VDD_CX supply */ + rpm-regulator-smpa1 { + status = "okay"; + pm8916_s1_corner: regulator-s1-corner { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s1_corner"; + qcom,set = <3>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + qcom,use-voltage-corner; + }; + pm8916_s1_corner_ao: regulator-s1-corner-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s1_corner_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + qcom,use-voltage-corner; + }; + pm8916_s1_floor_corner: regulator-s1-floor-corner { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_s1_floor_corner"; + qcom,set = <3>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + qcom,use-voltage-floor-corner; + qcom,always-send-voltage; + }; + }; + + rpm-regulator-smpa3 { + status = "okay"; + pm8916_s3: regulator-s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa4 { + status = "okay"; + pm8916_s4: regulator-s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa1 { + status = "okay"; + pm8916_l1: regulator-l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa2 { + status = "okay"; + pm8916_l2: regulator-l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + /* PM8916 L3 VDD_MX supply */ + rpm-regulator-ldoa3 { + status = "okay"; + pm8916_l3: regulator-l3 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1287500>; + status = "okay"; + }; + + pm8916_l3_corner_ao: regulator-l3-corner-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l3_corner_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + qcom,use-voltage-corner; + }; + + pm8916_l3_corner_so: regulator-l3-corner-so { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l3_corner_so"; + qcom,set = <2>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + qcom,use-voltage-corner; + qcom,init-voltage = <1>; + }; + }; + + rpm-regulator-ldoa4 { + status = "okay"; + pm8916_l4: regulator-l4 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + qcom,init-voltage = <2050000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa5 { + status = "okay"; + pm8916_l5: regulator-l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + pm8916_l6: regulator-l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa7 { + status = "okay"; + pm8916_l7: regulator-l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + + pm8916_l7_ao: regulator-l7-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l7_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + + pm8916_l7_so: regulator-l7-so { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8916_l7_so"; + qcom,set = <2>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-enable = <0>; + }; + }; + + rpm-regulator-ldoa8 { + status = "okay"; + pm8916_l8: regulator-l8 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2900000>; + qcom,init-voltage = <2850000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa9 { + status = "okay"; + pm8916_l9: regulator-l9 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <3300000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + pm8916_l10: regulator-l10 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2800000>; + qcom,init-voltage = <2700000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + pm8916_l11: regulator-l11 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + pm8916_l12: regulator-l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + pm8916_l13: regulator-l13 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + qcom,init-voltage = <3075000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa14 { + status = "okay"; + pm8916_l14: regulator-l14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa15 { + status = "okay"; + pm8916_l15: regulator-l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa16 { + status = "okay"; + pm8916_l16: regulator-l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa17 { + status = "okay"; + pm8916_l17: regulator-l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + qcom,init-voltage = <2850000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa18 { + status = "okay"; + pm8916_l18: regulator-l18 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + qcom,init-voltage = <2700000>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/msm8916.dtsi b/arch/arm/boot/dts/msm8916.dtsi new file mode 100644 index 000000000000..2e7d8c6c6a3d --- /dev/null +++ b/arch/arm/boot/dts/msm8916.dtsi @@ -0,0 +1,810 @@ +/* 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 "skeleton64.dtsi" +#include <dt-bindings/clock/msm-clocks-8916.h> + +/ { + model = "Qualcomm Technologies, Inc. MSM8916"; + compatible = "qcom,msm8916"; + qcom,msm-id = <206 0>, + <248 0>, + <249 0>, + <250 0>; + + interrupt-parent = <&intc>; + aliases { + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD card slot */ + + /* smdtty devices */ + smd1 = &smdtty_apps_fm; + smd2 = &smdtty_apps_riva_bt_acl; + smd3 = &smdtty_apps_riva_bt_cmd; + smd4 = &smdtty_mbalbridge; + smd5 = &smdtty_apps_riva_ant_cmd; + smd6 = &smdtty_apps_riva_ant_data; + smd7 = &smdtty_data1; + smd8 = &smdtty_data4; + smd11 = &smdtty_data11; + smd21 = &smdtty_data21; + smd36 = &smdtty_loopback; + + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0>; + enable-method = "qcom,arm-cortex-acc"; + qcom,acc = <&acc0>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x1>; + enable-method = "qcom,arm-cortex-acc"; + qcom,acc = <&acc1>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x2>; + enable-method = "qcom,arm-cortex-acc"; + qcom,acc = <&acc2>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x3>; + enable-method = "qcom,arm-cortex-acc"; + qcom,acc = <&acc3>; + }; + }; + + soc: soc { }; +}; + +#include "msm8916-ipcrouter.dtsi" +#include "msm-gdsc-8916.dtsi" + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + 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>; + }; + + intc: interrupt-controller@b000000 { + compatible = "qcom,msm-qgic2"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x0b000000 0x1000>, + <0x0b002000 0x1000>; + }; + + restart@4ab000 { + compatible = "qcom,pshold"; + reg = <0x4ab000 0x4>; + }; + + qcom,mpm2-sleep-counter@4a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x4a3000 0x1000>; + clock-frequency = <32768>; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = <1 2 0xf08>, + <1 3 0xf08>, + <1 4 0xf08>, + <1 1 0xf08>; + clock-frequency = <19200000>; + }; + + timer@b020000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0xb020000 0x1000>; + clock-frequency = <19200000>; + + frame@b021000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0xb021000 0x1000>, + <0xb022000 0x1000>; + }; + + frame@b023000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0xb023000 0x1000>; + status = "disabled"; + }; + + frame@b024000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0xb024000 0x1000>; + status = "disabled"; + }; + + frame@b025000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0xb025000 0x1000>; + status = "disabled"; + }; + + frame@b026000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0xb026000 0x1000>; + status = "disabled"; + }; + + frame@b027000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0xb027000 0x1000>; + status = "disabled"; + }; + + frame@b028000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0xb028000 0x1000>; + status = "disabled"; + }; + }; + + clock_rpm: qcom,rpmcc@1800000 { + compatible = "qcom,rpmcc-8916"; + reg = <0x1800000 0x80000>; + reg-names = "cc_base"; + #clock-cells = <1>; + + }; + + clock_gcc: qcom,gcc@1800000 { + compatible = "qcom,gcc-8916"; + reg = <0x1800000 0x80000>, + <0xb016000 0x00040>; + reg-names = "cc_base", "apcs_base"; + vdd_dig-supply = <&pm8916_s1_corner>; + vdd_sr2_dig-supply = <&pm8916_s1_corner_ao>; + vdd_sr2_pll-supply = <&pm8916_l7_ao>; + clocks = <&clock_rpm clk_xo_clk_src>, + <&clock_rpm clk_xo_a_clk_src>; + clock-names = "xo", "xo_a"; + #clock-cells = <1>; + }; + + clock_debug: qcom,cc-debug@1874000 { + compatible = "qcom,cc-debug-8916"; + reg = <0x1874000 0x4>, + <0xb01101c 0x8>; + reg-names = "cc_base", "meas"; + clocks = <&clock_rpm clk_rpm_debug_mux>; + clock-names = "rpm_debug_mux"; + #clock-cells = <1>; + }; + + tsens: tsens@4a8000 { + compatible = "qcom,msm8916-tsens"; + reg = <0x4a8000 0x2000>, + <0x5c000 0x1000>; + reg-names = "tsens_physical", "tsens_eeprom_physical"; + interrupts = <0 184 0>; + qcom,sensors = <5>; + qcom,slope = <3200 3200 3200 3200 3200>; + qcom,sensor-id = <0 1 2 4 5>; + }; + + qcom,clock-a7@0b011050 { + compatible = "qcom,clock-a53-8916"; + reg = <0x0b011050 0x8>, + <0x0005c004 0x8>; + reg-names = "rcg-base", "efuse1"; + qcom,safe-freq = < 400000000 >; + cpu-vdd-supply = <&apc_vreg_corner>; + clocks = <&clock_gcc clk_gpll0_ao_clk_src>, + <&clock_gcc clk_a53sspll>; + clock-names = "clk-4", "clk-5"; + qcom,speed0-bin-v0 = + < 0 0>, + < 200000000 1>, + < 400000000 2>, + < 533333000 3>, + < 800000000 4>, + < 998400000 5>, + < 1094400000 6>, + < 1152000000 7>, + < 1209600000 8>; + + qcom,speed1-bin-v0 = + < 0 0>, + < 200000000 1>, + < 400000000 2>, + < 533333000 3>, + < 800000000 4>, + < 998400000 5>, + < 1094400000 6>, + < 1152000000 7>; + }; + + qcom,cpubw { + compatible = "qcom,cpubw"; + qcom,cpu-mem-ports = <1 512>; + qcom,bw-tbl = + /* 73 9.60 MHz */ + /* 381 50MHz */ + < 762 /* 100 MHz */>, + < 1525 /* 200 MHz */>, + < 3051 /* 400 MHz */>, + < 4066 /* 533 MHz */>; + qcom,ab-tbl = + < 229 >, + < 458 >, + < 915 >, + < 1220 >; + }; + + qcom,msm-cpufreq@0 { + reg = <0 4>; + compatible = "qcom,msm-cpufreq"; + qcom,cpufreq-table = + < 200000 762>, + < 400000 762>, + < 533330 1525>, + < 800000 1525>, + < 998400 3051>, + < 1094400 3051>, + < 1152000 4066>, + < 1209600 4066>; + }; + + qcom,sps { + compatible = "qcom,msm_sps_4k"; + qcom,device-type = <3>; + qcom,pipe-attr-ee; + }; + + blsp1_uart1: uart@78af000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78af000 0x200>, + <0x7884000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 107 0 + 1 &intc 0 238 0 + 2 &msm_gpio 1 0>; + + qcom,inject-rx-on-wakeup = <1>; + qcom,rx-char-to-inject = <0xFD>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <86>; + + clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + clock-names = "core_clk", "iface_clk"; + + qcom,msm-bus,name = "blsp1_uart1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + status = "disabled"; + }; + + blsp1_uart2: serial@78b0000 { + compatible = "qcom,msm-lsuart-v14"; + reg = <0x78b0000 0x200>; + interrupts = <0 108 0>; + status = "disabled"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + clock-names = "core_clk", "iface_clk"; + }; + + rmtfs_sharedmem { + compatible = "qcom,sharedmem-uio"; + reg = <0x86700000 0xe0000>; + reg-names = "rmtfs"; + }; + + dsp_sharedmem { + compatible = "qcom,sharedmem-uio"; + reg = <0x867e0000 0x20000>; + reg-names = "rfsa_dsp"; + }; + + mdm_sharedmem { + compatible = "qcom,sharedmem-uio"; + reg = <0x867e0000 0x20000>; + reg-names = "rfsa_mdm"; + }; + + jtag_fuse: jtagfuse@5e01c { + compatible = "qcom,jtag-fuse"; + reg = <0x5e01c 0x8>; + reg-names = "fuse-base"; + }; + + sdhc_1: sdhci@07824000 { + compatible = "qcom,sdhci-msm"; + reg = <0x07824900 0x11c>, <0x07824000 0x800>; + reg-names = "hc_mem", "core_mem"; + + interrupts = <0 123 0>, <0 138 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + + qcom,cpu-dma-latency-us = <701>; + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */ + <78 512 1600 3200>, /* 400 KB/s*/ + <78 512 80000 160000>, /* 20 MB/s */ + <78 512 100000 200000>, /* 25 MB/s */ + <78 512 200000 400000>, /* 50 MB/s */ + <78 512 400000 800000>, /* 100 MB/s */ + <78 512 400000 800000>, /* 200 MB/s */ + <78 512 2048000 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>, + <&clock_gcc clk_gcc_sdcc1_apps_clk>; + clock-names = "iface_clk", "core_clk"; + + qcom,clk-rates = <400000 25000000 50000000 100000000 177770000>; + qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; + + status = "disabled"; + }; + + sdhc_2: sdhci@07864000 { + compatible = "qcom,sdhci-msm"; + reg = <0x07864900 0x11c>, <0x07864000 0x800>; + reg-names = "hc_mem", "core_mem"; + + interrupts = <0 125 0>, <0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + + qcom,cpu-dma-latency-us = <701>; + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */ + <81 512 1600 3200>, /* 400 KB/s*/ + <81 512 80000 160000>, /* 20 MB/s */ + <81 512 100000 200000>, /* 25 MB/s */ + <81 512 200000 400000>, /* 50 MB/s */ + <81 512 400000 800000>, /* 100 MB/s */ + <81 512 400000 800000>, /* 200 MB/s */ + <81 512 2048000 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>, + <&clock_gcc clk_gcc_sdcc2_apps_clk>; + clock-names = "iface_clk", "core_clk"; + + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + + status = "disabled"; + }; + + qcom,ipc-spinlock@1905000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1905000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,smem@86300000 { + compatible = "qcom,smem"; + reg = <0x86300000 0x100000>, + <0x0b011008 0x4>, + <0x60000 0x8000>, + <0x193D000 0x8>; + reg-names = "smem", "irq-reg-base", "aux-mem1", "smem_targ_info_reg"; + qcom,mpu-enabled; + + qcom,smd-modem { + compatible = "qcom,smd"; + qcom,smd-edge = <0>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x1000>; + qcom,pil-string = "modem"; + interrupts = <0 25 1>; + }; + + qcom,smsm-modem { + compatible = "qcom,smsm"; + qcom,smsm-edge = <0>; + qcom,smsm-irq-offset = <0x0>; + qcom,smsm-irq-bitmask = <0x2000>; + interrupts = <0 26 1>; + }; + + qcom,smd-wcnss { + compatible = "qcom,smd"; + qcom,smd-edge = <6>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x20000>; + qcom,pil-string = "wcnss"; + interrupts = <0 142 1>; + }; + + qcom,smsm-wcnss { + compatible = "qcom,smsm"; + qcom,smsm-edge = <6>; + qcom,smsm-irq-offset = <0x0>; + qcom,smsm-irq-bitmask = <0x80000>; + interrupts = <0 144 1>; + }; + + qcom,smd-rpm { + compatible = "qcom,smd"; + qcom,smd-edge = <15>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x1>; + interrupts = <0 168 1>; + qcom,irq-no-suspend; + }; + }; + + rpm_bus: qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + rpm-channel-name = "rpm_requests"; + rpm-channel-type = <15>; /* SMD_APPS_RPM */ + }; + + qcom,bam_dmux@4044000 { + compatible = "qcom,bam_dmux"; + reg = <0x4044000 0x19000>; + interrupts = <0 29 1>; + qcom,rx-ring-size = <32>; + }; + + qcom_tzlog: tz-log@8600720 { + compatible = "qcom,tz-log"; + reg = <0x08600720 0x1000>; + status = "disabled"; + }; + + qcom,smdtty { + compatible = "qcom,smdtty"; + + smdtty_apps_fm: qcom,smdtty-apps-fm { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_FM"; + }; + + smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_BT_ACL"; + }; + + smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_BT_CMD"; + }; + + smdtty_mbalbridge: qcom,smdtty-mbalbridge { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "MBALBRIDGE"; + }; + + smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD"; + }; + + smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA"; + }; + + smdtty_data1: qcom,smdtty-data1 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA1"; + }; + + smdtty_data4: qcom,smdtty-data4 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA4"; + }; + + smdtty_data11: qcom,smdtty-data11 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA11"; + }; + + smdtty_data21: qcom,smdtty-data21 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA21"; + }; + + smdtty_loopback: smdtty-loopback { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "LOOPBACK"; + qcom,smdtty-dev-name = "LOOPBACK_TTY"; + }; + }; + + qcom,smdpkt { + compatible = "qcom,smdpkt"; + + qcom,smdpkt-data5-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA5_CNTL"; + qcom,smdpkt-dev-name = "smdcntl0"; + }; + + qcom,smdpkt-data6-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA6_CNTL"; + qcom,smdpkt-dev-name = "smdcntl1"; + }; + + qcom,smdpkt-data7-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA7_CNTL"; + qcom,smdpkt-dev-name = "smdcntl2"; + }; + + qcom,smdpkt-data8-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA8_CNTL"; + qcom,smdpkt-dev-name = "smdcntl3"; + }; + + qcom,smdpkt-data9-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA9_CNTL"; + qcom,smdpkt-dev-name = "smdcntl4"; + }; + + qcom,smdpkt-data12-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA12_CNTL"; + qcom,smdpkt-dev-name = "smdcntl5"; + }; + + qcom,smdpkt-data13-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA13_CNTL"; + qcom,smdpkt-dev-name = "smdcntl6"; + }; + + qcom,smdpkt-data14-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA14_CNTL"; + qcom,smdpkt-dev-name = "smdcntl7"; + }; + + qcom,smdpkt-data15-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA15_CNTL"; + qcom,smdpkt-dev-name = "smdcntl9"; + }; + + qcom,smdpkt-data16-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA16_CNTL"; + qcom,smdpkt-dev-name = "smdcntl10"; + }; + + qcom,smdpkt-data17-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA17_CNTL"; + qcom,smdpkt-dev-name = "smdcntl11"; + }; + + qcom,smdpkt-data22 { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA22"; + qcom,smdpkt-dev-name = "smd22"; + }; + + qcom,smdpkt-data23-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA23_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev0"; + }; + + qcom,smdpkt-data24-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA24_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev1"; + }; + + qcom,smdpkt-data25-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA25_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev2"; + }; + + qcom,smdpkt-data26-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA26_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev3"; + }; + + qcom,smdpkt-data27-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA27_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev4"; + }; + + qcom,smdpkt-data28-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA28_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev5"; + }; + + qcom,smdpkt-data29-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA29_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev6"; + }; + + qcom,smdpkt-data30-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA30_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev7"; + }; + + qcom,smdpkt-data31-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA31_CNTL"; + qcom,smdpkt-dev-name = "smdcnt_rev8"; + }; + + qcom,smdpkt-data40-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA40_CNTL"; + qcom,smdpkt-dev-name = "smdcntl8"; + }; + + qcom,smdpkt-apr-apps2 { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "apr_apps2"; + qcom,smdpkt-dev-name = "apr_apps2"; + }; + + qcom,smdpkt-loopback { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "LOOPBACK"; + qcom,smdpkt-dev-name = "smd_pkt_loopback"; + }; + }; + + + spmi_bus: qcom,spmi@200f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x200f000 0x1000>, + <0x2400000 0x400000>, + <0x2c00000 0x400000>, + <0x3800000 0x200000>, + <0x200a000 0x2100>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupts = <0 190 0>; + qcom,pmic-arb-channel = <0>; + qcom,pmic-arb-ee = <0>; + #interrupt-cells = <3>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + }; + + qcom,msm-imem@8600000 { + compatible = "qcom,msm-imem"; + reg = <0x08600000 0x1000>; /* Address and size of IMEM */ + ranges = <0x0 0x08600000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + }; + + cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 7 0xf00>; + }; + +}; + +// AG 2014-11-29 without this, +40mA idle + +&gdsc_mdss { + status = "okay"; +}; + + +#include "msm-pm8916-rpm-regulator.dtsi" +#include "msm-pm8916.dtsi" +#include "msm8916-regulator.dtsi" +#include "msm8916-pm.dtsi" diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi index b41d241de2cd..f9988cd78c6a 100644 --- a/arch/arm/boot/dts/skeleton.dtsi +++ b/arch/arm/boot/dts/skeleton.dtsi @@ -9,5 +9,10 @@ #size-cells = <1>; chosen { }; aliases { }; - memory { device_type = "memory"; reg = <0 0>; }; + memory { + #address-cells = <1>; + #size-cells = <1>; + device_type = "memory"; + reg = <0 0>; + }; }; diff --git a/arch/arm/configs/msm8916-qrd-andy_defconfig b/arch/arm/configs/msm8916-qrd-andy_defconfig new file mode 100644 index 000000000000..4282e4b6b5f6 --- /dev/null +++ b/arch/arm/configs/msm8916-qrd-andy_defconfig @@ -0,0 +1,121 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=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_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=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_ARCH_MSM8916=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_SMP=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CP_ACCESS=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES="msm8916-qrd-skui" +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_CMDLINE="console=ttyHSL0,115200,n8" +CONFIG_ARM_DECOMPRESSOR_LIMIT=0x3200000 +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_RUNTIME=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_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=1024 +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_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_MMC=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=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_EXT4_FS_SECURITY=y +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_CRAMFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_UART_PHYS=0x078B0000 +CONFIG_DEBUG_UART_VIRT=0xFA0B0000 +CONFIG_EARLY_PRINTK=y +CONFIG_KEYS=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 10e78d00a0bb..5e4f2278242e 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -94,6 +94,21 @@ * DMA Cache Coherency * =================== * + * dma_inv_range(start, end) + * + * Invalidate (discard) the specified virtual address range. + * May not write back any entries. If 'start' or 'end' + * are not cache line aligned, those lines must be written + * back. + * - start - virtual start address + * - end - virtual end address + * + * dma_clean_range(start, end) + * + * Clean (write back) the specified virtual address range. + * - start - virtual start address + * - end - virtual end address + * * dma_flush_range(start, end) * * Clean and invalidate the specified virtual address range. @@ -115,6 +130,8 @@ struct cpu_cache_fns { void (*dma_map_area)(const void *, size_t, int); void (*dma_unmap_area)(const void *, size_t, int); + void (*dma_inv_range)(const void *, const void *); + void (*dma_clean_range)(const void *, const void *); void (*dma_flush_range)(const void *, const void *); }; @@ -142,6 +159,8 @@ extern struct cpu_cache_fns cpu_cache; */ #define dmac_map_area cpu_cache.dma_map_area #define dmac_unmap_area cpu_cache.dma_unmap_area +#define dmac_inv_range cpu_cache.dma_inv_range +#define dmac_clean_range cpu_cache.dma_clean_range #define dmac_flush_range cpu_cache.dma_flush_range #else @@ -163,6 +182,8 @@ extern void __cpuc_flush_dcache_area(void *, size_t); */ extern void dmac_map_area(const void *, size_t, int); extern void dmac_unmap_area(const void *, size_t, int); +extern void dmac_inv_range(const void *, const void *); +extern void dmac_clean_range(const void *, const void *); extern void dmac_flush_range(const void *, const void *); #endif @@ -489,4 +510,12 @@ int set_memory_nx(unsigned long addr, int numpages); void flush_uprobe_xol_access(struct page *page, unsigned long uaddr, void *kaddr, unsigned long len); +#ifdef CONFIG_FREE_PAGES_RDONLY +#define mark_addr_rdonly(a) set_memory_ro((unsigned long)a, 1); +#define mark_addr_rdwrite(a) set_memory_rw((unsigned long)a, 1); +#else +#define mark_addr_rdonly(a) +#define mark_addr_rdwrite(a) +#endif + #endif diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index 819777d0e91f..867fa5bbc64d 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -61,6 +61,7 @@ #define ARM_CPU_IMP_ARM 0x41 #define ARM_CPU_IMP_INTEL 0x69 +#define ARM_CPU_IMP_QUALCOMM 0x51 /* ARM implemented processors */ #define ARM_CPU_PART_ARM1136 0x4100b360 diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h index dc662fca9230..866f027e5e7c 100644 --- a/arch/arm/include/asm/device.h +++ b/arch/arm/include/asm/device.h @@ -25,6 +25,7 @@ struct pdev_archdata { #ifdef CONFIG_ARCH_OMAP struct omap_device *od; #endif + u64 dma_mask; }; #ifdef CONFIG_ARM_DMA_USE_IOMMU diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 85738b200023..b85ecbf3b719 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -189,6 +189,39 @@ extern int dma_supported(struct device *dev, u64 mask); extern int arm_dma_set_mask(struct device *dev, u64 dma_mask); +/* + * dma_coherent_pre_ops - barrier functions for coherent memory before DMA. + * A barrier is required to ensure memory operations are complete before the + * initiation of a DMA xfer. + * If the coherent memory is Strongly Ordered + * - pre ARMv7 and 8x50 guarantees ordering wrt other mem accesses + * - ARMv7 guarantees ordering only within a 1KB block, so we need a barrier + * If coherent memory is normal then we need a barrier to prevent + * reordering + */ +static inline void dma_coherent_pre_ops(void) +{ +#if COHERENT_IS_NORMAL == 1 + dmb(); +#else + barrier(); +#endif +} +/* + * dma_post_coherent_ops - barrier functions for coherent memory after DMA. + * If the coherent memory is Strongly Ordered we dont need a barrier since + * there are no speculative fetches to Strongly Ordered memory. + * If coherent memory is normal then we need a barrier to prevent reordering + */ +static inline void dma_coherent_post_ops(void) +{ +#if COHERENT_IS_NORMAL == 1 + dmb(); +#else + barrier(); +#endif +} + /** * arm_dma_alloc - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -264,6 +297,72 @@ static inline void dma_free_attrs(struct device *dev, size_t size, extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs); +#if 0 +static inline void *dma_alloc_writecombine(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs); +} + +static inline void dma_free_writecombine(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); +} +#endif +static inline void *dma_alloc_stronglyordered(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs); + return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs); +} + +static inline void dma_free_stronglyordered(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs); + return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); +} + +static inline int dma_mmap_stronglyordered(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs); + return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs); +} + +static inline void *dma_alloc_nonconsistent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); + return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs); +} + +static inline void dma_free_nonconsistent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); + return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); +} + +static inline int dma_mmap_nonconsistent(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); + return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs); +} /* * This can be called during early boot to increase the size of the atomic @@ -311,7 +410,55 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); +/** + * dma_cache_pre_ops - clean or invalidate cache before dma transfer is + * initiated and perform a barrier operation. + * @virtual_addr: A kernel logical or kernel virtual address + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Ensure that any data held in the cache is appropriately discarded + * or written back. + * + */ +static inline void dma_cache_pre_ops(void *virtual_addr, + size_t size, enum dma_data_direction dir) +{ + extern void ___dma_single_cpu_to_dev(const void *, size_t, + enum dma_data_direction); + + BUG_ON(!valid_dma_direction(dir)); + + ___dma_single_cpu_to_dev(virtual_addr, size, dir); +} +/** + * dma_cache_post_ops - clean or invalidate cache after dma transfer is + * initiated and perform a barrier operation. + * @virtual_addr: A kernel logical or kernel virtual address + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Ensure that any data held in the cache is appropriately discarded + * or written back. + * + */ +static inline void dma_cache_post_ops(void *virtual_addr, + size_t size, enum dma_data_direction dir) +{ + extern void ___dma_single_cpu_to_dev(const void *, size_t, + enum dma_data_direction); + + BUG_ON(!valid_dma_direction(dir)); + + if (arch_has_speculative_dfetch() && dir != DMA_TO_DEVICE) + /* + * Treat DMA_BIDIRECTIONAL and DMA_FROM_DEVICE + * identically: invalidate + */ + ___dma_single_cpu_to_dev(virtual_addr, + size, DMA_FROM_DEVICE); +} /* * The scatter list versions of the above methods. diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h index 6ddbe446425e..d5924f65637d 100644 --- a/arch/arm/include/asm/domain.h +++ b/arch/arm/include/asm/domain.h @@ -31,8 +31,13 @@ * * 36-bit addressing and supersections are only available on * CPUs based on ARMv6+ or the Intel XSC3 core. + * + * We cannot use domain 0 for the kernel on QSD8x50 since the kernel domain + * is set to manager mode when set_fs(KERNEL_DS) is called. Setting domain 0 + * to manager mode will disable the workaround for a cpu bug that can cause an + * invalid fault status and/or tlb corruption (CONFIG_VERIFY_PERMISSION_FAULT). */ -#ifndef CONFIG_IO_36 +#if !defined(CONFIG_IO_36) && !defined(CONFIG_VERIFY_PERMISSION_FAULT) #define DOMAIN_KERNEL 0 #define DOMAIN_TABLE 0 #define DOMAIN_USER 1 diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index a3c24cd5b7c8..2681262e5f9b 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -161,6 +161,8 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { } #define dmac_map_area __glue(_CACHE,_dma_map_area) #define dmac_unmap_area __glue(_CACHE,_dma_unmap_area) #define dmac_flush_range __glue(_CACHE,_dma_flush_range) +#define dmac_inv_range __glue(_CACHE,_dma_inv_range) +#define dmac_clean_range __glue(_CACHE,_dma_clean_range) #endif #endif diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 180567408ee8..2ea596dda249 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -100,6 +100,31 @@ static inline void __raw_writel(u32 val, volatile void __iomem *addr) : "r" (val)); } +static inline u64 __raw_readq(const volatile void __iomem *addr) +{ + register u64 val asm ("r2"); + + asm volatile("ldrd %1, %0" + : "+Qo" (*(volatile u64 __force *)addr), + "=r" (val)); + return val; +} +#define readq_relaxed(c) ({ u64 __r = le64_to_cpu((__force __le64) \ + __raw_readq(c)); __r; }) + +static inline void __raw_writeq(u64 val, volatile void __iomem *addr) + { + register u64 v asm ("r2"); + + v = val; + + asm volatile("strd %1, %0" + : "+Qo" (*(volatile u64 __force *)addr) + : "r" (v)); + } + + + static inline u8 __raw_readb(const volatile void __iomem *addr) { u8 val; diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 0406cb3f1af7..5b2619460fc1 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -54,6 +54,7 @@ struct machine_desc { void (*init_meminfo)(void); void (*reserve)(void);/* reserve mem blocks */ void (*map_io)(void);/* IO mapping function */ + void (*init_very_early)(void); void (*init_early)(void); void (*init_irq)(void); void (*init_time)(void); diff --git a/arch/arm/include/asm/mach/flash.h b/arch/arm/include/asm/mach/flash.h index 4ca69fe2c850..7ed96303419b 100644 --- a/arch/arm/include/asm/mach/flash.h +++ b/arch/arm/include/asm/mach/flash.h @@ -13,27 +13,36 @@ struct mtd_partition; struct mtd_info; +enum sw_version { + VERSION_1 = 0, + VERSION_2, +}; + /* * map_name: the map probe function name * name: flash device name (eg, as used with mtdparts=) * width: width of mapped device + * interleave: interleave mode feature support * init: method called at driver/device initialisation * exit: method called at driver/device removal * set_vpp: method called to enable or disable VPP * mmcontrol: method called to enable or disable Sync. Burst Read in OneNAND * parts: optional array of mtd_partitions for static partitioning * nr_parts: number of mtd_partitions for static partitoning + * version: software register interface version */ struct flash_platform_data { const char *map_name; const char *name; unsigned int width; + unsigned int interleave; int (*init)(void); void (*exit)(void); void (*set_vpp)(int on); void (*mmcontrol)(struct mtd_info *mtd, int sync_read); struct mtd_partition *parts; unsigned int nr_parts; + enum sw_version version; }; #endif diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index f98c7f32c9c8..7c079ca16c02 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -36,6 +36,7 @@ enum { MT_MEMORY_RWX_ITCM, MT_MEMORY_RW_SO, MT_MEMORY_DMA_READY, + MT_DEVICE_USER_ACCESSIBLE, }; #ifdef CONFIG_MMU @@ -57,6 +58,9 @@ extern const struct mem_type *get_mem_type(unsigned int type); */ extern int ioremap_page(unsigned long virt, unsigned long phys, const struct mem_type *mtype); + +extern int ioremap_pages(unsigned long virt, unsigned long phys, + unsigned long size, const struct mem_type *mtype); #else #define iotable_init(map,num) do { } while (0) #define vm_reserve_area_early(a,s,c) do { } while (0) diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index e731018869a7..6c8d731c2e5f 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -348,6 +348,12 @@ static inline __deprecated void *bus_to_virt(unsigned long x) #define virt_addr_valid(kaddr) (((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) \ && pfn_valid(virt_to_pfn(kaddr))) +/* + * Set if the architecture speculatively fetches data into cache. + */ +#ifndef arch_has_speculative_dfetch +#define arch_has_speculative_dfetch() 0 +#endif #endif #include <asm-generic/memory_model.h> diff --git a/arch/arm/include/asm/mmu_writeable.h b/arch/arm/include/asm/mmu_writeable.h new file mode 100644 index 000000000000..8c64b7fac60d --- /dev/null +++ b/arch/arm/include/asm/mmu_writeable.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011, 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. + * + */ +#ifndef _MMU_WRITEABLE_H +#define _MMU_WRITEABLE_H + +#ifdef CONFIG_STRICT_MEMORY_RWX +void mem_text_writeable_spinlock(unsigned long *flags); +void mem_text_address_writeable(unsigned long); +void mem_text_address_restore(void); +void mem_text_writeable_spinunlock(unsigned long *flags); +#else +static inline void mem_text_writeable_spinlock(unsigned long *flags) {}; +static inline void mem_text_address_writeable(unsigned long addr) {}; +static inline void mem_text_address_restore(void) {}; +static inline void mem_text_writeable_spinunlock(unsigned long *flags) {}; +#endif + +void mem_text_write_kernel_word(unsigned long *addr, unsigned long word); + +#endif diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 4355f0ec44d6..06fa6d07b599 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -160,6 +160,11 @@ typedef struct page *pgtable_t; extern int pfn_valid(unsigned long); #endif +#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE +extern int _early_pfn_valid(unsigned long); +#define early_pfn_valid(pfn) (_early_pfn_valid(pfn)) +#endif + #include <asm/memory.h> #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h index 9fd61c72a33a..96ddaebaad56 100644 --- a/arch/arm/include/asm/pgtable-3level-hwdef.h +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h @@ -52,6 +52,7 @@ #define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) #define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) #define PMD_SECT_AP1 (_AT(pmdval_t, 1) << 6) +#define PMD_SECT_AP2 (_AT(pmdval_t, 1) << 7) #define PMD_SECT_TEX(x) (_AT(pmdval_t, 0)) /* diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index a31ecdad4b59..a1977728cb1b 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -132,6 +132,8 @@ #define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */ +#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */ + /* * Hyp-mode PL2 PTE definitions for LPAE. */ diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 3b30062975b2..c0ee50d7f876 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -120,18 +120,32 @@ extern pgprot_t pgprot_s2_device; __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE) #define pgprot_stronglyordered(prot) \ - __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN) + +#define pgprot_device(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_NONSHARED) + +#define pgprot_writethroughcache(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITETHROUGH) + +#define pgprot_writebackcache(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITEBACK) + +#define pgprot_writebackwacache(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITEALLOC) #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE #define pgprot_dmacoherent(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN) #define __HAVE_PHYS_MEM_ACCESS_PROT +#define COHERENT_IS_NORMAL 1 struct file; extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot); #else #define pgprot_dmacoherent(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN) +#define COHERENT_IS_NORMAL 0 #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 8a1e8e995dae..b2c5d790840a 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -30,6 +30,9 @@ #define STACK_TOP_MAX TASK_SIZE #endif +extern unsigned int boot_reason; +extern unsigned int cold_boot; + struct debug_info { #ifdef CONFIG_HAVE_HW_BREAKPOINT struct perf_event *hbp[ARM_MAX_HBP_SLOTS]; diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index e0adb9f1bf94..5eb31adc2833 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -21,6 +21,37 @@ #define __tagtable(tag, fn) \ static const struct tagtable __tagtable_##fn __tag = { tag, fn } +/* + * Memory map description + */ +#if !defined(NR_BANKS) +#define NR_BANKS 16 +#endif + +struct membank { + phys_addr_t start; + phys_addr_t size; + unsigned int highmem; +}; + +struct meminfo { + int nr_banks; + struct membank bank[NR_BANKS]; +}; + +extern struct meminfo meminfo; + +#define for_each_bank(iter,mi) \ + for (iter = 0; iter < (mi)->nr_banks; iter++) + +#define bank_pfn_start(bank) __phys_to_pfn((bank)->start) +#define bank_pfn_end(bank) (__phys_to_pfn((bank)->start) + \ + __phys_to_pfn((bank)->size)) +#define bank_pfn_size(bank) ((bank)->size >> PAGE_SHIFT) +#define bank_phys_start(bank) (bank)->start +#define bank_phys_end(bank) ((bank)->start + (bank)->size) +#define bank_phys_size(bank) (bank)->size + extern int arm_add_memory(u64 start, u64 size); extern void early_print(const char *str, ...); extern void dump_machine_table(void); diff --git a/arch/arm/include/asm/smcmod.h b/arch/arm/include/asm/smcmod.h new file mode 100644 index 000000000000..6225c1e78421 --- /dev/null +++ b/arch/arm/include/asm/smcmod.h @@ -0,0 +1,165 @@ +/* Qualcomm SMC Module API */ + +#ifndef __SMCMOD_H_ +#define __SMCMOD_H_ + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define SMCMOD_DEV "smcmod" + +#define SMCMOD_REG_REQ_MAX_ARGS 2 + +/** + * struct smcmod_reg_req - for SMC register ioctl request + * + * @service_id - requested service. + * @command_id - requested command. + * @num_args - number of arguments. + * @args - argument(s) to be passed to the secure world. + * @return_val - return value from secure world operation. + */ +struct smcmod_reg_req { + uint32_t service_id; /* in */ + uint32_t command_id; /* in */ + uint8_t num_args; /* in */ + uint32_t args[SMCMOD_REG_REQ_MAX_ARGS]; /* in */ + uint32_t return_val; /* out */ +}; + +/** + * struct smcmod_buf_req - for SMC buffer ioctl request + * + * @service_id - requested service. + * @command_id - requested command. + * @ion_cmd_fd - fd obtained from ION_IOC_MAP or ION_IOC_SHARE. + * @cmd_len - length of command data buffer in bytes. + * @ion_resp_fd - fd obtained from ION_IOC_MAP or ION_IOC_SHARE. + * @resp_len - length of response data buffer in bytes. + * @return_val - return value from secure world operation. + */ +struct smcmod_buf_req { + uint32_t service_id;/* in */ + uint32_t command_id; /* in */ + int32_t ion_cmd_fd; /* in */ + uint32_t cmd_len; /* in */ + int32_t ion_resp_fd; /* in */ + uint32_t resp_len; /* in */ + uint32_t return_val; /* out */ +}; + +/** + * struct smcmod_cipher_req - for SMC cipher command ioctl + * + * @algorithm - specifies the cipher algorithm. + * @operation - specifies encryption or decryption. + * @mode - specifies cipher mode. + * @ion_key_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @key_size - key size in bytes. + * @ion_plain_text_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @plain_text_size - size of plain text in bytes. + * @ion_cipher_text_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @cipher_text_size - cipher text size in bytes. + * @ion_init_vector_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @init_vector_size - size of initialization vector in bytes. + * @key_is_null - indicates that the key is null. + * @return_val - return value from secure world opreation. + */ +struct smcmod_cipher_req { + uint32_t algorithm; /* in */ + uint32_t operation; /* in */ + uint32_t mode; /* in */ + int32_t ion_key_fd; /* in */ + uint32_t key_size; /* in */ + int32_t ion_plain_text_fd; /* in (encrypt)/out (decrypt) */ + uint32_t plain_text_size; /* in */ + int32_t ion_cipher_text_fd; /* out (encrypt)/in (decrypt) */ + uint32_t cipher_text_size; /* in */ + int32_t ion_init_vector_fd; /* in */ + uint32_t init_vector_size; /* in */ + uint32_t key_is_null; /* in */ + uint32_t return_val; /* out */ +}; + +/** + * struct smcmod_msg_digest_req - for message digest command ioctl + * + * @algorithm - specifies the cipher algorithm. + * @ion_key_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @key_size - hash key size in bytes. + * @ion_input_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @input_size - input data size in bytes. + * @ion_output_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE. + * @output_size - size of output buffer in bytes. + * @fixed_block - indicates whether this is a fixed block digest. + * @key_is_null - indicates that the key is null. + * @return_val - return value from secure world opreation. + */ +struct smcmod_msg_digest_req { + uint32_t algorithm; /* in */ + int32_t ion_key_fd; /* in */ + uint32_t key_size; /* in */ + int32_t ion_input_fd; /* in */ + uint32_t input_size; /* in */ + int32_t ion_output_fd; /* in/out */ + uint32_t output_size; /* in */ + uint32_t fixed_block; /* in */ + uint32_t key_is_null; /* in */ + uint32_t return_val; /* out */ +} __packed; + +/** + * struct smcmod_decrypt_req - used to decrypt image fragments. + * @service_id - requested service. + * @command_id - requested command. + * @operation - specifies metadata parsing or image fragment decrypting. + * @request - describes request parameters depending on operation. + * @response - this is the response of the request. + */ +struct smcmod_decrypt_req { + uint32_t service_id; + uint32_t command_id; +#define SMCMOD_DECRYPT_REQ_OP_METADATA 1 +#define SMCMOD_DECRYPT_REQ_OP_IMG_FRAG 2 + uint32_t operation; + union { + struct { + uint32_t len; + uint32_t ion_fd; + } metadata; + struct { + uint32_t ctx_id; + uint32_t last_frag; + uint32_t frag_len; + uint32_t ion_fd; + uint32_t offset; + } img_frag; + } request; + union { + struct { + uint32_t status; + uint32_t ctx_id; + uint32_t end_offset; + } metadata; + struct { + uint32_t status; + } img_frag; + } response; +}; + +#define SMCMOD_IOC_MAGIC 0x97 + +/* Number chosen to avoid any conflicts */ +#define SMCMOD_IOCTL_SEND_REG_CMD \ + _IOWR(SMCMOD_IOC_MAGIC, 32, struct smcmod_reg_req) +#define SMCMOD_IOCTL_SEND_BUF_CMD \ + _IOWR(SMCMOD_IOC_MAGIC, 33, struct smcmod_buf_req) +#define SMCMOD_IOCTL_SEND_CIPHER_CMD \ + _IOWR(SMCMOD_IOC_MAGIC, 34, struct smcmod_cipher_req) +#define SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD \ + _IOWR(SMCMOD_IOC_MAGIC, 35, struct smcmod_msg_digest_req) +#define SMCMOD_IOCTL_GET_VERSION _IOWR(SMCMOD_IOC_MAGIC, 36, uint32_t) +#define SMCMOD_IOCTL_SEND_DECRYPT_CMD \ + _IOWR(SMCMOD_IOC_MAGIC, 37, struct smcmod_decrypt_req) + +#endif /* __SMCMOD_H_ */ diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 18f5a554134f..d9e2bacde208 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -80,6 +80,7 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask); extern int register_ipi_completion(struct completion *completion, int cpu); +extern void smp_send_all_cpu_backtrace(void); struct smp_operations { #ifdef CONFIG_SMP diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h index ac4bfae26702..6a0826328286 100644 --- a/arch/arm/include/asm/spinlock.h +++ b/arch/arm/include/asm/spinlock.h @@ -7,21 +7,17 @@ #include <linux/prefetch.h> +extern int msm_krait_need_wfe_fixup; + /* * sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K * extensions, so when running on UP, we have to patch these instructions away. */ #ifdef CONFIG_THUMB2_KERNEL /* - * For Thumb-2, special care is needed to ensure that the conditional WFE - * instruction really does assemble to exactly 4 bytes (as required by - * the SMP_ON_UP fixup code). By itself "wfene" might cause the - * assembler to insert a extra (16-bit) IT instruction, depending on the - * presence or absence of neighbouring conditional instructions. - * - * To avoid this unpredictableness, an approprite IT is inserted explicitly: - * the assembler won't change IT instructions which are explicitly present - * in the input. + * Both instructions given to the ALT_SMP macro need to be the same size, to + * allow the SMP_ON_UP fixups to function correctly. Hence the explicit encoding + * specifications. */ #define WFE(cond) __ALT_SMP_ASM( \ "it " cond "\n\t" \ @@ -33,6 +29,33 @@ #define WFE(cond) __ALT_SMP_ASM("wfe" cond, "nop") #endif +/* + * The fixup involves disabling FIQs during execution of the WFE instruction. + * This could potentially lead to deadlock if a thread is trying to acquire a + * spinlock which is being released from an FIQ. This should not be a problem + * because FIQs are handled by the secure environment and do not directly + * manipulate spinlocks. + */ +#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP +#define WFE_SAFE(fixup, tmp) \ +" mrs " tmp ", cpsr\n" \ +" cmp " fixup ", #0\n" \ +" wfeeq\n" \ +" beq 10f\n" \ +" cpsid f\n" \ +" mrc p15, 7, " fixup ", c15, c0, 5\n" \ +" bic " fixup ", " fixup ", #0x10000\n" \ +" mcr p15, 7, " fixup ", c15, c0, 5\n" \ +" isb\n" \ +" wfe\n" \ +" orr " fixup ", " fixup ", #0x10000\n" \ +" mcr p15, 7, " fixup ", c15, c0, 5\n" \ +" isb\n" \ +"10: msr cpsr_cf, " tmp "\n" +#else +#define WFE_SAFE(fixup, tmp) " wfe\n" +#endif + #define SEV __ALT_SMP_ASM(WASM(sev), WASM(nop)) static inline void dsb_sev(void) @@ -57,7 +80,7 @@ static inline void dsb_sev(void) static inline void arch_spin_lock(arch_spinlock_t *lock) { - unsigned long tmp; + unsigned long tmp, flags = 0; u32 newval; arch_spinlock_t lockval; @@ -73,7 +96,33 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) : "cc"); while (lockval.tickets.next != lockval.tickets.owner) { + if (msm_krait_need_wfe_fixup) { + local_save_flags(flags); + local_fiq_disable(); + __asm__ __volatile__( + "mrc p15, 7, %0, c15, c0, 5\n" + : "=r" (tmp) + : + : "cc"); + tmp &= ~(0x10000); + __asm__ __volatile__( + "mcr p15, 7, %0, c15, c0, 5\n" + : + : "r" (tmp) + : "cc"); + isb(); + } wfe(); + if (msm_krait_need_wfe_fixup) { + tmp |= 0x10000; + __asm__ __volatile__( + "mcr p15, 7, %0, c15, c0, 5\n" + : + : "r" (tmp) + : "cc"); + isb(); + local_irq_restore(flags); + } lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner); } @@ -140,17 +189,19 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock) static inline void arch_write_lock(arch_rwlock_t *rw) { - unsigned long tmp; + unsigned long tmp, fixup = msm_krait_need_wfe_fixup; prefetchw(&rw->lock); __asm__ __volatile__( -"1: ldrex %0, [%1]\n" +"1: ldrex %0, [%2]\n" " teq %0, #0\n" - WFE("ne") -" strexeq %0, %2, [%1]\n" +" beq 2f\n" + WFE_SAFE("%1", "%0") +"2:\n" +" strexeq %0, %3, [%2]\n" " teq %0, #0\n" " bne 1b" - : "=&r" (tmp) + : "=&r" (tmp), "+r" (fixup) : "r" (&rw->lock), "r" (0x80000000) : "cc"); @@ -211,17 +262,19 @@ static inline void arch_write_unlock(arch_rwlock_t *rw) */ static inline void arch_read_lock(arch_rwlock_t *rw) { - unsigned long tmp, tmp2; + unsigned long tmp, tmp2, fixup = msm_krait_need_wfe_fixup; prefetchw(&rw->lock); __asm__ __volatile__( -"1: ldrex %0, [%2]\n" +"1: ldrex %0, [%3]\n" " adds %0, %0, #1\n" -" strexpl %1, %0, [%2]\n" - WFE("mi") +" strexpl %1, %0, [%3]\n" +" bpl 2f\n" + WFE_SAFE("%2", "%0") +"2:\n" " rsbpls %0, %1, #0\n" " bmi 1b" - : "=&r" (tmp), "=&r" (tmp2) + : "=&r" (tmp), "=&r" (tmp2), "+r" (fixup) : "r" (&rw->lock) : "cc"); diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h index a3d61ad984af..062c48452148 100644 --- a/arch/arm/include/asm/system_misc.h +++ b/arch/arm/include/asm/system_misc.h @@ -21,6 +21,7 @@ extern void (*arm_pm_idle)(void); #define UDBG_BUS (1 << 4) extern unsigned int user_debug; +extern char* (*arch_read_hardware_id)(void); #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index def9e570199f..7c51bf6a2cba 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -519,7 +519,11 @@ static inline void __flush_tlb_kernel_page(unsigned long kaddr) dsb(ishst); __local_flush_tlb_kernel_page(kaddr); +#ifdef CONFIG_ARCH_MSM8X60 + tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", kaddr); +#else tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr); +#endif if (tlb_flag(TLB_BARRIER)) { dsb(ish); diff --git a/arch/arm/include/uapi/asm/posix_types.h b/arch/arm/include/uapi/asm/posix_types.h index d2de9cbbcd9b..1db85c99abdd 100644 --- a/arch/arm/include/uapi/asm/posix_types.h +++ b/arch/arm/include/uapi/asm/posix_types.h @@ -22,6 +22,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 38ddd9f83d0e..3e55f2ca818d 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -15,7 +15,7 @@ CFLAGS_REMOVE_return_address.o = -pg # Object file lists. -obj-y := elf.o entry-common.o irq.o opcodes.o \ +obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ process.o ptrace.o return_address.o \ setup.o signal.o sigreturn_codes.o \ stacktrace.o sys_arm.o time.o traps.o diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 11c54de9f8cf..1e93787a4b43 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -27,6 +27,22 @@ #include <asm/mach/arch.h> #include <asm/mach-types.h> +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ +#ifndef CONFIG_ARM_LPAE + if (base > ((phys_addr_t)~0)) { + pr_crit("Ignoring memory at 0x%08llx due to lack of LPAE support\n", + base); + return; + } + + if (size > ((phys_addr_t)~0)) + size = ((phys_addr_t)~0); + + /* arm_add_memory() already checks for the case of base + size > 4GB */ +#endif + arm_add_memory(base, size); +} #ifdef CONFIG_SMP extern struct of_cpu_method __cpu_method_of_table[]; @@ -169,10 +185,14 @@ void __init arm_dt_init_cpu_maps(void) * a reg property, the DT CPU list can be considered valid and the * logical map created in smp_setup_processor_id() can be overridden */ - for (i = 0; i < cpuidx; i++) { - set_cpu_possible(i, true); - cpu_logical_map(i) = tmp_map[i]; - pr_debug("cpu logical map 0x%x\n", cpu_logical_map(i)); + for (i = 0; i < nr_cpu_ids; i++) { + if (i < cpuidx) { + set_cpu_possible(i, true); + cpu_logical_map(i) = tmp_map[i]; + pr_debug("cpu logical map 0x%x\n", cpu_logical_map(i)); + } else { + set_cpu_possible(i, false); + } } } diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2f5555d307b3..1135c24babac 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -832,6 +832,97 @@ ENDPROC(__switch_to) .align 5 .globl __kuser_helper_start __kuser_helper_start: +#ifdef GENERIC_TIME_VSYSCALL +/* + * Reference declaration: + * + * extern struct timezone __kernel_helper_gtod_timezone + * extern unsigned int __kernel_helper_gtod_seqnum + * + * Definition and user space usage example: + * + * #define __kernel_helper_gtod_timezone (*(unsigned int*)0xffff0f20) + * #define __kernel_helper_gtod_seqnum (*(unsigned int*)0xffff0f28) + * + * unsigned int prelock, postlock ; + * do { + * prelock = __kernel_helper_gtod_seqnum; + * memcpy(&tz, (void*)&(__kernel_helper_gtod_timezone), + * sizeof(struct timezone)) ; + * postlock = __kernel_helper_gtod_seqnum; + * } while (prelock != postlock); + * + * 0xffff0f20-3: tz_minuteswest + * 0xffff0f24-7: tz_dsttime + * 0xffff0f28-b: sequence #. + * 0xffff0f30-3: offset into CONFIG_USER_ACCESSIBLE_TIMER_BASE to get the timer. + * 0xffff0f34-7: Feature flag + * 0xffff0f38-b: wall-to-mononic: tv_sec + * 0xffff0f3c-f: wall-to-mononic: tv_nsec + */ + .globl __kuser_gtod_timezone +__kuser_gtod_timezone: @0xffff0f20 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + /* This offset is where the flag to enable the + * user accessible timers is located. + */ + .word 0 + .word 0 + .word 0 + .align 5 + +/* + * Reference declaration: + * + * extern struct timeval __kernel_helper_gtod_timeval + * extern unsigned int __kernel_helper_gtod_seqnum + * + * Definition and user space usage example: + * + * #define __kernel_helper_gtod_timeval (*(unsigned int*)0xffff0f40) + * #define __kernel_helper_gtod_seqnum (*(unsigned int*)0xffff0f48) + * + * unsigned int prelock, postlock ; + * struct gtod { + * uint64_t cycle_last; + * uint64_t mask; + * uint32_t mult; + * uint32_t shift; + * uint32_t tv_sec; + * uint32_t tv_nsec; + * }; + * struct gtod gdtod; + * + * do { + * prelock = __kernel_helper_gtod_seqnum; + * memcpy(&gdtod, (void*)&(__kernel_helper_gtod_timeval), + * sizeof(struct gtod)) ; + * postlock = __kernel_helper_gtod_seqnum; + * } while (prelock != postlock); + * + * 0xffff0f40-7: cycle_last + * 0xffff0f48-f: mask + * 0xffff0f50-3: mult + * 0xffff0f54-7: shift + * 0xffff0f58-b: tv_sec + * 0xffff0f5c-f: tv_nsec + */ + .globl __kuser_gtod_timeval +__kuser_gtod_timeval: @0xffff0f40 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .align 5 +#endif /* * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular @@ -1032,7 +1123,7 @@ __kuser_helper_end: * SP points to a minimal amount of processor-private memory, the address * of which is copied into r0 for the mode specific abort handler. */ - .macro vector_stub, name, mode, correction=0 + .macro vector_stub, name, mode, fixup, correction=0 .align 5 vector_\name: @@ -1061,6 +1152,18 @@ vector_\name: and lr, lr, #0x0f THUMB( adr r0, 1f ) THUMB( ldr lr, [r0, lr, lsl #2] ) + .if \fixup +#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP + ldr r0, .krait_fixup + ldr r0, [r0] + cmp r0, #0 + beq 10f + mrc p15, 7, r0, c15, c0, 5 + orr r0, r0, #0x10000 + mcr p15, 7, r0, c15, c0, 5 +10: isb +#endif + .endif mov r0, sp ARM( ldr lr, [pc, lr, lsl #2] ) movs pc, lr @ branch to handler in SVC mode @@ -1085,7 +1188,7 @@ vector_rst: /* * Interrupt dispatcher */ - vector_stub irq, IRQ_MODE, 4 + vector_stub irq, IRQ_MODE, 1, 4 .long __irq_usr @ 0 (USR_26 / USR_32) .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) @@ -1108,7 +1211,7 @@ vector_rst: * Data abort dispatcher * Enter in ABT mode, spsr = USR CPSR, lr = USR PC */ - vector_stub dabt, ABT_MODE, 8 + vector_stub dabt, ABT_MODE, 0, 8 .long __dabt_usr @ 0 (USR_26 / USR_32) .long __dabt_invalid @ 1 (FIQ_26 / FIQ_32) @@ -1131,7 +1234,7 @@ vector_rst: * Prefetch abort dispatcher * Enter in ABT mode, spsr = USR CPSR, lr = USR PC */ - vector_stub pabt, ABT_MODE, 4 + vector_stub pabt, ABT_MODE, 0, 4 .long __pabt_usr @ 0 (USR_26 / USR_32) .long __pabt_invalid @ 1 (FIQ_26 / FIQ_32) @@ -1154,7 +1257,7 @@ vector_rst: * Undef instr entry dispatcher * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC */ - vector_stub und, UND_MODE + vector_stub und, UND_MODE, 0 .long __und_usr @ 0 (USR_26 / USR_32) .long __und_invalid @ 1 (FIQ_26 / FIQ_32) @@ -1210,6 +1313,9 @@ vector_addrexcptn: .long __fiq_svc @ e .long __fiq_svc @ f +.krait_fixup: + .word msm_krait_need_wfe_fixup + .globl vector_fiq_offset .equ vector_fiq_offset, vector_fiq diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index b37752a96652..00b0d8e8949b 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -39,6 +39,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/seq_file.h> #include <asm/cacheflush.h> @@ -147,6 +148,11 @@ void disable_fiq(int fiq) disable_irq(fiq + fiq_start); } +void fiq_set_type(int fiq, unsigned int type) +{ + irq_set_irq_type(fiq + FIQ_START, type); +} + EXPORT_SYMBOL(set_fiq_handler); EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */ @@ -154,6 +160,7 @@ EXPORT_SYMBOL(claim_fiq); EXPORT_SYMBOL(release_fiq); EXPORT_SYMBOL(enable_fiq); EXPORT_SYMBOL(disable_fiq); +EXPORT_SYMBOL(fiq_set_type); void __init init_FIQ(int start) { diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 664eee8c4a26..1a9d952636ee 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -467,6 +467,17 @@ ENTRY(__turn_mmu_on) mrc p15, 0, r3, c0, c0, 0 @ read id reg instr_sync mov r3, r3 +#ifdef CONFIG_ARCH_MSM_KRAIT + movw r3, 0xff0d + movt r3, 0xffff + and r3, r9, r3 + movw r4, 0x0400 + movt r4, 0x511f + cmp r3, r4 + mrceq p15, 7, r3, c15, c0, 2 + biceq r3, r3, #0x400 + mcreq p15, 7, r3, c15, c0, 2 +#endif mov r3, r13 ret r3 __turn_mmu_on_end: diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index b5b452f90f76..6b35b54363e9 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -227,6 +227,17 @@ static int get_num_brps(void) return core_has_mismatch_brps() ? brps - 1 : brps; } +/* Determine if halting mode is enabled */ +static int halting_mode_enabled(void) +{ + u32 dscr; + ARM_DBG_READ(c0, c1, 0, dscr); + WARN_ONCE(dscr & ARM_DSCR_HDBGEN, + "halting debug mode enabled. " + "Unable to access hardware resources.\n"); + return !!(dscr & ARM_DSCR_HDBGEN); +} + /* * In order to access the breakpoint/watchpoint control registers, * we must be running in debug monitor mode. Unfortunately, we can @@ -932,6 +943,17 @@ static void reset_ctrl_regs(void *unused) u32 val; /* + * Bail out without clearing the breakpoint registers if halting + * debug mode or monitor debug mode is enabled. Checking for monitor + * debug mode here ensures we don't clear the breakpoint registers + * across power collapse if save and restore code has already + * preserved the debug register values or they weren't lost and + * monitor mode was already enabled earlier. + */ + if (halting_mode_enabled() || monitor_mode_enabled()) + return; + + /* * v7 debug contains save and restore registers so that debug state * can be maintained across low-power modes without leaving the debug * logic powered up. It is IMPLEMENTATION DEFINED whether we can access diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c index 07314af47733..7a27c47dad5b 100644 --- a/arch/arm/kernel/patch.c +++ b/arch/arm/kernel/patch.c @@ -5,6 +5,7 @@ #include <asm/cacheflush.h> #include <asm/smp_plat.h> #include <asm/opcodes.h> +#include <asm/mmu_writeable.h> #include "patch.h" @@ -17,6 +18,10 @@ void __kprobes __patch_text(void *addr, unsigned int insn) { bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL); int size; + unsigned long flags; + + mem_text_writeable_spinlock(&flags); + mem_text_address_writeable((unsigned long)addr); if (thumb2 && __opcode_is_thumb16(insn)) { *(u16 *)addr = __opcode_to_mem_thumb16(insn); @@ -42,6 +47,9 @@ void __kprobes __patch_text(void *addr, unsigned int insn) flush_icache_range((uintptr_t)(addr), (uintptr_t)(addr) + size); + + mem_text_address_restore(); + mem_text_writeable_spinunlock(&flags); } static int __kprobes patch_text_stop_machine(void *data) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index c03106378b49..9ff5825b4e03 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -30,6 +30,7 @@ #include <linux/bug.h> #include <linux/compiler.h> #include <linux/sort.h> +#include <linux/dma-mapping.h> #include <asm/unified.h> #include <asm/cp15.h> @@ -77,7 +78,7 @@ extern void paging_init(const struct machine_desc *desc); extern void early_paging_init(const struct machine_desc *, struct proc_info_list *); extern void sanity_check_meminfo(void); -extern enum reboot_mode reboot_mode; +//extern enum reboot_mode reboot_mode; extern void setup_dma_zone(const struct machine_desc *desc); unsigned int processor_id; @@ -104,6 +105,14 @@ EXPORT_SYMBOL(elf_hwcap); unsigned int elf_hwcap2 __read_mostly; EXPORT_SYMBOL(elf_hwcap2); +unsigned int boot_reason; +EXPORT_SYMBOL(boot_reason); + +unsigned int cold_boot; +EXPORT_SYMBOL(cold_boot); + +char* (*arch_read_hardware_id)(void); +EXPORT_SYMBOL(arch_read_hardware_id); #ifdef MULTI_CPU struct processor processor __read_mostly; @@ -890,6 +899,15 @@ void __init hyp_mode_check(void) #endif } +#if 0 +static int __init meminfo_cmp(const void *_a, const void *_b) +{ + const struct membank *a = _a, *b = _b; + long cmp = bank_pfn_start(a) - bank_pfn_start(b); + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} +#endif + void __init setup_arch(char **cmdline_p) { const struct machine_desc *mdesc; @@ -901,8 +919,9 @@ void __init setup_arch(char **cmdline_p) machine_desc = mdesc; machine_name = mdesc->name; - if (mdesc->reboot_mode != REBOOT_HARD) - reboot_mode = mdesc->reboot_mode; +// if (mdesc->reboot_mode != REBOOT_HARD) +// reboot_mode = mdesc->reboot_mode; + setup_dma_zone(mdesc); init_mm.start_code = (unsigned long) _text; init_mm.end_code = (unsigned long) _etext; @@ -917,6 +936,10 @@ void __init setup_arch(char **cmdline_p) early_paging_init(mdesc, lookup_processor_type(read_cpuid_id())); setup_dma_zone(mdesc); + if (mdesc->init_very_early) + mdesc->init_very_early(); + +// sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); sanity_check_meminfo(); arm_memblock_init(mdesc); @@ -942,6 +965,7 @@ void __init setup_arch(char **cmdline_p) smp_build_mpidr_hash(); } #endif + arm_dt_init_cpu_maps(); if (!is_smp()) hyp_mode_check(); @@ -1032,7 +1056,7 @@ static int c_show(struct seq_file *m, void *v) int i, j; u32 cpuid; - for_each_online_cpu(i) { + for_each_present_cpu(i) { /* * glibc reads /proc/cpuinfo to determine the number of * online processors, looking for lines beginning with @@ -1077,10 +1101,15 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "CPU revision\t: %d\n\n", cpuid & 15); } - seq_printf(m, "Hardware\t: %s\n", machine_name); + if (!arch_read_hardware_id) + seq_printf(m, "Hardware\t: %s\n", machine_name); + else + seq_printf(m, "Hardware\t: %s\n", arch_read_hardware_id()); seq_printf(m, "Revision\t: %04x\n", system_rev); seq_printf(m, "Serial\t\t: %08x%08x\n", system_serial_high, system_serial_low); + seq_printf(m, "Processor\t: %s rev %d (%s)\n", + cpu_name, read_cpuid_id() & 15, elf_platform); return 0; } @@ -1106,3 +1135,9 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = c_show }; + +void arch_setup_pdev_archdata(struct platform_device *pdev) +{ + pdev->archdata.dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->archdata.dma_mask; +} diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 13396d3d600e..45f39d0a859f 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -26,6 +26,7 @@ #include <linux/completion.h> #include <linux/cpufreq.h> #include <linux/irq_work.h> +#include <linux/smp.h> #include <linux/atomic.h> #include <asm/smp.h> diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 8e95aa47457a..2d2c9ad182c9 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -8,7 +8,10 @@ #include <asm/thread_info.h> #include <asm/memory.h> #include <asm/page.h> - +#ifdef CONFIG_STRICT_MEMORY_RWX +#include <asm/pgtable.h> +#endif + #define PROC_INFO \ . = ALIGN(4); \ VMLINUX_SYMBOL(__proc_info_begin) = .; \ @@ -90,6 +93,10 @@ SECTIONS _text = .; HEAD_TEXT } +#ifdef CONFIG_STRICT_MEMORY_RWX + . = ALIGN(1<<SECTION_SHIFT); +#endif + .text : { /* Real text segment */ _stext = .; /* Text and read-only data */ __exception_text_start = .; @@ -112,6 +119,9 @@ SECTIONS ARM_CPU_KEEP(PROC_INFO) } +#ifdef CONFIG_STRICT_MEMORY_RWX + . = ALIGN(1<<SECTION_SHIFT); +#endif RO_DATA(PAGE_SIZE) . = ALIGN(4); @@ -145,7 +155,11 @@ SECTIONS _etext = .; /* End of text and rodata section */ #ifndef CONFIG_XIP_KERNEL +#ifdef CONFIG_STRICT_MEMORY_RWX + . = ALIGN(1<<SECTION_SHIFT); +#else . = ALIGN(PAGE_SIZE); +#endif __init_begin = .; #endif /* @@ -173,6 +187,9 @@ SECTIONS .init.proc.info : { ARM_CPU_DISCARD(PROC_INFO) } +#ifdef CONFIG_STRICT_MEMORY_RWX + . = ALIGN(1<<SECTION_SHIFT); +#endif .init.arch.info : { __arch_info_begin = .; *(.arch.info.init) @@ -202,6 +219,7 @@ SECTIONS INIT_SETUP(16) INIT_CALLS CON_INITCALL + COMPAT_EXPORTS SECURITY_INITCALL INIT_RAM_FS } diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index 9b803a578b4d..dc20ebe76f63 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -1,3 +1,29 @@ - zreladdr-y += 0x10008000 -params_phys-y := 0x10000100 -initrd_phys-y := 0x10800000 +# MSM8974 + zreladdr-$(CONFIG_ARCH_MSM8974) := 0x00008000 + +# APQ8084 + zreladdr-$(CONFIG_ARCH_APQ8084) := 0x00008000 + +# MDM9630 + zreladdr-$(CONFIG_ARCH_MDM9630) := 0x00008000 + +# MSMZIRC + zreladdr-$(CONFIG_ARCH_MSMZIRC) := 0x80008000 + +# MSM8226 + zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000 + +# FSM9900 + zreladdr-$(CONFIG_ARCH_FSM9900) := 0x11408000 + +# MPQ8092 + zreladdr-$(CONFIG_ARCH_MPQ8092) := 0x00008000 + +# MSM8916 + zreladdr-$(CONFIG_ARCH_MSM8916) := 0x80008000 + +# MSM8610 + zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000 + +# MSMSAMARIUM + zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000 diff --git a/arch/arm/mach-msm/board-8916.c b/arch/arm/mach-msm/board-8916.c new file mode 100644 index 000000000000..65d6753d00d7 --- /dev/null +++ b/arch/arm/mach-msm/board-8916.c @@ -0,0 +1,128 @@ +/* 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 <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/of_fdt.h> +#include <linux/of_irq.h> +#include <asm/mach/arch.h> +#include <soc/qcom/socinfo.h> +#include <mach/board.h> +#include <mach/msm_memtypes.h> +// AGSTUB +//#include <soc/qcom/rpm-smd.h> +//#include <soc/qcom/smd.h> +#include <soc/qcom/smem.h> +// AGSTUB +//#include <soc/qcom/spm.h> +#include <soc/qcom/pm.h> +#include "board-dt.h" +#include "platsmp.h" + +static void __init msm8916_early_memory(void) +{ + of_scan_flat_dt(dt_scan_for_memory_hole, NULL); +} + +static void __init msm8916_dt_reserve(void) +{ + of_scan_flat_dt(dt_scan_for_memory_reserve, NULL); +} + +static void __init msm8916_map_io(void) +{ + msm_map_msm8916_io(); +} + +static struct of_dev_auxdata msm8916_auxdata_lookup[] __initdata = { + {} +}; + +/* + * Used to satisfy dependencies for devices that need to be + * run early or in a particular order. Most likely your device doesn't fall + * into this category, and thus the driver should not be added here. The + * EPROBE_DEFER can satisfy most dependency problems. + */ +void __init msm8916_add_drivers(void) +{ +// msm_smd_init(); +// AGSTUB +// msm_rpm_driver_init(); +// msm_spm_device_init(); + msm_pm_sleep_status_init(); +} + +static void __init msm8916_init(void) +{ + struct of_dev_auxdata *adata = msm8916_auxdata_lookup; + + /* + * populate devices from DT first so smem probe will get called as part + * of msm_smem_init. socinfo_init needs smem support so call + * msm_smem_init before it. + */ + of_platform_populate(NULL, of_default_bus_match_table, adata, NULL); + msm_smem_init(); + + if (socinfo_init() < 0) + pr_err("%s: socinfo_init() failed\n", __func__); + + msm8916_add_drivers(); +} + +static const char *msm8916_dt_match[] __initconst = { + "qcom,msm8916", + "qcom,apq8016", + NULL +}; + +static const char *msm8936_dt_match[] __initconst = { + "qcom,msm8936", + NULL +}; + +static const char *msm8939_dt_match[] __initconst = { + "qcom,msm8939", + NULL +}; + +DT_MACHINE_START(MSM8916_DT, + "Qualcomm Technologies, Inc. MSM 8916 (Flattened Device Tree)") + .map_io = msm8916_map_io, + .init_machine = msm8916_init, + .dt_compat = msm8916_dt_match, + .reserve = msm8916_dt_reserve, + .init_very_early = msm8916_early_memory, + .smp = &msm8916_smp_ops, +MACHINE_END + +DT_MACHINE_START(MSM8939_DT, + "Qualcomm Technologies, Inc. MSM 8939 (Flattened Device Tree)") + .map_io = msm8916_map_io, + .init_machine = msm8916_init, + .dt_compat = msm8939_dt_match, + .reserve = msm8916_dt_reserve, + .smp = &msm8936_smp_ops, +MACHINE_END + +DT_MACHINE_START(MSM8936_DT, + "Qualcomm Technologies, Inc. MSM 8936 (Flattened Device Tree)") + .map_io = msm8916_map_io, + .init_machine = msm8916_init, + .dt_compat = msm8936_dt_match, + .reserve = msm8916_dt_reserve, + .init_very_early = msm8916_early_memory, + .smp = &msm8936_smp_ops, +MACHINE_END diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c new file mode 100644 index 000000000000..4016c4dac4c5 --- /dev/null +++ b/arch/arm/mach-msm/board-dt.c @@ -0,0 +1,31 @@ +/* Copyright (c) 2011-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 <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <soc/qcom/scm.h> +#include <asm/mach/map.h> +#include <mach/msm_iomap.h> + +#include "board-dt.h" + +void __init board_dt_populate(struct of_dev_auxdata *adata) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + /* Explicitly parent the /soc devices to the root node to preserve + * the kernel ABI (sysfs structure, etc) until userspace is updated + */ + of_platform_populate(of_find_node_by_path("/soc"), + of_default_bus_match_table, adata, NULL); +} diff --git a/arch/arm/mach-msm/board-dt.h b/arch/arm/mach-msm/board-dt.h new file mode 100644 index 000000000000..33448947015a --- /dev/null +++ b/arch/arm/mach-msm/board-dt.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2012-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 <linux/of_platform.h> + +void __init board_dt_populate(struct of_dev_auxdata *adata); diff --git a/arch/arm/mach-msm/boot_stats.c b/arch/arm/mach-msm/boot_stats.c new file mode 100644 index 000000000000..4ebf722fd4b6 --- /dev/null +++ b/arch/arm/mach-msm/boot_stats.c @@ -0,0 +1,108 @@ +/* Copyright (c) 2013, 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 <linux/kernel.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/smp.h> +#include <linux/clk.h> +#include <linux/cpu.h> +#include <linux/sched.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <mach/msm_iomap.h> + +struct boot_stats { + uint32_t bootloader_start; + uint32_t bootloader_end; + uint32_t bootloader_display; + uint32_t bootloader_load_kernel; +}; + +static void __iomem *mpm_counter_base; +static uint32_t mpm_counter_freq; +static struct boot_stats __iomem *boot_stats; + +static int mpm_parse_dt(void) +{ + struct device_node *np; + u32 freq; + + np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-boot_stats"); + if (!np) { + pr_err("can't find qcom,msm-imem node\n"); + return -ENODEV; + } + boot_stats = of_iomap(np, 0); + if (!boot_stats) { + pr_err("boot_stats: Can't map imem\n"); + return -ENODEV; + } + + np = of_find_compatible_node(NULL, NULL, "qcom,mpm2-sleep-counter"); + if (!np) { + pr_err("mpm_counter: can't find DT node\n"); + return -ENODEV; + } + + if (!of_property_read_u32(np, "clock-frequency", &freq)) + mpm_counter_freq = freq; + else + return -ENODEV; + + if (of_get_address(np, 0, NULL, NULL)) { + mpm_counter_base = of_iomap(np, 0); + if (!mpm_counter_base) { + pr_err("mpm_counter: cant map counter base\n"); + return -ENODEV; + } + } + + return 0; +} + +static void print_boot_stats(void) +{ + pr_info("KPI: Bootloader start count = %u\n", + readl_relaxed(&boot_stats->bootloader_start)); + pr_info("KPI: Bootloader end count = %u\n", + readl_relaxed(&boot_stats->bootloader_end)); + pr_info("KPI: Bootloader display count = %u\n", + readl_relaxed(&boot_stats->bootloader_display)); + pr_info("KPI: Bootloader load kernel count = %u\n", + readl_relaxed(&boot_stats->bootloader_load_kernel)); + pr_info("KPI: Kernel MPM timestamp = %u\n", + readl_relaxed(mpm_counter_base)); + pr_info("KPI: Kernel MPM Clock frequency = %u\n", + mpm_counter_freq); +} + +int boot_stats_init(void) +{ + int ret; + + ret = mpm_parse_dt(); + if (ret < 0) + return -ENODEV; + + print_boot_stats(); + + iounmap(boot_stats); + iounmap(mpm_counter_base); + + return 0; +} + diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c new file mode 100644 index 000000000000..33c51446802f --- /dev/null +++ b/arch/arm/mach-msm/cache_erp.c @@ -0,0 +1,670 @@ +/* Copyright (c) 2012-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 <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/proc_fs.h> +#include <linux/cpu.h> +#include <linux/seq_file.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <mach/msm-krait-l2-accessors.h> +#include <mach/msm_iomap.h> +#include <soc/qcom/socinfo.h> +#include <asm/cputype.h> + +#define CESR_DCTPE BIT(0) +#define CESR_DCDPE BIT(1) +#define CESR_ICTPE BIT(2) +#define CESR_ICDPE BIT(3) +#define CESR_DCTE (BIT(4) | BIT(5)) +#define CESR_ICTE (BIT(6) | BIT(7)) +#define CESR_TLBMH BIT(16) +#define CESR_I_MASK 0x000000CC + +#define CESR_VALID_MASK 0x000100FF + +/* Print a message for everything but TLB MH events */ +#define CESR_PRINT_MASK 0x000000FF + +/* Log everything but TLB MH events */ +#define CESR_LOG_EVENT_MASK 0x000000FF + +#define L2ESR_IND_ADDR 0x204 +#define L2ESYNR0_IND_ADDR 0x208 +#define L2ESYNR1_IND_ADDR 0x209 +#define L2EAR0_IND_ADDR 0x20C +#define L2EAR1_IND_ADDR 0x20D + +#define L2ESR_MPDCD BIT(0) +#define L2ESR_MPSLV BIT(1) +#define L2ESR_TSESB BIT(2) +#define L2ESR_TSEDB BIT(3) +#define L2ESR_DSESB BIT(4) +#define L2ESR_DSEDB BIT(5) +#define L2ESR_MSE BIT(6) +#define L2ESR_MPLDREXNOK BIT(8) + +#define L2ESR_ACCESS_ERR_MASK 0xFFFC + +#define L2ESR_CPU_MASK 0x0F +#define L2ESR_CPU_SHIFT 16 + +#ifdef CONFIG_MSM_L1_ERR_PANIC +#define ERP_L1_ERR(a) panic(a) +#else +#define ERP_L1_ERR(a) do { } while (0) +#endif + +#ifdef CONFIG_MSM_L1_RECOV_ERR_PANIC +#define ERP_L1_RECOV_ERR(a) panic(a) +#else +#define ERP_L1_RECOV_ERR(a) do { } while (0) +#endif + +#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC +#define ERP_PORT_ERR(a) panic(a) +#else +#define ERP_PORT_ERR(a) WARN(1, a) +#endif + +#ifdef CONFIG_MSM_L2_ERP_1BIT_PANIC +#define ERP_1BIT_ERR(a) panic(a) +#else +#define ERP_1BIT_ERR(a) do { } while (0) +#endif + +#ifdef CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS +#define print_access_errors() 1 +#else +#define print_access_errors() 0 +#endif + +#ifdef CONFIG_MSM_L2_ERP_2BIT_PANIC +#define ERP_2BIT_ERR(a) panic(a) +#else +#define ERP_2BIT_ERR(a) do { } while (0) +#endif + +#define MODULE_NAME "msm_cache_erp" + +#define ERP_LOG_MAGIC_ADDR 0x6A4 +#define ERP_LOG_MAGIC 0x11C39893 + +struct msm_l1_err_stats { + unsigned int dctpe; + unsigned int dcdpe; + unsigned int ictpe; + unsigned int icdpe; + unsigned int dcte; + unsigned int icte; + unsigned int tlbmh; +}; + +struct msm_l2_err_stats { + unsigned int mpdcd; + unsigned int mpslv; + unsigned int tsesb; + unsigned int tsedb; + unsigned int dsesb; + unsigned int dsedb; + unsigned int mse; + unsigned int mplxrexnok; +}; + +struct msm_erp_dump_region { + struct resource *res; + void __iomem *va; +}; + +static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats); +static struct msm_l2_err_stats msm_l2_erp_stats; + +static int l1_erp_irq, l2_erp_irq; +static struct proc_dir_entry *procfs_entry; +static int num_dump_regions; +static struct msm_erp_dump_region *dump_regions; + +static void __iomem *msm_erp_log_base; + +#ifdef CONFIG_MSM_L1_ERR_LOG +static struct proc_dir_entry *procfs_log_entry; +#endif + +static inline unsigned int read_cesr(void) +{ + unsigned int cesr; + asm volatile ("mrc p15, 7, %0, c15, c0, 1" : "=r" (cesr)); + return cesr; +} + +static inline void write_cesr(unsigned int cesr) +{ + asm volatile ("mcr p15, 7, %[cesr], c15, c0, 1" : : [cesr]"r" (cesr)); +} + +static inline unsigned int read_cesynr(void) +{ + unsigned int cesynr; + asm volatile ("mrc p15, 7, %0, c15, c0, 3" : "=r" (cesynr)); + return cesynr; +} + +static int cache_erp_show(struct seq_file *m, void *v) +{ + struct msm_l1_err_stats *l1_stats; + int cpu; + + for_each_present_cpu(cpu) { + l1_stats = &per_cpu(msm_l1_erp_stats, cpu); + + seq_printf(m, + "CPU %d:\n" + "\tD-cache tag parity errors:\t%u\n" + "\tD-cache data parity errors:\t%u\n" + "\tI-cache tag parity errors:\t%u\n" + "\tI-cache data parity errors:\t%u\n" + "\tD-cache timing errors:\t\t%u\n" + "\tI-cache timing errors:\t\t%u\n" + "\tTLB multi-hit errors:\t\t%u\n\n", + cpu, + l1_stats->dctpe, + l1_stats->dcdpe, + l1_stats->ictpe, + l1_stats->icdpe, + l1_stats->dcte, + l1_stats->icte, + l1_stats->tlbmh); + } + + seq_printf(m, + "L2 master port decode errors:\t\t%u\n" + "L2 master port slave errors:\t\t%u\n" + "L2 tag soft errors, single-bit:\t\t%u\n" + "L2 tag soft errors, double-bit:\t\t%u\n" + "L2 data soft errors, single-bit:\t%u\n" + "L2 data soft errors, double-bit:\t%u\n" + "L2 modified soft errors:\t\t%u\n" + "L2 master port LDREX NOK errors:\t%u\n", + msm_l2_erp_stats.mpdcd, + msm_l2_erp_stats.mpslv, + msm_l2_erp_stats.tsesb, + msm_l2_erp_stats.tsedb, + msm_l2_erp_stats.dsesb, + msm_l2_erp_stats.dsedb, + msm_l2_erp_stats.mse, + msm_l2_erp_stats.mplxrexnok); + + return 0; +} + +static int cache_erp_open(struct inode *inode, struct file *file) +{ + return single_open(file, cache_erp_show, NULL); +} + +static const struct file_operations cache_erp_fops = { + .open = cache_erp_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int msm_erp_dump_regions(void) +{ + int i = 0; + struct msm_erp_dump_region *r; + + for (i = 0; i < num_dump_regions; i++) { + r = &dump_regions[i]; + + pr_alert("%s %pR:\n", r->res->name, r->res); + print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 32, 4, r->va, + resource_size(r->res), 0); + } + + return 0; +} + +#ifdef CONFIG_MSM_L1_ERR_LOG +static int cache_erp_log_show(struct seq_file *m, void *v) +{ + int log_value; + + log_value = __raw_readl(msm_erp_log_base) == ERP_LOG_MAGIC ? 1 : 0; + + seq_printf(m, "%d\n", log_value); + + return 0; +} + +static int cache_erp_log_open(struct inode *inode, struct file *file) +{ + return single_open(file, cache_erp_log_show, NULL); +} + +static const struct file_operations cache_erp_log_fops = { + .open = cache_erp_log_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void log_cpu_event(void) +{ + __raw_writel(ERP_LOG_MAGIC, msm_erp_log_base); + mb(); +} + +static int procfs_event_log_init(void) +{ + procfs_log_entry = proc_create("cpu/msm_erp_log", S_IRUGO, NULL, + &cache_erp_log_fops); + if (!procfs_log_entry) + return -ENODEV; + return 0; +} + +#else +static inline void log_cpu_event(void) { } +static inline int procfs_event_log_init(void) { return 0; } +#endif + +static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id) +{ + struct msm_l1_err_stats *l1_stats = dev_id; + unsigned int cesr = read_cesr(); + unsigned int i_cesynr, d_cesynr; + unsigned int cpu = smp_processor_id(); + int print_regs = cesr & CESR_PRINT_MASK; + int log_event = cesr & CESR_LOG_EVENT_MASK; + + if (print_regs) { + pr_alert("L1 / TLB Error detected on CPU %d!\n", cpu); + pr_alert("\tCESR = 0x%08x\n", cesr); + pr_alert("\tMIDR = 0x%08x\n", read_cpuid_id()); + msm_erp_dump_regions(); + } + + if (cesr & CESR_DCTPE) { + pr_alert("D-cache tag parity error\n"); + l1_stats->dctpe++; + } + + if (cesr & CESR_DCDPE) { + pr_alert("D-cache data parity error\n"); + l1_stats->dcdpe++; + } + + if (cesr & CESR_ICTPE) { + pr_alert("I-cache tag parity error\n"); + l1_stats->ictpe++; + } + + if (cesr & CESR_ICDPE) { + pr_alert("I-cache data parity error\n"); + l1_stats->icdpe++; + } + + if (cesr & CESR_DCTE) { + pr_alert("D-cache timing error\n"); + l1_stats->dcte++; + } + + if (cesr & CESR_ICTE) { + pr_alert("I-cache timing error\n"); + l1_stats->icte++; + } + + if (cesr & CESR_TLBMH) { + asm ("mcr p15, 0, r0, c8, c7, 0"); + l1_stats->tlbmh++; + } + + if (cesr & (CESR_ICTPE | CESR_ICDPE | CESR_ICTE)) { + i_cesynr = read_cesynr(); + pr_alert("I-side CESYNR = 0x%08x\n", i_cesynr); + write_cesr(CESR_I_MASK); + + /* + * Clear the I-side bits from the captured CESR value so that we + * don't accidentally clear any new I-side errors when we do + * the CESR write-clear operation. + */ + cesr &= ~CESR_I_MASK; + } + + if (cesr & (CESR_DCTPE | CESR_DCDPE | CESR_DCTE)) { + d_cesynr = read_cesynr(); + pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr); + } + + if (log_event) + log_cpu_event(); + + /* Clear the interrupt bits we processed */ + write_cesr(cesr); + + if (print_regs) { + if ((cesr & (~CESR_I_MASK & CESR_VALID_MASK)) || + cpu_is_krait_v1() || cpu_is_krait_v2()) + ERP_L1_ERR("L1 nonrecoverable cache error detected"); + else + ERP_L1_RECOV_ERR("L1 recoverable error detected\n"); + } + + return IRQ_HANDLED; +} + +static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id) +{ + unsigned int l2esr; + unsigned int l2esynr0; + unsigned int l2esynr1; + unsigned int l2ear0; + unsigned int l2ear1; + int soft_error = 0; + int port_error = 0; + int unrecoverable = 0; + int print_alert; + + l2esr = get_l2_indirect_reg(L2ESR_IND_ADDR); + l2esynr0 = get_l2_indirect_reg(L2ESYNR0_IND_ADDR); + l2esynr1 = get_l2_indirect_reg(L2ESYNR1_IND_ADDR); + l2ear0 = get_l2_indirect_reg(L2EAR0_IND_ADDR); + l2ear1 = get_l2_indirect_reg(L2EAR1_IND_ADDR); + + print_alert = print_access_errors() || (l2esr & L2ESR_ACCESS_ERR_MASK); + + if (print_alert) { + pr_alert("L2 Error detected!\n"); + pr_alert("\tL2ESR = 0x%08x\n", l2esr); + pr_alert("\tL2ESYNR0 = 0x%08x\n", l2esynr0); + pr_alert("\tL2ESYNR1 = 0x%08x\n", l2esynr1); + pr_alert("\tL2EAR0 = 0x%08x\n", l2ear0); + pr_alert("\tL2EAR1 = 0x%08x\n", l2ear1); + pr_alert("\tCPU bitmap = 0x%x\n", (l2esr >> L2ESR_CPU_SHIFT) & + L2ESR_CPU_MASK); + } + + if (l2esr & L2ESR_MPDCD) { + if (print_alert) + pr_alert("L2 master port decode error\n"); + port_error++; + msm_l2_erp_stats.mpdcd++; + } + + if (l2esr & L2ESR_MPSLV) { + if (print_alert) + pr_alert("L2 master port slave error\n"); + port_error++; + msm_l2_erp_stats.mpslv++; + } + + if (l2esr & L2ESR_TSESB) { + pr_alert("L2 tag soft error, single-bit\n"); + soft_error++; + msm_l2_erp_stats.tsesb++; + } + + if (l2esr & L2ESR_TSEDB) { + pr_alert("L2 tag soft error, double-bit\n"); + soft_error++; + unrecoverable++; + msm_l2_erp_stats.tsedb++; + } + + if (l2esr & L2ESR_DSESB) { + pr_alert("L2 data soft error, single-bit\n"); + soft_error++; + msm_l2_erp_stats.dsesb++; + } + + if (l2esr & L2ESR_DSEDB) { + pr_alert("L2 data soft error, double-bit\n"); + soft_error++; + unrecoverable++; + msm_l2_erp_stats.dsedb++; + } + + if (l2esr & L2ESR_MSE) { + pr_alert("L2 modified soft error\n"); + soft_error++; + msm_l2_erp_stats.mse++; + } + + if (l2esr & L2ESR_MPLDREXNOK) { + pr_alert("L2 master port LDREX received Normal OK response\n"); + port_error++; + msm_l2_erp_stats.mplxrexnok++; + } + + if (port_error && print_alert) + ERP_PORT_ERR("L2 master port error detected"); + + if (soft_error && print_alert) + msm_erp_dump_regions(); + + if (soft_error && !unrecoverable) + ERP_1BIT_ERR("L2 single-bit error detected"); + + if (unrecoverable) + ERP_2BIT_ERR("L2 double-bit error detected, trouble ahead"); + + set_l2_indirect_reg(L2ESR_IND_ADDR, l2esr); + return IRQ_HANDLED; +} + +static void enable_erp_irq_callback(void *info) +{ + enable_percpu_irq(l1_erp_irq, IRQ_TYPE_LEVEL_HIGH); +} + +static void disable_erp_irq_callback(void *info) +{ + disable_percpu_irq(l1_erp_irq); +} + +static int cache_erp_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + switch (action & (~CPU_TASKS_FROZEN)) { + case CPU_STARTING: + enable_erp_irq_callback(NULL); + break; + + case CPU_DYING: + disable_erp_irq_callback(NULL); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block cache_erp_cpu_notifier = { + .notifier_call = cache_erp_cpu_callback, +}; + +static int msm_erp_read_dump_regions(struct platform_device *pdev) +{ + int i; + struct device_node *np = pdev->dev.of_node; + struct resource *res; + + num_dump_regions = of_property_count_strings(np, "reg-names"); + + if (num_dump_regions <= 0) { + num_dump_regions = 0; + return 0; /* Not an error - this is an optional property */ + } + + dump_regions = devm_kzalloc(&pdev->dev, + sizeof(*dump_regions) * num_dump_regions, + GFP_KERNEL); + if (!dump_regions) + return -ENOMEM; + + for (i = 0; i < num_dump_regions; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + dump_regions[i].res = res; + dump_regions[i].va = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!dump_regions[i].va) + return -ENOMEM; + } + + return 0; +} + +static int msm_cache_erp_probe(struct platform_device *pdev) +{ + struct resource *r; + struct device_node *np = pdev->dev.of_node; + struct device_node *imem_node; + int ret, cpu; + + imem_node = of_parse_phandle(np, "qcom,msm-imem-phandle", 0); + if (!imem_node) { + pr_err("Could not get imem handle\n"); + ret = -ENODEV; + goto fail; + } + + msm_erp_log_base = of_iomap(imem_node, 0); + if (!msm_erp_log_base) { + pr_err("Failed to map imem region\n"); + ret = -ENODEV; + goto fail; + } + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l1_irq"); + + if (!r) { + pr_err("Could not get L1 resource\n"); + ret = -ENODEV; + goto fail_imem_map; + } + + l1_erp_irq = r->start; + + ret = request_percpu_irq(l1_erp_irq, msm_l1_erp_irq, "MSM_L1", + &msm_l1_erp_stats); + + if (ret) { + pr_err("Failed to request the L1 cache error interrupt\n"); + goto fail_imem_map; + } + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq"); + + if (!r) { + pr_err("Could not get L2 resource\n"); + ret = -ENODEV; + goto fail_l1; + } + + l2_erp_irq = r->start; + ret = request_irq(l2_erp_irq, msm_l2_erp_irq, 0, "MSM_L2", NULL); + + if (ret) { + pr_err("Failed to request the L2 cache error interrupt\n"); + goto fail_l1; + } + + procfs_entry = proc_create("cpu/msm_cache_erp", S_IRUGO, NULL, + &cache_erp_fops); + + if (!procfs_entry) { + pr_err("Failed to create procfs node for cache error reporting\n"); + ret = -ENODEV; + goto fail_l2; + } + + ret = msm_erp_read_dump_regions(pdev); + + if (ret) + goto fail_l2; + + get_online_cpus(); + register_hotcpu_notifier(&cache_erp_cpu_notifier); + for_each_cpu(cpu, cpu_online_mask) + smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1); + put_online_cpus(); + + ret = procfs_event_log_init(); + if (ret) + pr_err("Failed to create procfs node for ERP log access\n"); + + return 0; + +fail_l2: + free_irq(l2_erp_irq, NULL); +fail_l1: + free_percpu_irq(l1_erp_irq, NULL); +fail_imem_map: + iounmap(msm_erp_log_base); +fail: + return ret; +} + +static int msm_cache_erp_remove(struct platform_device *pdev) +{ + int cpu; + if (procfs_entry) + remove_proc_entry("cpu/msm_cache_erp", NULL); + + get_online_cpus(); + unregister_hotcpu_notifier(&cache_erp_cpu_notifier); + for_each_cpu(cpu, cpu_online_mask) + smp_call_function_single(cpu, disable_erp_irq_callback, NULL, + 1); + put_online_cpus(); + + free_percpu_irq(l1_erp_irq, NULL); + + disable_irq(l2_erp_irq); + free_irq(l2_erp_irq, NULL); + return 0; +} + +static struct of_device_id cache_erp_match_table[] = { + { .compatible = "qcom,cache_erp", }, + {} +}; + +static struct platform_driver msm_cache_erp_driver = { + .probe = msm_cache_erp_probe, + .remove = msm_cache_erp_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .of_match_table = cache_erp_match_table, + }, +}; + +static int __init msm_cache_erp_init(void) +{ + return platform_driver_register(&msm_cache_erp_driver); +} + +static void __exit msm_cache_erp_exit(void) +{ + platform_driver_unregister(&msm_cache_erp_driver); +} + + +module_init(msm_cache_erp_init); +module_exit(msm_cache_erp_exit); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM cache error reporting driver"); diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index fb9762464718..84246a5b81a6 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/dma.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2010, 2012, 2013 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -19,35 +20,199 @@ #include <linux/interrupt.h> #include <linux/completion.h> #include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/pm_runtime.h> #include <mach/dma.h> -#include <mach/msm_iomap.h> + +#define MODULE_NAME "msm_dmov" #define MSM_DMOV_CHANNEL_COUNT 16 +#define MSM_DMOV_CRCI_COUNT 16 -#define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2)) -#define DMOV_SD1(off, ch) (MSM_DMOV_BASE + 0x0400 + (off) + ((ch) << 2)) -#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2)) -#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2)) +enum { + CLK_DIS, + CLK_ENABLING, + CLK_EN, + CLK_TO_BE_DIS, + CLK_DISABLING +}; -#if defined(CONFIG_ARCH_MSM7X30) -#define DMOV_SD_AARM DMOV_SD2 -#else -#define DMOV_SD_AARM DMOV_SD3 -#endif +struct msm_dmov_ci_conf { + int start; + int end; + int burst; +}; + +struct msm_dmov_crci_conf { + int sd; + int blk_size; +}; + +struct msm_dmov_chan_conf { + int sd; + int block; + int priority; +}; + +struct msm_dmov_conf { + void *base; + struct msm_dmov_crci_conf *crci_conf; + struct msm_dmov_chan_conf *chan_conf; + int channel_active; + int sd; + size_t sd_size; + struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT]; + struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; + struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; + struct mutex clock_lock; + spinlock_t lock; + unsigned int irq; + struct clk *clk; + struct clk *pclk; + struct clk *ebiclk; + unsigned int clk_ctl; + struct delayed_work work; + struct workqueue_struct *cmd_wq; +}; + +static void msm_dmov_clock_work(struct work_struct *); + +#ifdef CONFIG_ARCH_MSM8X60 + +#define DMOV_CHANNEL_DEFAULT_CONF { .sd = 1, .block = 0, .priority = 0 } +#define DMOV_CHANNEL_MODEM_CONF { .sd = 3, .block = 0, .priority = 0 } +#define DMOV_CHANNEL_CONF(secd, blk, pri) \ + { .sd = secd, .block = blk, .priority = pri } + +static struct msm_dmov_chan_conf adm0_chan_conf[] = { + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_DEFAULT_CONF, +}; + +static struct msm_dmov_chan_conf adm1_chan_conf[] = { + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_DEFAULT_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, + DMOV_CHANNEL_MODEM_CONF, +}; + +#define DMOV_CRCI_DEFAULT_CONF { .sd = 1, .blk_size = 0 } +#define DMOV_CRCI_CONF(secd, blk) { .sd = secd, .blk_size = blk } + +static struct msm_dmov_crci_conf adm0_crci_conf[] = { + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_CONF(1, 4), + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, +}; -#define DMOV_CMD_PTR(ch) DMOV_SD_AARM(0x000, ch) -#define DMOV_RSLT(ch) DMOV_SD_AARM(0x040, ch) -#define DMOV_FLUSH0(ch) DMOV_SD_AARM(0x080, ch) -#define DMOV_FLUSH1(ch) DMOV_SD_AARM(0x0C0, ch) -#define DMOV_FLUSH2(ch) DMOV_SD_AARM(0x100, ch) -#define DMOV_FLUSH3(ch) DMOV_SD_AARM(0x140, ch) -#define DMOV_FLUSH4(ch) DMOV_SD_AARM(0x180, ch) -#define DMOV_FLUSH5(ch) DMOV_SD_AARM(0x1C0, ch) +static struct msm_dmov_crci_conf adm1_crci_conf[] = { + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_CONF(1, 1), + DMOV_CRCI_CONF(1, 1), + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_CONF(1, 1), + DMOV_CRCI_CONF(1, 1), + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_DEFAULT_CONF, + DMOV_CRCI_CONF(1, 1), + DMOV_CRCI_DEFAULT_CONF, +}; -#define DMOV_STATUS(ch) DMOV_SD_AARM(0x200, ch) -#define DMOV_ISR DMOV_SD_AARM(0x380, 0) +static struct msm_dmov_conf dmov_conf[] = { + { + .crci_conf = adm0_crci_conf, + .chan_conf = adm0_chan_conf, + .clock_lock = __MUTEX_INITIALIZER(dmov_conf[0].clock_lock), + .lock = __SPIN_LOCK_UNLOCKED(dmov_lock), + .clk_ctl = CLK_DIS, + .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work, + msm_dmov_clock_work, 0), + }, { + .crci_conf = adm1_crci_conf, + .chan_conf = adm1_chan_conf, + .clock_lock = __MUTEX_INITIALIZER(dmov_conf[1].clock_lock), + .lock = __SPIN_LOCK_UNLOCKED(dmov_lock), + .clk_ctl = CLK_DIS, + .work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work, + msm_dmov_clock_work, 0), + } +}; +#else +static struct msm_dmov_conf dmov_conf[] = { + { + .crci_conf = NULL, + .chan_conf = NULL, + .clock_lock = __MUTEX_INITIALIZER(dmov_conf[0].clock_lock), + .lock = __SPIN_LOCK_UNLOCKED(dmov_lock), + .clk_ctl = CLK_DIS, + .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work, + msm_dmov_clock_work, 0), + } +}; +#endif -#define DMOV_CONFIG(ch) DMOV_SD_AARM(0x300, ch) +#define MSM_DMOV_ID_COUNT (MSM_DMOV_CHANNEL_COUNT * ARRAY_SIZE(dmov_conf)) +#define DMOV_REG(name, adm) ((name) + (dmov_conf[adm].base) +\ + (dmov_conf[adm].sd * dmov_conf[adm].sd_size)) +#define DMOV_ID_TO_ADM(id) ((id) / MSM_DMOV_CHANNEL_COUNT) +#define DMOV_ID_TO_CHAN(id) ((id) % MSM_DMOV_CHANNEL_COUNT) +#define DMOV_CHAN_ADM_TO_ID(ch, adm) ((ch) + (adm) * MSM_DMOV_CHANNEL_COUNT) + +#ifdef CONFIG_MSM_ADM3 +#define DMOV_IRQ_TO_ADM(irq) \ +({ \ + typeof(irq) _irq = irq; \ + ((_irq == INT_ADM1_MASTER) || (_irq == INT_ADM1_AARM)); \ +}) +#else +#define DMOV_IRQ_TO_ADM(irq) 0 +#endif enum { MSM_DMOV_PRINT_ERRORS = 1, @@ -55,11 +220,6 @@ enum { MSM_DMOV_PRINT_FLOW = 4 }; -static DEFINE_SPINLOCK(msm_dmov_lock); -static struct clk *msm_dmov_clk; -static unsigned int channel_active; -static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; -static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; #define MSM_DMOV_DPRINTF(mask, format, args...) \ @@ -74,51 +234,274 @@ unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; #define PRINT_FLOW(format, args...) \ MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args); -void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) +static int msm_dmov_clk_on(int adm) { - writel((graceful << 31), DMOV_FLUSH0(id)); + int ret; + + ret = clk_prepare_enable(dmov_conf[adm].clk); + if (ret) + return ret; + if (dmov_conf[adm].pclk) { + ret = clk_prepare_enable(dmov_conf[adm].pclk); + if (ret) { + clk_disable_unprepare(dmov_conf[adm].clk); + return ret; + } + } + if (dmov_conf[adm].ebiclk) { + ret = clk_prepare_enable(dmov_conf[adm].ebiclk); + if (ret) { + if (dmov_conf[adm].pclk) + clk_disable_unprepare(dmov_conf[adm].pclk); + clk_disable_unprepare(dmov_conf[adm].clk); + } + } + return ret; } EXPORT_SYMBOL_GPL(msm_dmov_stop_cmd); -void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) +static void msm_dmov_clk_off(int adm) { + if (dmov_conf[adm].ebiclk) + clk_disable_unprepare(dmov_conf[adm].ebiclk); + if (dmov_conf[adm].pclk) + clk_disable_unprepare(dmov_conf[adm].pclk); + clk_disable_unprepare(dmov_conf[adm].clk); +} + +static void msm_dmov_clock_work(struct work_struct *work) +{ + struct msm_dmov_conf *conf = + container_of(to_delayed_work(work), struct msm_dmov_conf, work); + int adm = DMOV_IRQ_TO_ADM(conf->irq); unsigned long irq_flags; - unsigned int status; - spin_lock_irqsave(&msm_dmov_lock, irq_flags); - if (!channel_active) - clk_enable(msm_dmov_clk); - dsb(); - status = readl(DMOV_STATUS(id)); - if (list_empty(&ready_commands[id]) && - (status & DMOV_STATUS_CMD_PTR_RDY)) { -#if 0 - if (list_empty(&active_commands[id])) { - PRINT_FLOW("msm_dmov_enqueue_cmd(%d), enable interrupt\n", id); - writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id)); + mutex_lock(&conf->clock_lock); + spin_lock_irqsave(&conf->lock, irq_flags); + if (conf->clk_ctl == CLK_TO_BE_DIS) { + BUG_ON(conf->channel_active); + conf->clk_ctl = CLK_DISABLING; + spin_unlock_irqrestore(&conf->lock, irq_flags); + msm_dmov_clk_off(adm); + spin_lock_irqsave(&conf->lock, irq_flags); + if (conf->clk_ctl == CLK_DISABLING) + conf->clk_ctl = CLK_DIS; + } + spin_unlock_irqrestore(&conf->lock, irq_flags); + mutex_unlock(&conf->clock_lock); +} + +enum { + NOFLUSH = 0, + GRACEFUL, + NONGRACEFUL, +}; + +/* Caller must hold the list lock */ +static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm) +{ + struct msm_dmov_cmd *cmd; + + if (list_empty(&dmov_conf[adm].ready_commands[ch])) + return NULL; + + cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd), + list); + list_del(&cmd->list); + if (cmd->exec_func) + cmd->exec_func(cmd); + list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]); + if (!dmov_conf[adm].channel_active) + enable_irq(dmov_conf[adm].irq); + dmov_conf[adm].channel_active |= BIT(ch); + PRINT_IO("start_ready_cmd, %x, ch %d\n", cmd->cmdptr, ch); + writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm)); + + return cmd; +} + +static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work) +{ + struct msm_dmov_cmd *cmd = + container_of(work, struct msm_dmov_cmd, work); + unsigned id = cmd->id; + unsigned status; + unsigned long flags; + int adm = DMOV_ID_TO_ADM(id); + int ch = 0; + + mutex_lock(&dmov_conf[adm].clock_lock); + /*No spin_lock is required for the condition check below*/ + BUG_ON(dmov_conf[adm].clk_ctl != CLK_ENABLING); + status = msm_dmov_clk_on(adm); + if (status != 0) { + PRINT_ERROR("ADM: Unexpected clock failure at dma.c:%d/%s()!\n", + __LINE__, __func__); + goto error; + } + + spin_lock_irqsave(&dmov_conf[adm].lock, flags); + + dmov_conf[adm].clk_ctl = CLK_EN; + + for (ch = 0; ch < MSM_DMOV_CHANNEL_COUNT; ch++) { + while (!list_empty(&dmov_conf[adm].staged_commands[ch])) { + cmd = list_entry(dmov_conf[adm].staged_commands[ch]. + next, typeof(*cmd), list); + list_del(&cmd->list); + list_add_tail(&cmd->list, &dmov_conf[adm]. + ready_commands[ch]); } -#endif - if (cmd->execute_func) - cmd->execute_func(cmd); - PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); - list_add_tail(&cmd->list, &active_commands[id]); - if (!channel_active) - enable_irq(INT_ADM_AARM); - channel_active |= 1U << id; - writel(cmd->cmdptr, DMOV_CMD_PTR(id)); + if (!list_empty(&dmov_conf[adm].ready_commands[ch])) { + status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); + if (status & DMOV_STATUS_CMD_PTR_RDY) { + PRINT_IO("msm_dmov_enqueue_cmd(%d),"\ + " start command, status %x\n", + id, status); + cmd = start_ready_cmd(ch, adm); + /* + * We added something to the ready list, + * and still hold the list lock. + * Thus, no need to check for cmd == NULL + */ + if (cmd->toflush) { + int flush = (cmd->toflush == GRACEFUL) ? + 1 << 31 : 0; + writel_relaxed(flush, + DMOV_REG(DMOV_FLUSH0(ch), adm)); + } + } else { + if (list_empty(&dmov_conf[adm]. + active_commands[ch])) + PRINT_ERROR("msm_dmov_enqueue_cmd_ext"\ + "(%d), stalled, status %x\n", + id, status); + PRINT_IO("msm_dmov_enqueue_cmd(%d),"\ + "enqueue command, status " + "%x\n", id, status); + } + } + } + spin_unlock_irqrestore(&dmov_conf[adm].lock, flags); +error: + mutex_unlock(&dmov_conf[adm].clock_lock); +} + +void msm_dmov_enqueue_cmd_ext_atomic(unsigned id, struct msm_dmov_cmd *cmd) +{ + unsigned int status; + int adm = DMOV_ID_TO_ADM(id); + int ch = DMOV_ID_TO_CHAN(id); + + status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); + if (status & DMOV_STATUS_CMD_PTR_RDY) { + PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", + id, status); + if (cmd->exec_func) + cmd->exec_func(cmd); + list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]); + if (!dmov_conf[adm].channel_active) + enable_irq(dmov_conf[adm].irq); + dmov_conf[adm].channel_active |= BIT(ch); + PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, + ch); + writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm)); } else { - if (!channel_active) - clk_disable(msm_dmov_clk); - if (list_empty(&active_commands[id])) - PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); + list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]); + if (list_empty(&dmov_conf[adm].active_commands[ch]) && + !list_empty(&dmov_conf[adm].ready_commands[ch])) + PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, " + "status %x\n", id, status); + PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status " + "%x\n", id, status); + } +} - PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status %x\n", id, status); - list_add_tail(&cmd->list, &ready_commands[id]); +static void __msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd, + int onstack) +{ + int adm = DMOV_ID_TO_ADM(id); + int ch = DMOV_ID_TO_CHAN(id); + unsigned long flags; + + cmd->id = id; + cmd->toflush = 0; + + spin_lock_irqsave(&dmov_conf[adm].lock, flags); + switch (dmov_conf[adm].clk_ctl) { + case CLK_DIS: + case CLK_DISABLING: + if (onstack) + INIT_WORK_ONSTACK(&cmd->work, + msm_dmov_enqueue_cmd_ext_work); + else + INIT_WORK(&cmd->work, + msm_dmov_enqueue_cmd_ext_work); + list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]); + dmov_conf[adm].clk_ctl = CLK_ENABLING; + queue_work(dmov_conf[adm].cmd_wq, &cmd->work); + break; + + case CLK_ENABLING: + list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]); + break; + + case CLK_EN: + msm_dmov_enqueue_cmd_ext_atomic(id, cmd); + break; + + case CLK_TO_BE_DIS: + cancel_delayed_work(&dmov_conf[adm].work); + dmov_conf[adm].clk_ctl = CLK_EN; + msm_dmov_enqueue_cmd_ext_atomic(id, cmd); + break; + + default: + PRINT_ERROR("ADM%d: Invalid CLK State.\n", adm); + BUG_ON(dmov_conf[adm].clk_ctl); } - spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); + + spin_unlock_irqrestore(&dmov_conf[adm].lock, flags); } EXPORT_SYMBOL_GPL(msm_dmov_enqueue_cmd); +void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd) +{ + __msm_dmov_enqueue_cmd_ext(id, cmd, 0); +} +EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext); + +void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) +{ + /* Disable callback function (for backwards compatibility) */ + cmd->exec_func = NULL; + __msm_dmov_enqueue_cmd_ext(id, cmd, 0); +} +EXPORT_SYMBOL(msm_dmov_enqueue_cmd); + +void msm_dmov_flush(unsigned int id, int graceful) +{ + unsigned long irq_flags; + int ch = DMOV_ID_TO_CHAN(id); + int adm = DMOV_ID_TO_ADM(id); + int flush = graceful ? DMOV_FLUSH_TYPE : 0; + struct msm_dmov_cmd *cmd; + + spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + /* XXX not checking if flush cmd sent already */ + if (!list_empty(&dmov_conf[adm].active_commands[ch])) { + PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id); + writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm)); + } + list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list) + cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL; + list_for_each_entry(cmd, &dmov_conf[adm].ready_commands[ch], list) + cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL; + /* spin_unlock_irqrestore has the necessary barrier */ + spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); +} +EXPORT_SYMBOL(msm_dmov_flush); + struct msm_dmov_exec_cmdptr_cmd { struct msm_dmov_cmd dmov_cmd; struct completion complete; @@ -132,7 +515,8 @@ dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result, struct msm_dmov_errdata *err) { - struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); + struct msm_dmov_exec_cmdptr_cmd *cmd = + container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); cmd->result = result; if (result != 0x80000002 && err) memcpy(&cmd->err, err, sizeof(struct msm_dmov_errdata)); @@ -148,141 +532,338 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) cmd.dmov_cmd.cmdptr = cmdptr; cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; - cmd.dmov_cmd.execute_func = NULL; + cmd.dmov_cmd.exec_func = NULL; cmd.id = id; + cmd.result = 0; init_completion(&cmd.complete); - msm_dmov_enqueue_cmd(id, &cmd.dmov_cmd); - wait_for_completion(&cmd.complete); + __msm_dmov_enqueue_cmd_ext(id, &cmd.dmov_cmd, 1); + wait_for_completion_io(&cmd.complete); if (cmd.result != 0x80000002) { - PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result); + PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", + id, cmd.result); PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n", - id, cmd.err.flush[0], cmd.err.flush[1], cmd.err.flush[2], cmd.err.flush[3]); + id, cmd.err.flush[0], cmd.err.flush[1], + cmd.err.flush[2], cmd.err.flush[3]); return -EIO; } PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); return 0; } +EXPORT_SYMBOL(msm_dmov_exec_cmd); +static void fill_errdata(struct msm_dmov_errdata *errdata, int ch, int adm) +{ + errdata->flush[0] = readl_relaxed(DMOV_REG(DMOV_FLUSH0(ch), adm)); + errdata->flush[1] = readl_relaxed(DMOV_REG(DMOV_FLUSH1(ch), adm)); + errdata->flush[2] = 0; + errdata->flush[3] = readl_relaxed(DMOV_REG(DMOV_FLUSH3(ch), adm)); + errdata->flush[4] = readl_relaxed(DMOV_REG(DMOV_FLUSH4(ch), adm)); + errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm)); +} -static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) +static irqreturn_t msm_dmov_isr(int irq, void *dev_id) { - unsigned int int_status, mask, id; + unsigned int int_status; + unsigned int mask; + unsigned int id; + unsigned int ch; unsigned long irq_flags; unsigned int ch_status; unsigned int ch_result; + unsigned int valid = 0; struct msm_dmov_cmd *cmd; + int adm = DMOV_IRQ_TO_ADM(irq); - spin_lock_irqsave(&msm_dmov_lock, irq_flags); - - int_status = readl(DMOV_ISR); /* read and clear interrupt */ + spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + /* read and clear isr */ + int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm)); PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status); while (int_status) { mask = int_status & -int_status; - id = fls(mask) - 1; - PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id); + ch = fls(mask) - 1; + id = DMOV_CHAN_ADM_TO_ID(ch, adm); + PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", + int_status, mask, id); int_status &= ~mask; - ch_status = readl(DMOV_STATUS(id)); + ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); if (!(ch_status & DMOV_STATUS_RSLT_VALID)) { - PRINT_FLOW("msm_datamover_irq_handler id %d, result not valid %x\n", id, ch_status); + PRINT_FLOW("msm_datamover_irq_handler id %d, " + "result not valid %x\n", id, ch_status); continue; } do { - ch_result = readl(DMOV_RSLT(id)); - if (list_empty(&active_commands[id])) { - PRINT_ERROR("msm_datamover_irq_handler id %d, got result " - "with no active command, status %x, result %x\n", + valid = 1; + ch_result = readl_relaxed(DMOV_REG(DMOV_RSLT(ch), adm)); + if (list_empty(&dmov_conf[adm].active_commands[ch])) { + PRINT_ERROR("msm_datamover_irq_handler id %d,"\ + " got result with no active command," + " status %x, result %x\n", id, ch_status, ch_result); cmd = NULL; - } else - cmd = list_entry(active_commands[id].next, typeof(*cmd), list); - PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result); + } else { + cmd = list_entry(dmov_conf[adm]. + active_commands[ch].next, typeof(*cmd), + list); + } + PRINT_FLOW("msm_datamover_irq_handler id %d, status"\ + " %x, result %x\n", id, ch_status, ch_result); if (ch_result & DMOV_RSLT_DONE) { - PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", - id, ch_status); - PRINT_IO("msm_datamover_irq_handler id %d, got result " - "for %p, result %x\n", id, cmd, ch_result); + PRINT_FLOW("msm_datamover_irq_handler id %d,"\ + " status %x\n", id, ch_status); + PRINT_IO("msm_datamover_irq_handler id %d,"\ + " got result for %p," + " result %x\n", id, cmd, ch_result); if (cmd) { list_del(&cmd->list); - dsb(); - cmd->complete_func(cmd, ch_result, NULL); + cmd->complete_func(cmd, ch_result, + NULL); } } if (ch_result & DMOV_RSLT_FLUSH) { struct msm_dmov_errdata errdata; - errdata.flush[0] = readl(DMOV_FLUSH0(id)); - errdata.flush[1] = readl(DMOV_FLUSH1(id)); - errdata.flush[2] = readl(DMOV_FLUSH2(id)); - errdata.flush[3] = readl(DMOV_FLUSH3(id)); - errdata.flush[4] = readl(DMOV_FLUSH4(id)); - errdata.flush[5] = readl(DMOV_FLUSH5(id)); - PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); - PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); + fill_errdata(&errdata, ch, adm); + PRINT_FLOW("msm_datamover_irq_handler id %d,"\ + " status %x\n", id, ch_status); + PRINT_FLOW("msm_datamover_irq_handler id %d,"\ + " flush, result %x,flush0 %x\n", id, + ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); - dsb(); - cmd->complete_func(cmd, ch_result, &errdata); + cmd->complete_func(cmd, ch_result, + &errdata); } } if (ch_result & DMOV_RSLT_ERROR) { struct msm_dmov_errdata errdata; - errdata.flush[0] = readl(DMOV_FLUSH0(id)); - errdata.flush[1] = readl(DMOV_FLUSH1(id)); - errdata.flush[2] = readl(DMOV_FLUSH2(id)); - errdata.flush[3] = readl(DMOV_FLUSH3(id)); - errdata.flush[4] = readl(DMOV_FLUSH4(id)); - errdata.flush[5] = readl(DMOV_FLUSH5(id)); + fill_errdata(&errdata, ch, adm); - PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); - PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); + PRINT_ERROR("msm_datamover_irq_handler id %d,"\ + " status %x\n", id, ch_status); + PRINT_ERROR("msm_datamover_irq_handler id %d,"\ + " error, result %x, flush0 %x\n", + id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); - dsb(); - cmd->complete_func(cmd, ch_result, &errdata); + cmd->complete_func(cmd, ch_result, + &errdata); } - /* this does not seem to work, once we get an error */ - /* the datamover will no longer accept commands */ - writel(0, DMOV_FLUSH0(id)); + /* this does not seem to work, once we get an + * error. the datamover will no longer accept + * commands + */ + writel_relaxed(0, DMOV_REG(DMOV_FLUSH0(ch), + adm)); } - ch_status = readl(DMOV_STATUS(id)); - PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); - if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) && !list_empty(&ready_commands[id])) { - cmd = list_entry(ready_commands[id].next, typeof(*cmd), list); - list_move_tail(&cmd->list, &active_commands[id]); - if (cmd->execute_func) - cmd->execute_func(cmd); - PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id); - writel(cmd->cmdptr, DMOV_CMD_PTR(id)); + rmb(); + ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), + adm)); + PRINT_FLOW("msm_datamover_irq_handler id %d, status"\ + " %x\n", id, ch_status); + if (ch_status & DMOV_STATUS_CMD_PTR_RDY) { + cmd = start_ready_cmd(ch, adm); + + if (cmd != NULL) { + if (cmd->toflush) { + int flush = (cmd->toflush == + GRACEFUL) ? 1 << 31 : 0; + writel_relaxed(flush, + DMOV_REG(DMOV_FLUSH0(ch), adm)); + } + } } } while (ch_status & DMOV_STATUS_RSLT_VALID); - if (list_empty(&active_commands[id]) && list_empty(&ready_commands[id])) - channel_active &= ~(1U << id); - PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); + if (list_empty(&dmov_conf[adm].active_commands[ch]) && + list_empty(&dmov_conf[adm].ready_commands[ch])) + dmov_conf[adm].channel_active &= ~(1U << ch); + PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, + ch_status); } - if (!channel_active) { - disable_irq_nosync(INT_ADM_AARM); - clk_disable(msm_dmov_clk); + if (!dmov_conf[adm].channel_active && valid) { + disable_irq_nosync(dmov_conf[adm].irq); + dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS; + schedule_delayed_work(&dmov_conf[adm].work, (HZ/10)); } - spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); - return IRQ_HANDLED; + spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); + return valid ? IRQ_HANDLED : IRQ_NONE; } -static int __init msm_init_datamover(void) +static int msm_dmov_suspend_late(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + int adm = (pdev->id >= 0) ? pdev->id : 0; + unsigned long irq_flags; + + mutex_lock(&dmov_conf[adm].clock_lock); + spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) { + BUG_ON(dmov_conf[adm].channel_active); + dmov_conf[adm].clk_ctl = CLK_DISABLING; + spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); + msm_dmov_clk_off(adm); + spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + if (dmov_conf[adm].clk_ctl == CLK_DISABLING) + dmov_conf[adm].clk_ctl = CLK_DIS; + } + spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); + mutex_unlock(&dmov_conf[adm].clock_lock); + return 0; +} + +static int msm_dmov_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int msm_dmov_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static int msm_dmov_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: idling...\n"); + return 0; +} + +static const struct dev_pm_ops msm_dmov_dev_pm_ops = { + .runtime_suspend = msm_dmov_runtime_suspend, + .runtime_resume = msm_dmov_runtime_resume, + .runtime_idle = msm_dmov_runtime_idle, + .suspend = msm_dmov_suspend_late, +}; + +static int msm_dmov_init_clocks(struct platform_device *pdev) +{ + int adm = (pdev->id >= 0) ? pdev->id : 0; + int ret; + + dmov_conf[adm].clk = clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(dmov_conf[adm].clk)) { + printk(KERN_ERR "%s: Error getting adm_clk\n", __func__); + dmov_conf[adm].clk = NULL; + return -ENOENT; + } + + dmov_conf[adm].pclk = clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR(dmov_conf[adm].pclk)) { + dmov_conf[adm].pclk = NULL; + /* pclk not present on all SoCs, don't bail on failure */ + } + + dmov_conf[adm].ebiclk = clk_get(&pdev->dev, "mem_clk"); + if (IS_ERR(dmov_conf[adm].ebiclk)) { + dmov_conf[adm].ebiclk = NULL; + /* ebiclk not present on all SoCs, don't bail on failure */ + } else { + ret = clk_set_rate(dmov_conf[adm].ebiclk, 27000000); + if (ret) + return -ENOENT; + } + + return 0; +} + +static void config_datamover(int adm) { +#ifdef CONFIG_MSM_ADM3 + int i; + for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { + struct msm_dmov_chan_conf *chan_conf = + dmov_conf[adm].chan_conf; + unsigned conf; + /* Only configure scorpion channels */ + if (chan_conf[i].sd <= 1) { + conf = readl_relaxed(DMOV_REG(DMOV_CONF(i), adm)); + conf &= ~DMOV_CONF_SD(7); + conf |= DMOV_CONF_SD(chan_conf[i].sd); + writel_relaxed(conf | DMOV_CONF_SHADOW_EN, + DMOV_REG(DMOV_CONF(i), adm)); + } + } + for (i = 0; i < MSM_DMOV_CRCI_COUNT; i++) { + struct msm_dmov_crci_conf *crci_conf = + dmov_conf[adm].crci_conf; + + writel_relaxed(DMOV_CRCI_CTL_BLK_SZ(crci_conf[i].blk_size), + DMOV_REG(DMOV_CRCI_CTL(i), adm)); + } +#endif +} + +static int msm_dmov_probe(struct platform_device *pdev) +{ + int adm = (pdev->id >= 0) ? pdev->id : 0; int i; int ret; - struct clk *clk; + struct msm_dmov_pdata *pdata = pdev->dev.platform_data; + struct resource *irqres = + platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct resource *mres = + platform_get_resource(pdev, IORESOURCE_MEM, 0); + char wq_name[12]; + + if (pdata) { + dmov_conf[adm].sd = pdata->sd; + dmov_conf[adm].sd_size = pdata->sd_size; + } + if (!dmov_conf[adm].sd_size) + return -ENXIO; + + if (!irqres || !irqres->start) + return -ENXIO; + dmov_conf[adm].irq = irqres->start; + + if (!mres || !mres->start) + return -ENXIO; + dmov_conf[adm].base = ioremap_nocache(mres->start, resource_size(mres)); + if (!dmov_conf[adm].base) + return -ENOMEM; + + snprintf(wq_name, sizeof(wq_name), "dmov%d_wq", adm); + dmov_conf[adm].cmd_wq = alloc_workqueue(wq_name, WQ_CPU_INTENSIVE, 1); + if (!dmov_conf[adm].cmd_wq) { + PRINT_ERROR("Couldn't allocate ADM%d workqueue.\n", adm); + ret = -ENOMEM; + goto out_map; + } + + ret = request_irq(dmov_conf[adm].irq, msm_dmov_isr, + 0, "msmdatamover", NULL); + if (ret) { + PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm, + dmov_conf[adm].irq); + goto out_wq; + } + disable_irq(dmov_conf[adm].irq); + ret = msm_dmov_init_clocks(pdev); + if (ret) { + PRINT_ERROR("Requesting ADM%d clocks failed\n", adm); + goto out_irq; + } + ret = msm_dmov_clk_on(adm); + if (ret) { + PRINT_ERROR("Enabling ADM%d clocks failed\n", adm); + goto out_irq; + } + config_datamover(adm); for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { - INIT_LIST_HEAD(&ready_commands[i]); - INIT_LIST_HEAD(&active_commands[i]); - writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); + INIT_LIST_HEAD(&dmov_conf[adm].staged_commands[i]); + INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]); + INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]); + + writel_relaxed(DMOV_RSLT_CONF_IRQ_EN + | DMOV_RSLT_CONF_FORCE_FLUSH_RSLT, + DMOV_REG(DMOV_RSLT_CONF(i), adm)); } clk = clk_get(NULL, "adm_clk"); if (IS_ERR(clk)) @@ -290,9 +871,35 @@ static int __init msm_init_datamover(void) clk_prepare(clk); msm_dmov_clk = clk; ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); + wmb(); + msm_dmov_clk_off(adm); + return ret; +out_irq: + free_irq(dmov_conf[adm].irq, NULL); +out_wq: + destroy_workqueue(dmov_conf[adm].cmd_wq); +out_map: + iounmap(dmov_conf[adm].base); + return ret; +} + +static struct platform_driver msm_dmov_driver = { + .probe = msm_dmov_probe, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .pm = &msm_dmov_dev_pm_ops, + }, +}; + +/* static int __init */ +static int __init msm_init_datamover(void) +{ + int ret; + ret = platform_driver_register(&msm_dmov_driver); if (ret) return ret; - disable_irq(INT_ADM_AARM); return 0; } module_init(msm_init_datamover); +arch_initcall(msm_init_datamover); diff --git a/arch/arm/mach-msm/gpiomux-v2.c b/arch/arm/mach-msm/gpiomux-v2.c new file mode 100644 index 000000000000..92b914814833 --- /dev/null +++ b/arch/arm/mach-msm/gpiomux-v2.c @@ -0,0 +1,32 @@ +/* Copyright (c) 2010-2011, 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 <linux/bitops.h> +#include <linux/io.h> +#include <mach/msm_iomap.h> +#include <mach/gpiomux.h> + +#define GPIO_CFG(n) (MSM_TLMM_BASE + 0x1000 + (0x10 * n)) +#define GPIO_IN_OUT(n) (MSM_TLMM_BASE + 0x1004 + (0x10 * n)) + +void __msm_gpiomux_write(unsigned gpio, struct gpiomux_setting val) +{ + uint32_t bits; + + bits = (val.drv << 6) | (val.func << 2) | val.pull; + if (val.func == GPIOMUX_FUNC_GPIO) { + bits |= val.dir > GPIOMUX_IN ? BIT(9) : 0; + __raw_writel(val.dir == GPIOMUX_OUT_HIGH ? BIT(1) : 0, + GPIO_IN_OUT(gpio)); + } + __raw_writel(bits, GPIO_CFG(gpio)); + mb(); +} diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c index 2b8e2d217082..967c577b726e 100644 --- a/arch/arm/mach-msm/gpiomux.c +++ b/arch/arm/mach-msm/gpiomux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010,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 @@ -8,19 +8,31 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> #include <linux/spinlock.h> +<<<<<<< current #include "gpiomux.h" #include "proc_comm.h" +======= +#include <linux/io.h> +#include <mach/gpiomux.h> +#include <mach/msm_iomap.h> + +struct msm_gpiomux_rec { + struct gpiomux_setting *sets[GPIOMUX_NSETTINGS]; + int ref; +}; +>>>>>>> patched static DEFINE_SPINLOCK(gpiomux_lock); +static struct msm_gpiomux_rec *msm_gpiomux_recs; +static struct gpiomux_setting *msm_gpiomux_sets; +static unsigned msm_gpiomux_ngpio; +<<<<<<< current static void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val) { unsigned tlmm_config = (val & ~GPIOMUX_CTL_MASK) | @@ -38,42 +50,80 @@ static void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val) int msm_gpiomux_write(unsigned gpio, gpiomux_config_t active, gpiomux_config_t suspended) +======= +static int msm_gpiomux_store(unsigned gpio, enum msm_gpiomux_setting which, + struct gpiomux_setting *setting, struct gpiomux_setting *old_setting) +>>>>>>> patched { - struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; + struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio; + unsigned set_slot = gpio * GPIOMUX_NSETTINGS + which; unsigned long irq_flags; - gpiomux_config_t setting; + int status = 0; + + if (!msm_gpiomux_recs) + return -EFAULT; - if (gpio >= GPIOMUX_NGPIOS) + if (gpio >= msm_gpiomux_ngpio) return -EINVAL; spin_lock_irqsave(&gpiomux_lock, irq_flags); - if (active & GPIOMUX_VALID) - cfg->active = active; + if (old_setting) { + if (rec->sets[which] == NULL) + status = 1; + else + *old_setting = *(rec->sets[which]); + } + + if (setting) { + msm_gpiomux_sets[set_slot] = *setting; + rec->sets[which] = &msm_gpiomux_sets[set_slot]; + } else { + rec->sets[which] = NULL; + } + + spin_unlock_irqrestore(&gpiomux_lock, irq_flags); + return status; +} + +int msm_gpiomux_write(unsigned gpio, enum msm_gpiomux_setting which, + struct gpiomux_setting *setting, struct gpiomux_setting *old_setting) +{ + int ret; + unsigned long irq_flags; + struct gpiomux_setting *new_set; + struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio; + + ret = msm_gpiomux_store(gpio, which, setting, old_setting); + if (ret < 0) + return ret; - if (suspended & GPIOMUX_VALID) - cfg->suspended = suspended; + spin_lock_irqsave(&gpiomux_lock, irq_flags); - setting = cfg->ref ? active : suspended; - if (setting & GPIOMUX_VALID) - __msm_gpiomux_write(gpio, setting); + new_set = rec->ref ? rec->sets[GPIOMUX_ACTIVE] : + rec->sets[GPIOMUX_SUSPENDED]; + if (new_set) + __msm_gpiomux_write(gpio, *new_set); spin_unlock_irqrestore(&gpiomux_lock, irq_flags); - return 0; + return ret; } EXPORT_SYMBOL(msm_gpiomux_write); int msm_gpiomux_get(unsigned gpio) { - struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; + struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio; unsigned long irq_flags; - if (gpio >= GPIOMUX_NGPIOS) + if (!msm_gpiomux_recs) + return -EFAULT; + + if (gpio >= msm_gpiomux_ngpio) return -EINVAL; spin_lock_irqsave(&gpiomux_lock, irq_flags); - if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID) - __msm_gpiomux_write(gpio, cfg->active); + if (rec->ref++ == 0 && rec->sets[GPIOMUX_ACTIVE]) + __msm_gpiomux_write(gpio, *rec->sets[GPIOMUX_ACTIVE]); spin_unlock_irqrestore(&gpiomux_lock, irq_flags); return 0; } @@ -81,31 +131,117 @@ EXPORT_SYMBOL(msm_gpiomux_get); int msm_gpiomux_put(unsigned gpio) { - struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; + struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio; unsigned long irq_flags; - if (gpio >= GPIOMUX_NGPIOS) + if (!msm_gpiomux_recs) + return -EFAULT; + + if (gpio >= msm_gpiomux_ngpio) return -EINVAL; spin_lock_irqsave(&gpiomux_lock, irq_flags); - BUG_ON(cfg->ref == 0); - if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID) - __msm_gpiomux_write(gpio, cfg->suspended); + BUG_ON(rec->ref == 0); + if (--rec->ref == 0 && rec->sets[GPIOMUX_SUSPENDED]) + __msm_gpiomux_write(gpio, *rec->sets[GPIOMUX_SUSPENDED]); spin_unlock_irqrestore(&gpiomux_lock, irq_flags); return 0; } EXPORT_SYMBOL(msm_gpiomux_put); -static int __init gpiomux_init(void) +int msm_tlmm_misc_reg_read(enum msm_tlmm_misc_reg misc_reg) +{ + return readl_relaxed(MSM_TLMM_BASE + misc_reg); +} + +void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val) +{ + writel_relaxed(val, MSM_TLMM_BASE + misc_reg); + /* ensure the write completes before returning */ + mb(); +} + +int msm_gpiomux_init(size_t ngpio) { - unsigned n; + if (!ngpio) + return -EINVAL; - for (n = 0; n < GPIOMUX_NGPIOS; ++n) { - msm_gpiomux_configs[n].ref = 0; - if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID)) - continue; - __msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended); + if (msm_gpiomux_recs) + return -EPERM; + + msm_gpiomux_recs = kzalloc(sizeof(struct msm_gpiomux_rec) * ngpio, + GFP_KERNEL); + if (!msm_gpiomux_recs) + return -ENOMEM; + + /* There is no need to zero this memory, as clients will be blindly + * installing settings on top of it. + */ + msm_gpiomux_sets = kmalloc(sizeof(struct gpiomux_setting) * ngpio * + GPIOMUX_NSETTINGS, GFP_KERNEL); + if (!msm_gpiomux_sets) { + kfree(msm_gpiomux_recs); + msm_gpiomux_recs = NULL; + return -ENOMEM; } + + msm_gpiomux_ngpio = ngpio; + return 0; } -postcore_initcall(gpiomux_init); +EXPORT_SYMBOL(msm_gpiomux_init); + +void msm_gpiomux_install_nowrite(struct msm_gpiomux_config *configs, + unsigned nconfigs) +{ + unsigned c, s; + int rc; + + for (c = 0; c < nconfigs; ++c) { + for (s = 0; s < GPIOMUX_NSETTINGS; ++s) { + rc = msm_gpiomux_store(configs[c].gpio, s, + configs[c].settings[s], NULL); + if (rc) + pr_err("%s: write failure: %d\n", __func__, rc); + } + } +} + +void msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs) +{ + unsigned c, s; + int rc; + + for (c = 0; c < nconfigs; ++c) { + for (s = 0; s < GPIOMUX_NSETTINGS; ++s) { + rc = msm_gpiomux_write(configs[c].gpio, s, + configs[c].settings[s], NULL); + if (rc) + pr_err("%s: write failure: %d\n", __func__, rc); + } + } +} +EXPORT_SYMBOL(msm_gpiomux_install); + +int msm_gpiomux_init_dt(void) +{ + int rc; + unsigned int ngpio; + struct device_node *of_gpio_node; + + of_gpio_node = of_find_compatible_node(NULL, NULL, "qcom,msm-gpio"); + if (!of_gpio_node) { + pr_err("%s: Failed to find qcom,msm-gpio node\n", __func__); + return -ENODEV; + } + + rc = of_property_read_u32(of_gpio_node, "ngpio", &ngpio); + if (rc) { + pr_err("%s: Failed to find ngpio property in msm-gpio device node %d\n" + , __func__, rc); + return rc; + } + + return msm_gpiomux_init(ngpio); +} +EXPORT_SYMBOL(msm_gpiomux_init_dt); diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c new file mode 100644 index 000000000000..7e6e1c106ab6 --- /dev/null +++ b/arch/arm/mach-msm/hotplug.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * Copyright (c) 2011-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 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/cpu.h> +#include <linux/notifier.h> +#include <linux/msm_rtb.h> +// AGSTUB +//#include <soc/qcom/spm.h> +#include <soc/qcom/pm.h> + +#include <asm/smp_plat.h> +#include <asm/vfp.h> + +//#include <soc/qcom/jtag.h> + +static cpumask_t cpu_dying_mask; + +static DEFINE_PER_CPU(unsigned int, warm_boot_flag); + +static inline void cpu_enter_lowpower(void) +{ +} + +static inline void cpu_leave_lowpower(void) +{ +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ + /* Just enter wfi for now. TODO: Properly shut off the cpu. */ + for (;;) { + + lpm_cpu_hotplug_enter(cpu); + if (pen_release == cpu_logical_map(cpu)) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * The trouble is, letting people know about this is not really + * possible, since we are currently running incoherently, and + * therefore cannot safely call printk() or anything else + */ + (*spurious)++; + } +} + +int msm_cpu_kill(unsigned int cpu) +{ + int ret = 0; + + if (cpumask_test_and_clear_cpu(cpu, &cpu_dying_mask)) + ret = msm_pm_wait_cpu_shutdown(cpu); + + return ret ? 0 : 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void __ref msm_cpu_die(unsigned int cpu) +{ + int spurious = 0; + + if (unlikely(cpu != smp_processor_id())) { + pr_crit("%s: running on %u, should be %u\n", + __func__, smp_processor_id(), cpu); + BUG(); + } + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu, &spurious); + + pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__); + cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} + +#define CPU_SHIFT 0 +#define CPU_MASK 0xF +#define CPU_OF(n) (((n) & CPU_MASK) << CPU_SHIFT) +#define CPUSET_SHIFT 4 +#define CPUSET_MASK 0xFFFF +#define CPUSET_OF(n) (((n) & CPUSET_MASK) << CPUSET_SHIFT) + +static int hotplug_rtb_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + /* + * Bits [19:4] of the data are the online mask, lower 4 bits are the + * cpu number that is being changed. Additionally, changes to the + * online_mask that will be done by the current hotplug will be made + * even though they aren't necessarily in the online mask yet. + * + * XXX: This design is limited to supporting at most 16 cpus + */ + int this_cpumask = CPUSET_OF(1 << (int)hcpu); + int cpumask = CPUSET_OF(cpumask_bits(cpu_online_mask)[0]); + int cpudata = CPU_OF((int)hcpu) | cpumask; + + switch (action & (~CPU_TASKS_FROZEN)) { + case CPU_STARTING: + uncached_logk(LOGK_HOTPLUG, (void *)(cpudata | this_cpumask)); + break; + case CPU_DYING: + cpumask_set_cpu((unsigned long)hcpu, &cpu_dying_mask); + uncached_logk(LOGK_HOTPLUG, (void *)(cpudata & ~this_cpumask)); + break; + default: + break; + } + + return NOTIFY_OK; +} +static struct notifier_block hotplug_rtb_notifier = { + .notifier_call = hotplug_rtb_callback, +}; + +int msm_platform_secondary_init(unsigned int cpu) +{ + int ret; + unsigned int *warm_boot = &__get_cpu_var(warm_boot_flag); + + if (!(*warm_boot)) { + *warm_boot = 1; + return 0; + } +// msm_jtag_restore_state(); +#if defined(CONFIG_VFP) && defined (CONFIG_CPU_PM) + //vfp_pm_resume(); +#endif + ret = 0; // AGSTUB msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false); + + return ret; +} + +static int __init init_hotplug(void) +{ + return register_hotcpu_notifier(&hotplug_rtb_notifier); +} +early_initcall(init_hotplug); diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h new file mode 100644 index 000000000000..7f6376d16e6c --- /dev/null +++ b/arch/arm/mach-msm/include/mach/board.h @@ -0,0 +1,208 @@ +/* arch/arm/mach-msm/include/mach/board.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2014, The Linux Foundation. All rights reserved. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_BOARD_H +#define __ASM_ARCH_MSM_BOARD_H + +#include <linux/types.h> +#include <linux/input.h> +#include <linux/usb.h> +#include <linux/clkdev.h> +#include <linux/of_platform.h> +//#include <linux/ssbi.h> +//#include <linux/msm-bus.h> + + +struct clk_lookup; + +struct snd_endpoint { + int id; + const char *name; +}; + +struct msm_snd_endpoints { + struct snd_endpoint *endpoints; + unsigned num; +}; + +struct cad_endpoint { + int id; + const char *name; + uint32_t capability; +}; + +struct msm_cad_endpoints { + struct cad_endpoint *endpoints; + unsigned num; +}; + +#define MSM_MAX_DEC_CNT 14 +/* 7k target ADSP information */ +/* Bit 23:0, for codec identification like mp3, wav etc * + * Bit 27:24, for mode identification like tunnel, non tunnel* + * bit 31:28, for operation support like DM, DMA */ +enum msm_adspdec_concurrency { + MSM_ADSP_CODEC_WAV = 0, + MSM_ADSP_CODEC_ADPCM = 1, + MSM_ADSP_CODEC_MP3 = 2, + MSM_ADSP_CODEC_REALAUDIO = 3, + MSM_ADSP_CODEC_WMA = 4, + MSM_ADSP_CODEC_AAC = 5, + MSM_ADSP_CODEC_RESERVED = 6, + MSM_ADSP_CODEC_MIDI = 7, + MSM_ADSP_CODEC_YADPCM = 8, + MSM_ADSP_CODEC_QCELP = 9, + MSM_ADSP_CODEC_AMRNB = 10, + MSM_ADSP_CODEC_AMRWB = 11, + MSM_ADSP_CODEC_EVRC = 12, + MSM_ADSP_CODEC_WMAPRO = 13, + MSM_ADSP_CODEC_AC3 = 23, + MSM_ADSP_MODE_TUNNEL = 24, + MSM_ADSP_MODE_NONTUNNEL = 25, + MSM_ADSP_MODE_LP = 26, + MSM_ADSP_OP_DMA = 28, + MSM_ADSP_OP_DM = 29, +}; + +struct msm_adspdec_info { + const char *module_name; + unsigned module_queueid; + int module_decid; /* objid */ + unsigned nr_codec_support; +}; + +/* Carries information about number codec + * supported if same codec or different codecs + */ +struct dec_instance_table { + uint8_t max_instances_same_dec; + uint8_t max_instances_diff_dec; +}; + +struct msm_adspdec_database { + unsigned num_dec; + unsigned num_concurrency_support; + unsigned int *dec_concurrency_table; /* Bit masked entry to * + * represents codec, mode etc */ + struct msm_adspdec_info *dec_info_list; + struct dec_instance_table *dec_instance_list; +}; + +enum msm_mdp_hw_revision { + MDP_REV_20 = 1, + MDP_REV_22, + MDP_REV_30, + MDP_REV_303, + MDP_REV_31, + MDP_REV_40, + MDP_REV_41, + MDP_REV_42, + MDP_REV_43, + MDP_REV_44, +}; + + +#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE) +struct isp1763_platform_data { + unsigned reset_gpio; + int (*setup_gpio)(int enable); +}; +#endif +/* common init routines for use by arch/arm/mach-msm/board-*.c */ + +#ifdef CONFIG_OF_DEVICE +void msm_8974_init(struct of_dev_auxdata **); +#endif +void msm_add_devices(void); +void msm_8974_add_devices(void); +void msm_8974_add_drivers(void); +void msm_map_common_io(void); +void msm_map_qsd8x50_io(void); +void msm_map_msm8x60_io(void); +void msm_map_msm8960_io(void); +void msm_map_msm8930_io(void); +void msm_map_apq8064_io(void); +void msm_map_msm7x30_io(void); +void msm_map_fsm9xxx_io(void); +void msm_map_fsm9900_io(void); +void fsm9900_init_gpiomux(void); +void fsm9900_rf_init_gpiomux(void); +void msm_map_8974_io(void); +void msm_map_8084_io(void); +void msm_map_mdm9630_io(void); +void msm_map_msmzirc_io(void); +void msm_map_msmsamarium_io(void); +void msm_map_msm8625_io(void); +void msm_map_msm9625_io(void); +void msm_init_irq(void); +void msm_8974_init_irq(void); +void vic_handle_irq(struct pt_regs *regs); +void msm_8974_reserve(void); +void msm_8974_very_early(void); +void msm_8974_init_gpiomux(void); +void apq8084_init_gpiomux(void); +void msm9625_init_gpiomux(void); +void mdm9630_init_gpiomux(void); +void msmsamarium_init_gpiomux(void); +void msm_map_mpq8092_io(void); +void msm_map_msm8916_io(void); +void mpq8092_init_gpiomux(void); +void msm_map_msm8226_io(void); +void msm8226_init_irq(void); +void msm8226_init_gpiomux(void); +void msm8610_init_gpiomux(void); +void msm_map_msm8610_io(void); +void msm8610_init_irq(void); + +/* Dump debug info (states, rate, etc) of clocks */ +#if defined(CONFIG_ARCH_MSM7X27) +void msm_clk_dump_debug_info(void); +#else +static inline void msm_clk_dump_debug_info(void) {} +#endif + +struct mmc_platform_data; +int msm_add_sdcc(unsigned int controller, + struct mmc_platform_data *plat); + +void msm_pm_register_irqs(void); +struct msm_usb_host_platform_data; +int msm_add_host(unsigned int host, + struct msm_usb_host_platform_data *plat); +#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB) \ + || defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_MSM_72K_MODULE) +void msm_hsusb_set_vbus_state(int online); +#else +static inline void msm_hsusb_set_vbus_state(int online) {} +#endif + +void msm_snddev_init(void); +void msm_snddev_init_timpani(void); +void msm_snddev_poweramp_on(void); +void msm_snddev_poweramp_off(void); +void msm_snddev_hsed_voltage_on(void); +void msm_snddev_hsed_voltage_off(void); +void msm_snddev_tx_route_config(void); +void msm_snddev_tx_route_deconfig(void); + +#if defined(CONFIG_MSM_SMD) && defined(CONFIG_DEBUG_FS) +int smd_debugfs_init(void); +#else +static inline int smd_debugfs_init(void) { return 0; } +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/debug_mm.h b/arch/arm/mach-msm/include/mach/debug_mm.h new file mode 100644 index 000000000000..6b27dedee35e --- /dev/null +++ b/arch/arm/mach-msm/include/mach/debug_mm.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2009, 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. + * + */ +#ifndef __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ +#define __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ + +#include <linux/string.h> + +/* The below macro removes the directory path name and retains only the + * file name to avoid long path names in log messages that comes as + * part of __FILE__ to compiler. + */ +#define __MM_FILE__ strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/')+1) : \ + __FILE__ + +#define MM_DBG(fmt, args...) pr_debug("[%s] " fmt,\ + __func__, ##args) + +#define MM_INFO(fmt, args...) pr_info("[%s:%s] " fmt,\ + __MM_FILE__, __func__, ##args) + +#define MM_ERR(fmt, args...) pr_err("[%s:%s] " fmt,\ + __MM_FILE__, __func__, ##args) +#endif /* __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ */ diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index a72d48d42342..31dde30d8582 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -1,6 +1,7 @@ /* linux/include/asm-arm/arch-msm/dma.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -14,8 +15,14 @@ */ #ifndef __ASM_ARCH_MSM_DMA_H +#define __ASM_ARCH_MSM_DMA_H #include <linux/list.h> +#include <mach/msm_iomap.h> + +#if defined(CONFIG_ARCH_FSM9XXX) +#include <mach/dma-fsm9xxx.h> +#endif struct msm_dmov_errdata { uint32_t flush[6]; @@ -27,46 +34,170 @@ struct msm_dmov_cmd { void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result, struct msm_dmov_errdata *err); - void (*execute_func)(struct msm_dmov_cmd *cmd); - void *data; + void (*exec_func)(struct msm_dmov_cmd *cmd); + struct work_struct work; + unsigned id; /* For internal use */ + void *user; /* Pointer for caller's reference */ + u8 toflush; +}; + +struct msm_dmov_pdata { + int sd; + size_t sd_size; }; -#ifndef CONFIG_ARCH_MSM8X60 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); -void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful); +void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd); +void msm_dmov_flush(unsigned int id, int graceful); int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); -#else -static inline -void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) { } -static inline -void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) { } -static inline -int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) { return -EIO; } -#endif +#define DMOV_CRCIS_PER_CONF 10 + +#define DMOV_ADDR(off, ch) ((off) + ((ch) << 2)) + +#define DMOV_CMD_PTR(ch) DMOV_ADDR(0x000, ch) #define DMOV_CMD_LIST (0 << 29) /* does not work */ #define DMOV_CMD_PTR_LIST (1 << 29) /* works */ #define DMOV_CMD_INPUT_CFG (2 << 29) /* untested */ #define DMOV_CMD_OUTPUT_CFG (3 << 29) /* untested */ #define DMOV_CMD_ADDR(addr) ((addr) >> 3) +#define DMOV_RSLT(ch) DMOV_ADDR(0x040, ch) #define DMOV_RSLT_VALID (1 << 31) /* 0 == host has empties result fifo */ #define DMOV_RSLT_ERROR (1 << 3) #define DMOV_RSLT_FLUSH (1 << 2) #define DMOV_RSLT_DONE (1 << 1) /* top pointer done */ #define DMOV_RSLT_USER (1 << 0) /* command with FR force result */ +#define DMOV_FLUSH0(ch) DMOV_ADDR(0x080, ch) +#define DMOV_FLUSH1(ch) DMOV_ADDR(0x0C0, ch) +#define DMOV_FLUSH2(ch) DMOV_ADDR(0x100, ch) +#define DMOV_FLUSH3(ch) DMOV_ADDR(0x140, ch) +#define DMOV_FLUSH4(ch) DMOV_ADDR(0x180, ch) +#define DMOV_FLUSH5(ch) DMOV_ADDR(0x1C0, ch) +#define DMOV_FLUSH_TYPE (1 << 31) + +#define DMOV_STATUS(ch) DMOV_ADDR(0x200, ch) #define DMOV_STATUS_RSLT_COUNT(n) (((n) >> 29)) #define DMOV_STATUS_CMD_COUNT(n) (((n) >> 27) & 3) #define DMOV_STATUS_RSLT_VALID (1 << 1) #define DMOV_STATUS_CMD_PTR_RDY (1 << 0) -#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2) -#define DMOV_CONFIG_FORCE_FLUSH_RSLT (1 << 1) -#define DMOV_CONFIG_IRQ_EN (1 << 0) +#define DMOV_CONF(ch) DMOV_ADDR(0x240, ch) +#define DMOV_CONF_SD(sd) (((sd & 4) << 11) | ((sd & 3) << 4)) +#define DMOV_CONF_IRQ_EN (1 << 6) +#define DMOV_CONF_FORCE_RSLT_EN (1 << 7) +#define DMOV_CONF_SHADOW_EN (1 << 12) +#define DMOV_CONF_MPU_DISABLE (1 << 11) +#define DMOV_CONF_PRIORITY(n) (n << 0) + +#define DMOV_DBG_ERR(ci) DMOV_ADDR(0x280, ci) + +#define DMOV_RSLT_CONF(ch) DMOV_ADDR(0x300, ch) +#define DMOV_RSLT_CONF_FORCE_TOP_PTR_RSLT (1 << 2) +#define DMOV_RSLT_CONF_FORCE_FLUSH_RSLT (1 << 1) +#define DMOV_RSLT_CONF_IRQ_EN (1 << 0) + +#define DMOV_ISR DMOV_ADDR(0x380, 0) + +#define DMOV_CI_CONF(ci) DMOV_ADDR(0x390, ci) +#define DMOV_CI_CONF_RANGE_END(n) ((n) << 24) +#define DMOV_CI_CONF_RANGE_START(n) ((n) << 16) +#define DMOV_CI_CONF_MAX_BURST(n) ((n) << 0) + +#define DMOV_CI_DBG_ERR(ci) DMOV_ADDR(0x3B0, ci) + +#define DMOV_CRCI_CONF0 DMOV_ADDR(0x3D0, 0) +#define DMOV_CRCI_CONF1 DMOV_ADDR(0x3D4, 0) +#define DMOV_CRCI_CONF0_SD(crci, sd) (sd << (crci*3)) +#define DMOV_CRCI_CONF1_SD(crci, sd) (sd << ((crci-DMOV_CRCIS_PER_CONF)*3)) + +#define DMOV_CRCI_CTL(crci) DMOV_ADDR(0x400, crci) +#define DMOV_CRCI_CTL_BLK_SZ(n) ((n) << 0) +#define DMOV_CRCI_CTL_RST (1 << 17) +#define DMOV_CRCI_MUX (1 << 18) /* channel assignments */ +/* + * Format of CRCI numbers: crci number + (muxsel << 4) + */ + +#if defined(CONFIG_ARCH_MSM8X60) +#define DMOV_GP_CHAN 15 + +#define DMOV_NAND_CHAN 17 +#define DMOV_NAND_CHAN_MODEM 26 +#define DMOV_NAND_CHAN_Q6 27 +#define DMOV_NAND_CRCI_CMD 15 +#define DMOV_NAND_CRCI_DATA 3 + +#define DMOV_CE_IN_CHAN 2 +#define DMOV_CE_IN_CRCI 4 + +#define DMOV_CE_OUT_CHAN 3 +#define DMOV_CE_OUT_CRCI 5 + +#define DMOV_CE_HASH_CRCI 15 + +#define DMOV_SDC1_CHAN 18 +#define DMOV_SDC1_CRCI 1 + +#define DMOV_SDC2_CHAN 19 +#define DMOV_SDC2_CRCI 4 + +#define DMOV_SDC3_CHAN 20 +#define DMOV_SDC3_CRCI 2 + +#define DMOV_SDC4_CHAN 21 +#define DMOV_SDC4_CRCI 5 + +#define DMOV_SDC5_CHAN 21 +#define DMOV_SDC5_CRCI 14 + +#define DMOV_TSIF_CHAN 4 +#define DMOV_TSIF_CRCI 6 + +#define DMOV_HSUART1_TX_CHAN 22 +#define DMOV_HSUART1_TX_CRCI 8 + +#define DMOV_HSUART1_RX_CHAN 23 +#define DMOV_HSUART1_RX_CRCI 9 + +#define DMOV_HSUART2_TX_CHAN 8 +#define DMOV_HSUART2_TX_CRCI 13 + +#define DMOV_HSUART2_RX_CHAN 8 +#define DMOV_HSUART2_RX_CRCI 14 + +#elif defined(CONFIG_ARCH_MSM9615) + +#define DMOV_GP_CHAN 4 + +#define DMOV_CE_IN_CHAN 0 +#define DMOV_CE_IN_CRCI 12 + +#define DMOV_CE_OUT_CHAN 1 +#define DMOV_CE_OUT_CRCI 13 + +#define DMOV_NAND_CHAN 3 +#define DMOV_NAND_CRCI_CMD 15 +#define DMOV_NAND_CRCI_DATA 3 + +#elif defined(CONFIG_ARCH_FSM9XXX) +/* defined in dma-fsm9xxx.h */ + +#else +#define DMOV_GP_CHAN 4 + +#define DMOV_CE_IN_CHAN 5 +#define DMOV_CE_IN_CRCI 1 + +#define DMOV_CE_OUT_CHAN 6 +#define DMOV_CE_OUT_CRCI 2 + +#define DMOV_CE_HASH_CRCI 3 + #define DMOV_NAND_CHAN 7 #define DMOV_NAND_CRCI_CMD 5 #define DMOV_NAND_CRCI_DATA 4 @@ -77,11 +208,47 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) { return -EIO; } #define DMOV_SDC2_CHAN 8 #define DMOV_SDC2_CRCI 7 +#define DMOV_SDC3_CHAN 8 +#define DMOV_SDC3_CRCI 12 + +#define DMOV_SDC4_CHAN 8 +#define DMOV_SDC4_CRCI 13 + #define DMOV_TSIF_CHAN 10 #define DMOV_TSIF_CRCI 10 #define DMOV_USB_CHAN 11 +#define DMOV_HSUART1_TX_CHAN 4 +#define DMOV_HSUART1_TX_CRCI 8 + +#define DMOV_HSUART1_RX_CHAN 9 +#define DMOV_HSUART1_RX_CRCI 9 + +#define DMOV_HSUART2_TX_CHAN 4 +#define DMOV_HSUART2_TX_CRCI 14 + +#define DMOV_HSUART2_RX_CHAN 11 +#define DMOV_HSUART2_RX_CRCI 15 +#endif + +/* channels for APQ8064 */ +#define DMOV8064_CE_IN_CHAN 0 +#define DMOV8064_CE_IN_CRCI 14 + +#define DMOV8064_CE_OUT_CHAN 1 +#define DMOV8064_CE_OUT_CRCI 15 + +#define DMOV8064_TSIF_CHAN 4 +#define DMOV8064_TSIF_CRCI 1 + +/* channels for MPQ8064 */ +#define DMOV_MPQ8064_HSUART_GSBI6_TX_CHAN 7 +#define DMOV_MPQ8064_HSUART_GSBI6_TX_CRCI 6 + +#define DMOV_MPQ8064_HSUART_GSBI6_RX_CHAN 6 +#define DMOV_MPQ8064_HSUART_GSBI6_RX_CRCI 11 + /* no client rate control ifc (eg, ram) */ #define DMOV_NONE_CRCI 0 diff --git a/arch/arm/mach-msm/include/mach/entry-macro.S b/arch/arm/mach-msm/include/mach/entry-macro.S index f2ae9087f654..5b43f2a6ecb4 100644 --- a/arch/arm/mach-msm/include/mach/entry-macro.S +++ b/arch/arm/mach-msm/include/mach/entry-macro.S @@ -1,4 +1,5 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +/* + * Copyright (c) 2009-2010, 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 @@ -8,12 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * */ #if !defined(CONFIG_ARM_GIC) diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h new file mode 100644 index 000000000000..1cfea4959856 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#ifndef __ASM_ARCH_MSM_GPIO_H +#define __ASM_ARCH_MSM_GPIO_H + +#define ARCH_NR_GPIOS 1024 + +#include <linux/interrupt.h> +#include <asm-generic/gpio.h> +#include <mach/irqs.h> + +#define FIRST_BOARD_GPIO NR_GPIO_IRQS + + +/** + * struct msm_gpio - GPIO pin description + * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config() + * @label - textual label + * + * Usually, GPIO's are operated by sets. + * This struct accumulate all GPIO information in single source + * and facilitete group operations provided by msm_gpios_xxx() + */ +struct msm_gpio { + u32 gpio_cfg; + const char *label; +}; + +struct msm_gpio_pdata { + int ngpio; + int direct_connect_irqs; +}; + +/** + * msm_gpios_request_enable() - request and enable set of GPIOs + * + * Request and configure set of GPIO's + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_request_enable(const struct msm_gpio *table, int size); + +/** + * msm_gpios_disable_free() - disable and free set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_disable_free(const struct msm_gpio *table, int size); + +/** + * msm_gpios_request() - request set of GPIOs + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_request(const struct msm_gpio *table, int size); + +/** + * msm_gpios_free() - free set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_free(const struct msm_gpio *table, int size); + +/** + * msm_gpios_enable() - enable set of GPIOs + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_enable(const struct msm_gpio *table, int size); + +/** + * msm_gpios_disable() - disable set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_disable(const struct msm_gpio *table, int size); + +/** + * msm_gpios_show_resume_irq() - show the interrupts that could have triggered + * resume + */ +void msm_gpio_show_resume_irq(void); + +/* GPIO TLMM (Top Level Multiplexing) Definitions */ + +/* GPIO TLMM: Function -- GPIO specific */ + +/* GPIO TLMM: Direction */ +enum { + GPIO_CFG_INPUT, + GPIO_CFG_OUTPUT, +}; + +/* GPIO TLMM: Pullup/Pulldown */ +enum { + GPIO_CFG_NO_PULL, + GPIO_CFG_PULL_DOWN, + GPIO_CFG_KEEPER, + GPIO_CFG_PULL_UP, +}; + +/* GPIO TLMM: Drive Strength */ +enum { + GPIO_CFG_2MA, + GPIO_CFG_4MA, + GPIO_CFG_6MA, + GPIO_CFG_8MA, + GPIO_CFG_10MA, + GPIO_CFG_12MA, + GPIO_CFG_14MA, + GPIO_CFG_16MA, +}; + +enum { + GPIO_CFG_ENABLE, + GPIO_CFG_DISABLE, +}; + +#define GPIO_CFG(gpio, func, dir, pull, drvstr) \ + ((((gpio) & 0x3FF) << 4) | \ + ((func) & 0xf) | \ + (((dir) & 0x1) << 14) | \ + (((pull) & 0x3) << 15) | \ + (((drvstr) & 0xF) << 17)) + +/** + * extract GPIO pin from bit-field used for gpio_tlmm_config + */ +#define GPIO_PIN(gpio_cfg) (((gpio_cfg) >> 4) & 0x3ff) +#define GPIO_FUNC(gpio_cfg) (((gpio_cfg) >> 0) & 0xf) +#define GPIO_DIR(gpio_cfg) (((gpio_cfg) >> 14) & 0x1) +#define GPIO_PULL(gpio_cfg) (((gpio_cfg) >> 15) & 0x3) +#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf) + +int gpio_tlmm_config(unsigned config, unsigned disable); + +enum msm_tlmm_hdrive_tgt { + TLMM_HDRV_SDC4_CLK = 0, + TLMM_HDRV_SDC4_CMD, + TLMM_HDRV_SDC4_DATA, + TLMM_HDRV_SDC3_CLK, + TLMM_HDRV_SDC3_CMD, + TLMM_HDRV_SDC3_DATA, + TLMM_HDRV_SDC2_CLK, + TLMM_HDRV_SDC2_CMD, + TLMM_HDRV_SDC2_DATA, + TLMM_HDRV_SDC1_CLK, + TLMM_HDRV_SDC1_CMD, + TLMM_HDRV_SDC1_DATA, +}; + +enum msm_tlmm_pull_tgt { + TLMM_PULL_SDC4_CLK = 0, + TLMM_PULL_SDC4_CMD, + TLMM_PULL_SDC4_DATA, + TLMM_PULL_SDC3_CLK, + TLMM_PULL_SDC3_CMD, + TLMM_PULL_SDC3_DATA, + TLMM_PULL_SDC2_CLK, + TLMM_PULL_SDC2_CMD, + TLMM_PULL_SDC2_DATA, + TLMM_PULL_SDC1_CLK, + TLMM_PULL_SDC1_CMD, + TLMM_PULL_SDC1_DATA, + TLMM_PULL_SDC1_RCLK, +}; + +#if defined(CONFIG_GPIO_MSM_V2) || defined(CONFIG_GPIO_MSM_V3) +void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str); +void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull); + +/* + * A GPIO can be set as a direct-connect IRQ. This can be used to bypass + * the normal summary-interrupt mechanism for those GPIO lines deemed to be + * higher priority or otherwise worthy of special treatment, but resources + * are limited: only a few DC interrupt lines are available. + * Care must be taken when usurping a GPIO in this manner, as the summary + * interrupt controller has no idea that the GPIO has been taken away from it. + * Clients can still register to receive the summary interrupt assigned + * to that GPIO, which will uninstall it as a direct connect IRQ with + * no warning. + * + * The irq passed to this function is the DC IRQ number, not the + * irq number seen by the scorpion when the interrupt triggers. For example, + * if 0 is specified, then when DC IRQ 0 triggers, the scorpion will see + * interrupt TLMM_MSM_DIR_CONN_IRQ_0. + * + * input_polarity parameter specifies when the gpio should raise the direct + * interrupt. A value of 0 means that it is active low, anything else means + * active high + * + */ +int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq, + unsigned int input_polarity); +#else +static inline void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, + int drv_str) {} +static inline void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull) {} +static inline int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq, + unsigned int input_polarity) +{ + return -ENOSYS; +} +#endif + +#endif /* __ASM_ARCH_MSM_GPIO_H */ diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h new file mode 100644 index 000000000000..2278677bac17 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/gpiomux.h @@ -0,0 +1,216 @@ +/* Copyright (c) 2010-2011,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. + */ +#ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_H +#define __ARCH_ARM_MACH_MSM_GPIOMUX_H + +#include <linux/bitops.h> +#include <linux/errno.h> + +enum msm_gpiomux_setting { + GPIOMUX_ACTIVE = 0, + GPIOMUX_SUSPENDED, + GPIOMUX_NSETTINGS +}; + +enum gpiomux_drv { + GPIOMUX_DRV_2MA = 0, + GPIOMUX_DRV_4MA, + GPIOMUX_DRV_6MA, + GPIOMUX_DRV_8MA, + GPIOMUX_DRV_10MA, + GPIOMUX_DRV_12MA, + GPIOMUX_DRV_14MA, + GPIOMUX_DRV_16MA, +}; + +enum gpiomux_func { + GPIOMUX_FUNC_GPIO = 0, + GPIOMUX_FUNC_1, + GPIOMUX_FUNC_2, + GPIOMUX_FUNC_3, + GPIOMUX_FUNC_4, + GPIOMUX_FUNC_5, + GPIOMUX_FUNC_6, + GPIOMUX_FUNC_7, + GPIOMUX_FUNC_8, + GPIOMUX_FUNC_9, + GPIOMUX_FUNC_A, + GPIOMUX_FUNC_B, + GPIOMUX_FUNC_C, + GPIOMUX_FUNC_D, + GPIOMUX_FUNC_E, + GPIOMUX_FUNC_F, +}; + +enum gpiomux_pull { + GPIOMUX_PULL_NONE = 0, + GPIOMUX_PULL_DOWN, + GPIOMUX_PULL_KEEPER, + GPIOMUX_PULL_UP, +}; + +/* Direction settings are only meaningful when GPIOMUX_FUNC_GPIO is selected. + * This element is ignored for all other FUNC selections, as the output- + * enable pin is not under software control in those cases. See the SWI + * for your target for more details. + */ +enum gpiomux_dir { + GPIOMUX_IN = 0, + GPIOMUX_OUT_HIGH, + GPIOMUX_OUT_LOW, +}; + +struct gpiomux_setting { + enum gpiomux_func func; + enum gpiomux_drv drv; + enum gpiomux_pull pull; + enum gpiomux_dir dir; +}; + +/** + * struct msm_gpiomux_config: gpiomux settings for one gpio line. + * + * A complete gpiomux config is the combination of a drive-strength, + * function, pull, and (sometimes) direction. For functions other than GPIO, + * the input/output setting is hard-wired according to the function. + * + * @gpio: The index number of the gpio being described. + * @settings: The settings to be installed, specifically: + * GPIOMUX_ACTIVE: The setting to be installed when the + * line is active, or its reference count is > 0. + * GPIOMUX_SUSPENDED: The setting to be installed when + * the line is suspended, or its reference count is 0. + */ +struct msm_gpiomux_config { + unsigned gpio; + struct gpiomux_setting *settings[GPIOMUX_NSETTINGS]; +}; + +/** + * struct msm_gpiomux_configs: a collection of gpiomux configs. + * + * It is so common to manage blocks of gpiomux configs that the data structure + * for doing so has been standardized here as a convenience. + * + * @cfg: A pointer to the first config in an array of configs. + * @ncfg: The number of configs in the array. + */ +struct msm_gpiomux_configs { + struct msm_gpiomux_config *cfg; + size_t ncfg; +}; + +/* Provide an enum and an API to write to misc TLMM registers */ +enum msm_tlmm_misc_reg { + TLMM_ETM_MODE_REG = 0x2014, + TLMM_SDC2_HDRV_PULL_CTL = 0x2048, + TLMM_SPARE_REG = 0x2024, + TLMM_CDC_HDRV_CTL = 0x2054, + TLMM_CDC_HDRV_PULL_CTL = 0x2058, +}; + +#ifdef CONFIG_MSM_GPIOMUX + +/* Before using gpiomux, initialize the subsystem by telling it how many + * gpios are going to be managed. Calling any other gpiomux functions before + * msm_gpiomux_init is unsupported. + */ +int msm_gpiomux_init(size_t ngpio); + +/* DT Variant of msm_gpiomux_init. This will look up the number of gpios from + * device tree rather than relying on NR_GPIO_IRQS + */ +int msm_gpiomux_init_dt(void); + +/* Install a block of gpiomux configurations in gpiomux. This is functionally + * identical to calling msm_gpiomux_write many times. + */ +void msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs); + +/* Install a block of gpiomux configurations in gpiomux. Do not however write + * to hardware. Just store the settings to be retrieved at a later time + */ +void msm_gpiomux_install_nowrite(struct msm_gpiomux_config *configs, + unsigned nconfigs); + +/* Increment a gpio's reference count, possibly activating the line. */ +int __must_check msm_gpiomux_get(unsigned gpio); + +/* Decrement a gpio's reference count, possibly suspending the line. */ +int msm_gpiomux_put(unsigned gpio); + +/* Install a new setting in a gpio. To erase a slot, use NULL. + * The old setting that was overwritten can be passed back to the caller + * old_setting can be NULL if the caller is not interested in the previous + * setting + * If a previous setting was not available to return (NULL configuration) + * - the function returns 1 + * else function returns 0 + */ +int msm_gpiomux_write(unsigned gpio, enum msm_gpiomux_setting which, + struct gpiomux_setting *setting, struct gpiomux_setting *old_setting); + +/* Architecture-internal function for use by the framework only. + * This function can assume the following: + * - the gpio value has passed a bounds-check + * - the gpiomux spinlock has been obtained + * + * This function is not for public consumption. External users + * should use msm_gpiomux_write. + */ +void __msm_gpiomux_write(unsigned gpio, struct gpiomux_setting val); + +/* Functions that provide an API for drivers to read from and write to + * miscellaneous TLMM registers. + */ +int msm_tlmm_misc_reg_read(enum msm_tlmm_misc_reg misc_reg); + +void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val); + +#else +static inline int msm_gpiomux_init(size_t ngpio) +{ + return -ENOSYS; +} + +static inline void +msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs) {} + +static inline int __must_check msm_gpiomux_get(unsigned gpio) +{ + return -ENOSYS; +} + +static inline int msm_gpiomux_put(unsigned gpio) +{ + return -ENOSYS; +} + +static inline int msm_gpiomux_write(unsigned gpio, + enum msm_gpiomux_setting which, struct gpiomux_setting *setting, + struct gpiomux_setting *old_setting) +{ + return -ENOSYS; +} + +static inline int msm_tlmm_misc_reg_read(enum msm_tlmm_misc_reg misc_reg) +{ + return -ENOSYS; +} + +static inline void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, + int val) +{ +} + +#endif +#endif diff --git a/arch/arm/mach-msm/include/mach/hardware.h b/arch/arm/mach-msm/include/mach/hardware.h index 2d126091ae41..fbf289e209f8 100644 --- a/arch/arm/mach-msm/include/mach/hardware.h +++ b/arch/arm/mach-msm/include/mach/hardware.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/include/mach/hardware.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2012, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -14,5 +15,8 @@ */ #ifndef __ASM_ARCH_MSM_HARDWARE_H +#define __ASM_ARCH_MSM_HARDWARE_H + +#define pcibios_assign_all_busses() 1 #endif diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h new file mode 100644 index 000000000000..445e17567b10 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/io.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/arch/arm/mach-msm/include/mach/ipc_bridge.h b/arch/arm/mach-msm/include/mach/ipc_bridge.h new file mode 100644 index 000000000000..a0e12d6f9af5 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/ipc_bridge.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2013 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. + */ + +#ifndef __MSM_IPC_BRIDGE_H__ +#define __MSM_IPC_BRIDGE_H__ + +#include <linux/platform_device.h> + +/* + * The IPC bridge driver adds a IPC bridge platform device when the + * underlying transport is ready. The IPC transport driver acts as a + * platform driver for this device. The platform data is populated by + * IPC bridge driver to facilitate I/O. The callback functions are + * passed in platform data to avoid export functions. This would allow + * different bridge drivers to exist in the kernel. The IPC bridge driver + * removes the platform device when the underly transport is no longer + * available. It typically happens during shutdown and remote processor's + * subsystem restart. + */ + +/** + * struct ipc_bridge_platform_data - platform device data for IPC + * transport driver. + * @max_read_size: The maximum possible read size. + * @max_write_size: The maximum possible write size. + * @open: The open must be called before starting I/O. The IPC bridge + * driver use the platform device pointer to identify the + * underlying transport channel. The IPC bridge driver may + * notify that remote processor that it is ready to receive + * data. Returns 0 upon success and appropriate error code + * upon failure. + * @read: The read is done synchronously and should be called from process + * context. Returns the number of bytes read from remote + * processor or error code upon failure. The IPC transport + * driver may pass the buffer of max_read_size length if the + * available data size is not known in advance. + * @write: The write is done synchronously and should be called from process + * context. The IPC bridge driver uses the same buffer for DMA + * to avoid additional memcpy. So it must be physically contiguous. + * Returns the number of bytes written or error code upon failure. + * @close: The close must be called when the IPC bridge platform device + * is removed. The IPC transport driver may call close when + * it is no longer required to communicate with remote processor. + */ +struct ipc_bridge_platform_data { + unsigned int max_read_size; + unsigned int max_write_size; + int (*open)(struct platform_device *pdev); + int (*read)(struct platform_device *pdev, char *buf, + unsigned int count); + int (*write)(struct platform_device *pdev, char *buf, + unsigned int count); + void (*close)(struct platform_device *pdev); +}; + +#endif diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h new file mode 100644 index 000000000000..fd72a23d77ed --- /dev/null +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -0,0 +1,57 @@ +/* arch/arm/mach-msm/include/mach/memory.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H +#include <linux/types.h> + +/* physical offset of RAM */ +#define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) + +#ifndef __ASSEMBLY__ +int msm_get_memory_type_from_name(const char *memtype_name); + +#ifdef CONFIG_CACHE_L2X0 +extern void l2x0_cache_sync(void); +#define finish_arch_switch(prev) do { l2x0_cache_sync(); } while (0) +#endif + +#define MAX_HOLE_ADDRESS (PHYS_OFFSET + 0x10000000) +/* + * Need a temporary unique variable that no one will ever see to + * hold the compat string. Line number gives this easily. + * Need another layer of indirection to get __LINE__ to expand + * properly as opposed to appending and ending up with + * __compat___LINE__ + */ +#define __CONCAT(a, b) ___CONCAT(a, b) +#define ___CONCAT(a, b) a ## b + +#define EXPORT_COMPAT(com) \ +static char *__CONCAT(__compat_, __LINE__) __used \ + __attribute((__section__(".exportcompat.init"))) = com + +extern char *__compat_exports_start[]; +extern char *__compat_exports_end[]; + +#endif + +#if defined CONFIG_ARCH_MSM_SCORPION || defined CONFIG_ARCH_MSM_KRAIT +#define arch_has_speculative_dfetch() 1 +#endif + +#endif + +#define CONSISTENT_DMA_SIZE (SZ_1M * 14) diff --git a/arch/arm/mach-msm/include/mach/mpp.h b/arch/arm/mach-msm/include/mach/mpp.h new file mode 100644 index 000000000000..1198fd3c972e --- /dev/null +++ b/arch/arm/mach-msm/include/mach/mpp.h @@ -0,0 +1,262 @@ +/* Copyright (c) 2008-2013, 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_MPP_H +#define __ARCH_ARM_MACH_MSM_MPP_H + +#define MPPS 22 + +/* Digital Logical Output Level */ +enum { + MPP_DLOGIC_LVL_MSME, + MPP_DLOGIC_LVL_MSMP, + MPP_DLOGIC_LVL_RUIM, + MPP_DLOGIC_LVL_MMC, + MPP_DLOGIC_LVL_VDD, +}; + +/* Digital Logical Output Control Value */ +enum { + MPP_DLOGIC_OUT_CTRL_LOW, + MPP_DLOGIC_OUT_CTRL_HIGH, + MPP_DLOGIC_OUT_CTRL_MPP, /* MPP Output = MPP Input */ + MPP_DLOGIC_OUT_CTRL_NOT_MPP, /* MPP Output = Inverted MPP Input */ +}; + +/* Digital Logical Input Value */ +enum { + MPP_DLOGIC_IN_DBUS_NONE, + MPP_DLOGIC_IN_DBUS_1, + MPP_DLOGIC_IN_DBUS_2, + MPP_DLOGIC_IN_DBUS_3, +}; + +#define MPP_CFG(level, control) ((((level) & 0x0FFFF) << 16) | \ + ((control) & 0x0FFFF)) +#define MPP_CFG_INPUT(level, dbus) ((((level) & 0x0FFFF) << 16) | \ + ((dbus) & 0x0FFFF)) + +/* Use mpp number starting from 0 */ +int mpp_config_digital_out(unsigned mpp, unsigned config); +int mpp_config_digital_in(unsigned mpp, unsigned config); + +/* PM8058/PM8901 definitions */ + +/* APIs */ +static inline int pm8058_mpp_config(unsigned mpp, unsigned type, + unsigned level, unsigned control) +{ + return -EINVAL; +} + +static inline int pm8901_mpp_config(unsigned mpp, unsigned type, + unsigned level, unsigned control) +{ + return -EINVAL; +} + +/* MPP Type: type */ +#define PM_MPP_TYPE_D_INPUT 0 +#define PM_MPP_TYPE_D_OUTPUT 1 +#define PM_MPP_TYPE_D_BI_DIR 2 +#define PM_MPP_TYPE_A_INPUT 3 +#define PM_MPP_TYPE_A_OUTPUT 4 +#define PM_MPP_TYPE_SINK 5 +#define PM_MPP_TYPE_DTEST_SINK 6 +#define PM_MPP_TYPE_DTEST_OUTPUT 7 + + +/* Digital Input/Output: level [8058] */ +#define PM8058_MPP_DIG_LEVEL_VPH 0 +#define PM8058_MPP_DIG_LEVEL_S3 1 +#define PM8058_MPP_DIG_LEVEL_L2 2 +#define PM8058_MPP_DIG_LEVEL_L3 3 + +/* Digital Input/Output: level [8901] */ +#define PM8901_MPP_DIG_LEVEL_MSMIO 0 +#define PM8901_MPP_DIG_LEVEL_DIG 1 +#define PM8901_MPP_DIG_LEVEL_L5 2 +#define PM8901_MPP_DIG_LEVEL_S4 3 +#define PM8901_MPP_DIG_LEVEL_VPH 4 + +/* Digital Input: control */ +#define PM_MPP_DIN_TO_INT 0 +#define PM_MPP_DIN_TO_DBUS1 1 +#define PM_MPP_DIN_TO_DBUS2 2 +#define PM_MPP_DIN_TO_DBUS3 3 + +/* Digital Output: control */ +#define PM_MPP_DOUT_CTL_LOW 0 +#define PM_MPP_DOUT_CTL_HIGH 1 +#define PM_MPP_DOUT_CTL_MPP 2 +#define PM_MPP_DOUT_CTL_INV_MPP 3 + +/* Bidirectional: control */ +#define PM_MPP_BI_PULLUP_1KOHM 0 +#define PM_MPP_BI_PULLUP_OPEN 1 +#define PM_MPP_BI_PULLUP_10KOHM 2 +#define PM_MPP_BI_PULLUP_30KOHM 3 + +/* Analog Input: level */ +#define PM_MPP_AIN_AMUX_CH5 0 +#define PM_MPP_AIN_AMUX_CH6 1 +#define PM_MPP_AIN_AMUX_CH7 2 +#define PM_MPP_AIN_AMUX_CH8 3 +#define PM_MPP_AIN_AMUX_CH9 4 +#define PM_MPP_AIN_AMUX_ABUS1 5 +#define PM_MPP_AIN_AMUX_ABUS2 6 +#define PM_MPP_AIN_AMUX_ABUS3 7 + +/* Analog Output: level */ +#define PM_MPP_AOUT_LVL_1V25 0 +#define PM_MPP_AOUT_LVL_1V25_2 1 +#define PM_MPP_AOUT_LVL_0V625 2 +#define PM_MPP_AOUT_LVL_0V3125 3 +#define PM_MPP_AOUT_LVL_MPP 4 +#define PM_MPP_AOUT_LVL_ABUS1 5 +#define PM_MPP_AOUT_LVL_ABUS2 6 +#define PM_MPP_AOUT_LVL_ABUS3 7 + +/* Analog Output: control */ +#define PM_MPP_AOUT_CTL_DISABLE 0 +#define PM_MPP_AOUT_CTL_ENABLE 1 +#define PM_MPP_AOUT_CTL_MPP_HIGH_EN 2 +#define PM_MPP_AOUT_CTL_MPP_LOW_EN 3 + +/* Current Sink: level */ +#define PM_MPP_CS_OUT_5MA 0 +#define PM_MPP_CS_OUT_10MA 1 +#define PM_MPP_CS_OUT_15MA 2 +#define PM_MPP_CS_OUT_20MA 3 +#define PM_MPP_CS_OUT_25MA 4 +#define PM_MPP_CS_OUT_30MA 5 +#define PM_MPP_CS_OUT_35MA 6 +#define PM_MPP_CS_OUT_40MA 7 + +/* Current Sink: control */ +#define PM_MPP_CS_CTL_DISABLE 0 +#define PM_MPP_CS_CTL_ENABLE 1 +#define PM_MPP_CS_CTL_MPP_HIGH_EN 2 +#define PM_MPP_CS_CTL_MPP_LOW_EN 3 + +/* DTEST Current Sink: control */ +#define PM_MPP_DTEST_CS_CTL_EN1 0 +#define PM_MPP_DTEST_CS_CTL_EN2 1 +#define PM_MPP_DTEST_CS_CTL_EN3 2 +#define PM_MPP_DTEST_CS_CTL_EN4 3 + +/* DTEST Digital Output: control */ +#define PM_MPP_DTEST_DBUS1 0 +#define PM_MPP_DTEST_DBUS2 1 +#define PM_MPP_DTEST_DBUS3 2 +#define PM_MPP_DTEST_DBUS4 3 + +/* Helper APIs */ +static inline int pm8058_mpp_config_digital_in(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_D_INPUT, level, control); +} + +static inline int pm8058_mpp_config_digital_out(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_D_OUTPUT, level, control); +} + +static inline int pm8058_mpp_config_bi_dir(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_D_BI_DIR, level, control); +} + +static inline int pm8058_mpp_config_analog_input(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_A_INPUT, level, control); +} + +static inline int pm8058_mpp_config_analog_output(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_A_OUTPUT, level, control); +} + +static inline int pm8058_mpp_config_current_sink(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_SINK, level, control); +} + +static inline int pm8058_mpp_config_dtest_sink(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_DTEST_SINK, level, control); +} + +static inline int pm8058_mpp_config_dtest_output(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8058_mpp_config(mpp, PM_MPP_TYPE_DTEST_OUTPUT, + level, control); +} + +static inline int pm8901_mpp_config_digital_in(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_D_INPUT, level, control); +} + +static inline int pm8901_mpp_config_digital_out(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_D_OUTPUT, level, control); +} + +static inline int pm8901_mpp_config_bi_dir(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_D_BI_DIR, level, control); +} + +static inline int pm8901_mpp_config_analog_input(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_A_INPUT, level, control); +} + +static inline int pm8901_mpp_config_analog_output(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_A_OUTPUT, level, control); +} + +static inline int pm8901_mpp_config_current_sink(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_SINK, level, control); +} + +static inline int pm8901_mpp_config_dtest_sink(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_DTEST_SINK, level, control); +} + +static inline int pm8901_mpp_config_dtest_output(unsigned mpp, unsigned level, + unsigned control) +{ + return pm8901_mpp_config(mpp, PM_MPP_TYPE_DTEST_OUTPUT, + level, control); +} +#endif diff --git a/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h b/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h new file mode 100644 index 000000000000..5e927cfbc951 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011-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. + */ + +#ifndef __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H +#define __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H + +#define MAX_L2_PERIOD ((1ULL << 32) - 1) +#define MAX_KRAIT_L2_CTRS 10 + +#define PMCR_NUM_EV_SHIFT 11 +#define PMCR_NUM_EV_MASK 0x1f + +#define L2_EVT_MASK 0xfffff + +#define L2_SLAVE_EV_PREFIX 4 +#define L2_TRACECTR_PREFIX 5 + +#define L2PMCCNTR 0x409 +#define L2PMCCNTCR 0x408 +#define L2PMCCNTSR 0x40A +#define L2CYCLE_CTR_BIT 31 +#define L2CYCLE_CTR_RAW_CODE 0xfe + +#define L2PMOVSR 0x406 + +#define L2PMCR 0x400 +#define L2PMCR_RESET_ALL 0x6 +#define L2PMCR_GLOBAL_ENABLE 0x1 +#define L2PMCR_GLOBAL_DISABLE 0x0 + +#define L2PMCNTENSET 0x403 +#define L2PMCNTENCLR 0x402 + +#define L2PMINTENSET 0x405 +#define L2PMINTENCLR 0x404 + +#define IA_L2PMXEVCNTCR_BASE 0x420 +#define IA_L2PMXEVTYPER_BASE 0x424 +#define IA_L2PMRESX_BASE 0x410 +#define IA_L2PMXEVFILTER_BASE 0x423 +#define IA_L2PMXEVCNTR_BASE 0x421 + +/* event format is -e rsRCCG See get_event_desc() */ + +#define EVENT_PREFIX_MASK 0xf0000 +#define EVENT_REG_MASK 0x0f000 +#define EVENT_GROUPSEL_MASK 0x0000f +#define EVENT_GROUPCODE_MASK 0x00ff0 + +#define EVENT_PREFIX_SHIFT 16 +#define EVENT_REG_SHIFT 12 +#define EVENT_GROUPCODE_SHIFT 4 + +#define RESRX_VALUE_EN 0x80000000 + +#ifdef CONFIG_ARCH_MSM_KRAIT +extern void set_l2_indirect_reg(u32 reg_addr, u32 val); +extern u32 get_l2_indirect_reg(u32 reg_addr); +#else +static inline void set_l2_indirect_reg(u32 reg_addr, u32 val) {} +static inline u32 get_l2_indirect_reg(u32 reg_addr) +{ + return 0; +} +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_cache_dump.h b/arch/arm/mach-msm/include/mach/msm_cache_dump.h new file mode 100644 index 000000000000..a79bcbd2bc36 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_cache_dump.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 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. + */ +#ifndef _MACH_MSM_CACHE_DUMP_ +#define _MACH_MSM_CACHE_DUMP_ + +#include <asm-generic/sizes.h> + + +struct l2_cache_line_dump { + unsigned int l2dcrtr0_val; + unsigned int l2dcrtr1_val; + unsigned int cache_line_data[32]; + unsigned int ddr_data[32]; +} __packed; + +struct l2_cache_dump { + unsigned int magic_number; + unsigned int version; + unsigned int tag_size; + unsigned int line_size; + unsigned int total_lines; + struct l2_cache_line_dump cache[8*1024]; + unsigned int l2esr; +} __packed; + + +struct l1_cache_dump { + unsigned int magic; + unsigned int version; + unsigned int flags; + unsigned int cpu_count; + unsigned int i_tag_size; + unsigned int i_line_size; + unsigned int i_num_sets; + unsigned int i_num_ways; + unsigned int d_tag_size; + unsigned int d_line_size; + unsigned int d_num_sets; + unsigned int d_num_ways; + unsigned int spare[32]; + unsigned int lines[]; +} __packed; + + +struct msm_cache_dump_platform_data { + unsigned int l1_size; + unsigned int l2_size; +}; + +#define CACHE_BUFFER_DUMP_SIZE (L1_BUFFER_SIZE + L2_BUFFER_SIZE) + +#define L1C_SERVICE_ID 3 +#define L1C_BUFFER_SET_COMMAND_ID 4 +#define CACHE_BUFFER_DUMP_COMMAND_ID 5 +#define L1C_BUFFER_GET_SIZE_COMMAND_ID 6 +#define L2C_BUFFER_SET_COMMAND_ID 7 +#define L2C_BUFFER_GET_SIZE_COMMAND_ID 8 + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8916.h b/arch/arm/mach-msm/include/mach/msm_iomap-8916.h new file mode 100644 index 000000000000..b1341bba8383 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_iomap-8916.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __ASM_ARCH_MSM_IOMAP_8916_H +#define __ASM_ARCH_MSM_IOMAP_8916_H + +/* Physical base address and size of peripherals. + * Ordered by the virtual base addresses they will be mapped at. + * + * If you add or remove entries here, you'll want to edit the + * io desc array in arch/arm/mach-msm/io.c to reflect your + * changes. + * + */ + +#define MSM8916_APCS_GCC_PHYS 0xB011000 +#define MSM8916_APCS_GCC_SIZE SZ_4K + +#ifdef CONFIG_DEBUG_MSM8916_UART +#define MSM_DEBUG_UART_BASE IOMEM(0xFA0B0000) +#define MSM_DEBUG_UART_PHYS 0x78B0000 +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 0e4f49157684..69f7ec67441d 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2008-2014, The Linux Foundation. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -37,12 +37,12 @@ * */ -#if defined(CONFIG_ARCH_MSM7X30) -#include "msm_iomap-7x30.h" -#elif defined(CONFIG_ARCH_QSD8X50) -#include "msm_iomap-8x50.h" -#else -#include "msm_iomap-7x00.h" +#define MSM_DEBUG_UART_SIZE SZ_4K + +#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) \ + || defined(CONFIG_DEBUG_MSM_UART3) +#define MSM_DEBUG_UART_BASE 0xFC000000 +#define MSM_DEBUG_UART_PHYS CONFIG_MSM_DEBUG_UART_PHYS #endif /* Virtual addresses shared across all MSM targets. */ @@ -50,4 +50,49 @@ #define MSM_GPIO1_BASE IOMEM(0xE0003000) #define MSM_GPIO2_BASE IOMEM(0xE0004000) +#define MSM8625_WARM_BOOT_PHYS 0x0FD00000 + +/* Unified iomap */ + +#define MSM_TMR_BASE IOMEM(0xFA000000) /* 4K */ +#define MSM_TMR0_BASE IOMEM(0xFA001000) /* 4K */ +#define MSM_TCSR_BASE IOMEM(0xFA004000) /* 4K */ +#define MSM_APCS_GCC_BASE IOMEM(0xFA006000) /* 4K */ +#define MSM_SAW_L2_BASE IOMEM(0xFA007000) /* 4K */ +#define MSM_SAW0_BASE IOMEM(0xFA008000) /* 4K */ +#define MSM_SAW1_BASE IOMEM(0xFA009000) /* 4K */ + +#define MSM_ACC0_BASE IOMEM(0xFA00B000) /* 4K */ +#define MSM_ACC1_BASE IOMEM(0xFA00C000) /* 4K */ +#define MSM_ACC2_BASE IOMEM(0xFA00D000) /* 4K */ +#define MSM_ACC3_BASE IOMEM(0xFA00E000) /* 4K */ +#define MSM_CLK_CTL_BASE IOMEM(0xFA010000) /* 16K */ +#define MSM_MMSS_CLK_CTL_BASE IOMEM(0xFA014000) /* 4K */ +#define MSM_LPASS_CLK_CTL_BASE IOMEM(0xFA015000) /* 4K */ +#define MSM_HFPLL_BASE IOMEM(0xFA016000) /* 4K */ +#define MSM_TLMM_BASE IOMEM(0xFA017000) /* 16K */ +#define MSM_VIC_BASE IOMEM(0xFA100000) /* 4K */ +#define MSM_CSR_BASE IOMEM(0xFA101000) /* 4K */ +#define MSM_GPIO1_BASE IOMEM(0xFA102000) /* 4K */ +#define MSM_GPIO2_BASE IOMEM(0xFA103000) /* 4K */ +#define MSM_SCU_BASE IOMEM(0xFA104000) /* 4K */ +#define MSM_CFG_CTL_BASE IOMEM(0xFA105000) /* 4K */ +#define MSM_CLK_CTL_SH2_BASE IOMEM(0xFA106000) /* 4K */ +#define MSM_MPM2_PSHOLD_BASE IOMEM(0xFA107000) /* 4k */ +#define MSM_SIC_NON_SECURE_BASE IOMEM(0xFA600000) /* 64K */ +#define MSM_QFPROM_BASE IOMEM(0xFA700000) /* 4K */ +#define MSM_L2CC_BASE IOMEM(0xFA701000) /* 4K */ +#define MSM_APCS_GLB_BASE IOMEM(0xFA702000) /* 4K */ +#define MSM_SAW2_BASE IOMEM(0xFA703000) /* 4k */ +#define MSM_SAW3_BASE IOMEM(0xFA704000) /* 4k */ +#define MSM_HDMI_BASE IOMEM(0xFA800000) /* 4K */ +#define MSM_RPM_BASE IOMEM(0xFA801000) /* 4K */ +#define MSM_RPM_MPM_BASE IOMEM(0xFA802000) /* 4K */ +#define MSM_AD5_BASE IOMEM(0xFA900000) /* 13M (D00000) + 0xFB600000 */ +#define MSM_STRONGLY_ORDERED_PAGE 0xFA0F0000 +#define MSM8625_CPU_PHYS 0x0FE00000 + +#include "msm_iomap-8916.h" + #endif diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h new file mode 100644 index 000000000000..457432bd1705 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2010-2011, 2013 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. +*/ + +/* The MSM Hardware supports multiple flavors of physical memory. + * This file captures hardware specific information of these types. +*/ + +#ifndef __ASM_ARCH_MSM_MEMTYPES_H +#define __ASM_ARCH_MSM_MEMTYPES_H + +#include <mach/memory.h> +#include <linux/init.h> + +int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname, + int depth, void *data); +int __init dt_scan_for_memory_hole(unsigned long node, const char *uname, + int depth, void *data); +void adjust_meminfo(unsigned long start, unsigned long size); +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_mpmctr.h b/arch/arm/mach-msm/include/mach/msm_mpmctr.h new file mode 100644 index 000000000000..d3d853fbd6bd --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_mpmctr.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013, 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. + */ +#ifndef __MSM_MPMCTR_H__ +#define __MSM_MPMCTR_H__ + +/* + * returns the count value of the mpm timetick. + */ +uint32_t msm_mpm_get_count(void); + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h new file mode 100644 index 000000000000..b6933c226d5a --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_pcie.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2012-2013, 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. + */ + +#ifndef __ASM_ARCH_MSM_PCIE_H +#define __ASM_ARCH_MSM_PCIE_H + +#include <linux/types.h> + +enum msm_pcie_pm_opt { + MSM_PCIE_SUSPEND, + MSM_PCIE_RESUME +}; + +/** + * msm_pcie_pm_control - control the power state of a PCIe link. + * @pm_opt: power management operation + * @busnr: bus number of PCIe endpoint + * @user: handle of the caller + * @data: private data from the caller + * @options: options for pm control + * + * This function gives PCIe endpoint device drivers the control to change + * the power state of a PCIe link for their device. + * + * Return: 0 on success, negative value on error + */ +int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, + void *data, u32 options); + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h b/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h new file mode 100644 index 000000000000..774c91dd7c99 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __ASM_ARCH_MSM_SERIAL_HSL_REGS_H +#define __ASM_ARCH_MSM_SERIAL_HSL_REGS_H + +#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS_V14 +#define UARTDM_MR2_OFFSET 0x4 +#define UARTDM_CSR_OFFSET 0xa0 +#define UARTDM_SR_OFFSET 0xa4 +#define UARTDM_CR_OFFSET 0xa8 +#define UARTDM_ISR_OFFSET 0xb4 +#define UARTDM_NCF_TX_OFFSET 0x40 +#define UARTDM_TF_OFFSET 0x100 +#else +#define UARTDM_MR2_OFFSET 0x4 +#define UARTDM_CSR_OFFSET 0x8 +#define UARTDM_SR_OFFSET 0x8 +#define UARTDM_CR_OFFSET 0x10 +#define UARTDM_ISR_OFFSET 0x14 +#define UARTDM_NCF_TX_OFFSET 0x40 +#define UARTDM_TF_OFFSET 0x70 +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h new file mode 100644 index 000000000000..7c1319efcfc6 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2010, 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. +*/ + +#ifndef __ASM_ARCH_MSM_SERIAL_H +#define __ASM_ARCH_MSM_SERIAL_H + +#include <linux/serial_core.h> + +/* Optional platform device data for msm_serial driver. + * Used to configure low power wakeup */ +struct msm_serial_platform_data { + int wakeup_irq; /* wakeup irq */ + /* bool: inject char into rx tty on wakeup */ + unsigned char inject_rx_on_wakeup; + char rx_to_inject; + int userid; +}; + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h new file mode 100644 index 000000000000..251edc431394 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_spi.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2008-2009, 2012-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. + * + */ +/* + * SPI driver for Qualcomm Technologies, Inc. MSM platforms. + */ + +/** + * msm_spi_platform_data: msm spi-controller's configuration data + * + * @active_only when set, votes when system active and removes the vote when + * system goes idle (optimises for performance). When unset, voting using + * runtime pm (optimizes for power). + * @master_id master id number of the controller's wrapper (BLSP or GSBI). + * When zero, clock path voting is disabled. + * @rt when set, spi will pump transaction messages with high (realtime) + * priority to reduce the transfer latency on the bus by minimising + * the delay between a transfer request. + */ +struct msm_spi_platform_data { + u32 max_clock_speed; + bool active_only; + u32 master_id; + int (*gpio_config)(void); + void (*gpio_release)(void); + int (*dma_config)(void); + const char *rsl_id; + u32 pm_lat; + u32 infinite_mode; + bool ver_reg_exists; + bool use_bam; + u32 bam_consumer_pipe_index; + u32 bam_producer_pipe_index; + bool rt_priority; + bool use_pinctrl; +}; diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h new file mode 100644 index 000000000000..c02bb212a9ce --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_tspp.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2012-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. + */ + +#ifndef _MSM_TSPP_H_ +#define _MSM_TSPP_H_ + +struct msm_tspp_platform_data { + int num_gpios; + const struct msm_gpio *gpios; + const char *tsif_pclk; + const char *tsif_ref_clk; + int tsif_vreg_present; +}; + +struct tspp_data_descriptor { + void *virt_base; /* logical address of the actual data */ + phys_addr_t phys_base; /* physical address of the actual data */ + u32 size; /* size of buffer in bytes */ + int id; /* unique identifier */ + void *user; /* user-defined data */ +}; + +enum tspp_key_parity { + TSPP_KEY_PARITY_EVEN, + TSPP_KEY_PARITY_ODD +}; + +struct tspp_key { + enum tspp_key_parity parity; + int lsb; + int msb; +}; + +enum tspp_source { + TSPP_SOURCE_TSIF0, + TSPP_SOURCE_TSIF1, + TSPP_SOURCE_MEM, + TSPP_SOURCE_NONE = -1 +}; + +enum tspp_mode { + TSPP_MODE_DISABLED, + TSPP_MODE_PES, + TSPP_MODE_RAW, + TSPP_MODE_RAW_NO_SUFFIX +}; + +enum tspp_tsif_mode { + TSPP_TSIF_MODE_LOOPBACK, /* loopback mode */ + TSPP_TSIF_MODE_1, /* without sync */ + TSPP_TSIF_MODE_2 /* with sync signal */ +}; + +struct tspp_filter { + int pid; + int mask; + enum tspp_mode mode; + unsigned int priority; /* 0 - 15 */ + int decrypt; + enum tspp_source source; +}; + +struct tspp_select_source { + enum tspp_source source; + enum tspp_tsif_mode mode; + int clk_inverse; + int data_inverse; + int sync_inverse; + int enable_inverse; +}; + +typedef void (tspp_notifier)(int channel_id, void *user); +typedef void* (tspp_allocator)(int channel_id, u32 size, + phys_addr_t *phys_base, void *user); +typedef void (tspp_memfree)(int channel_id, u32 size, + void *virt_base, phys_addr_t phys_base, void *user); + +/* Kernel API functions */ +int tspp_open_stream(u32 dev, u32 channel_id, + struct tspp_select_source *source); +int tspp_close_stream(u32 dev, u32 channel_id); +int tspp_open_channel(u32 dev, u32 channel_id); +int tspp_close_channel(u32 dev, u32 channel_id); +int tspp_get_ref_clk_counter(u32 dev, + enum tspp_source source, u32 *tcr_counter); +int tspp_add_filter(u32 dev, u32 channel_id, struct tspp_filter *filter); +int tspp_remove_filter(u32 dev, u32 channel_id, struct tspp_filter *filter); +int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key); +int tspp_register_notification(u32 dev, u32 channel_id, tspp_notifier *notify, + void *data, u32 timer_ms); +int tspp_unregister_notification(u32 dev, u32 channel_id); +const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id); +int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id); +int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, + u32 size, u32 int_freq, tspp_allocator *alloc, + tspp_memfree *memfree, void *user); + +#endif /* _MSM_TSPP_H_ */ + diff --git a/arch/arm/mach-msm/include/mach/msm_tspp2.h b/arch/arm/mach-msm/include/mach/msm_tspp2.h new file mode 100644 index 000000000000..80bf13937fed --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_tspp2.h @@ -0,0 +1,759 @@ +/* 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. + */ + +#ifndef _MSM_TSPP2_H_ +#define _MSM_TSPP2_H_ + +#include <linux/ion.h> +#include <linux/msm-sps.h> + +#define TSPP2_NUM_DEVICES 1 +#define TSPP2_NUM_TSIF_INPUTS 2 +#define TSPP2_NUM_PIPES 31 +#define TSPP2_NUM_MEM_INPUTS 8 +#define TSPP2_NUM_INDEXING_TABLES 4 +#define TSPP2_NUM_INDEXING_PATTERNS 26 +#define TSPP2_MAX_OPS_PER_FILTER 16 + +#define TSPP2_INVALID_HANDLE 0 +#define TSPP2_UNIQUE_PID_MASK 0x1FFF + +/** + * struct msm_tspp2_platform_data - TSPP2 platform data + * + * @hlos_group: IOMMU HLOS group name. + * @cpz_group: IOMMU CPZ group name. + * @hlos_partition: IOMMU HLOS partition number. + * @cpz_partition: IOMMU CPZ partition number. + */ +struct msm_tspp2_platform_data { + const char *hlos_group; + const char *cpz_group; + int hlos_partition; + int cpz_partition; +}; + +/** + * struct tspp2_config - Global configuration + * + * @min_pcr_interval: Minimum time (in msec) between PCR notifications + * on the same PID. Setting to 0 means every PCR + * is notified. Default value is 50 msec. + * @pcr_on_discontinuity: Flag to indicate whether to notify on PCR when + * the discontinuity flag is set in the TS packet, + * regardless of min_pcr_interval. + * @stc_byte_offset: Offset (in bytes) between the 4 byte timestamp + * and the 7 byte STC counter. + * Valid values are 0 - 3. A value of 0 means the + * 4 LSBytes of the STC are used in the timestamp, + * while a value of 3 means the 4 MSBytes are used. + */ +struct tspp2_config { + u8 min_pcr_interval; + int pcr_on_discontinuity; + u8 stc_byte_offset; +}; + +/** + * enum tspp2_src_input - Source input type: TSIF or memory + * + * @TSPP2_INPUT_TSIF0: Input from TSIF 0. + * @TSPP2_INPUT_TSIF1: Input from TSIF 1. + * @TSPP2_INPUT_MEMORY: Input from memory. + */ +enum tspp2_src_input { + TSPP2_INPUT_TSIF0 = 0, + TSPP2_INPUT_TSIF1 = 1, + TSPP2_INPUT_MEMORY = 2 +}; + +/** + * enum tspp2_tsif_mode - TSIF mode of operation + * + * @TSPP2_TSIF_MODE_LOOPBACK: Loopback mode, used for debug only. + * @TSPP2_TSIF_MODE_1: Mode 1: TSIF works with 3 interface signals. + * @TSPP2_TSIF_MODE_2: Mode 2: TSIF works with 4 interface signals. + */ +enum tspp2_tsif_mode { + TSPP2_TSIF_MODE_LOOPBACK, + TSPP2_TSIF_MODE_1, + TSPP2_TSIF_MODE_2, +}; + +/** + * enum tspp2_packet_format - Packet size (in bytes) and timestamp format + * + * @TSPP2_PACKET_FORMAT_188_RAW: Packet size is 188 Bytes, no timestamp. + * @TSPP2_PACKET_FORMAT_192_HEAD: Packet size is 192 Bytes, + * 4 Byte timestamp before the data. + * @TSPP2_PACKET_FORMAT_192_TAIL: Packet size is 192 Bytes, + * 4 Byte timestamp after the data. + */ +enum tspp2_packet_format { + TSPP2_PACKET_FORMAT_188_RAW, + TSPP2_PACKET_FORMAT_192_HEAD, + TSPP2_PACKET_FORMAT_192_TAIL +}; + +/** + * struct tspp2_tsif_src_params - TSIF source configuration parameters + * + * @tsif_mode: TSIF mode of operation. + * @clock_inverse: Invert incoming clock signal. + * @data_inverse: Invert incoming data signal. + * @sync_inverse: Invert incoming sync signal. + * @enable_inverse: Invert incoming enable signal. + */ +struct tspp2_tsif_src_params { + enum tspp2_tsif_mode tsif_mode; + int clock_inverse; + int data_inverse; + int sync_inverse; + int enable_inverse; +}; + +/** + * struct tspp2_src_cfg - Source configuration + * + * @input: Source input (TSIF0/1 or memory). + * @params: source configuration parameters. + */ +struct tspp2_src_cfg { + enum tspp2_src_input input; + union { + struct tspp2_tsif_src_params tsif_params; + } params; +}; + +/** + * enum tspp2_src_parsing_option - Parsing options + * + * @TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY: Detect discontinuities in + * TS packets. + * @TSPP2_SRC_PARSING_OPT_IGNORE_DISCONTINUITY: Ignore discontinuity indicator. + * If set, discontinuities are + * detected according to the + * continuity counter only, + * which may result in false + * positives. + * @TSPP2_SRC_PARSING_OPT_ASSUME_DUPLICATE_PACKETS: Assume TS packets + * may be duplicated (i.e., have + * the same continuity counter). + * If cleared, may result in more + * discontinuity statuses. If TSPP2 + * is configured using PID filter + * masks it is recommended to + * disable this field. Multi PID + * filters may detect false + * duplicates which will results in + * discarded packets. + * @TSPP2_SRC_PARSING_OPT_DISCARD_INVALID_AF_PACKETS: Discard TS packets with + * invalid Adaptation Field + * control. + * @TSPP2_SRC_PARSING_OPT_VERIFY_PES_START: Verify PES start code. If + * enabled and the PES doesn’t + * start with the start code, the + * whole PES is not assembled. + */ +enum tspp2_src_parsing_option { + TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY, + TSPP2_SRC_PARSING_OPT_IGNORE_DISCONTINUITY, + TSPP2_SRC_PARSING_OPT_ASSUME_DUPLICATE_PACKETS, + TSPP2_SRC_PARSING_OPT_DISCARD_INVALID_AF_PACKETS, + TSPP2_SRC_PARSING_OPT_VERIFY_PES_START +}; + +/** + * enum tspp2_src_scrambling_ctrl - Scrambling bits control + * + * @TSPP2_SRC_SCRAMBLING_CTRL_PASSTHROUGH: Packet is clear, pass-through + * without decryption. + * @TSPP2_SRC_SCRAMBLING_CTRL_DISCARD: Discard packet. + * @TSPP2_SRC_SCRAMBLING_CTRL_EVEN: Packet is scrambled with + * even Key. + * @TSPP2_SRC_SCRAMBLING_CTRL_ODD: Packet is scrambled with + * odd key. + */ +enum tspp2_src_scrambling_ctrl { + TSPP2_SRC_SCRAMBLING_CTRL_PASSTHROUGH, + TSPP2_SRC_SCRAMBLING_CTRL_DISCARD, + TSPP2_SRC_SCRAMBLING_CTRL_EVEN, + TSPP2_SRC_SCRAMBLING_CTRL_ODD +}; + +/** + * enum tspp2_src_scrambling_monitoring - Scrambling bits monitoring + * + * @TSPP2_SRC_SCRAMBLING_MONITOR_NONE: No scrambling bits monitoring. + * @TSPP2_SRC_SCRAMBLING_MONITOR_PES_ONLY: Monitor only PES heaer + * scrambling bit control field. + * If no PES header was found, + * scrambling bits will be + * considered as ‘00’. + * @TSPP2_SRC_SCRAMBLING_MONITOR_TS_ONLY: Monitor only TS packet header + * scrambling bit control field. + * @TSPP2_SRC_SCRAMBLING_MONITOR_PES_AND_TS: Monitor both TS packet and PES + * header. Monitor result is the + * logical OR of the two. + */ +enum tspp2_src_scrambling_monitoring { + TSPP2_SRC_SCRAMBLING_MONITOR_NONE, + TSPP2_SRC_SCRAMBLING_MONITOR_PES_ONLY, + TSPP2_SRC_SCRAMBLING_MONITOR_TS_ONLY, + TSPP2_SRC_SCRAMBLING_MONITOR_PES_AND_TS +}; + +/** + * struct tspp2_src_scrambling_config - Source scrambling bits configuration + * + * Each TS/PES packet has two bits that + * control the scrambling, called + * transport_scrambling_control. This + * configuration sets the user-defined + * meaning of these bits. + * + * @scrambling_0_ctrl: Scrambling bits control for value '00'. + * @scrambling_1_ctrl: Scrambling bits control for value '01'. + * @scrambling_2_ctrl: Scrambling bits control for value '10'. + * @scrambling_3_ctrl: Scrambling bits control for value '11'. + * @scrambling_bits_monitoring: Scrambling bits monitoring configuration + * for this source. + */ +struct tspp2_src_scrambling_config { + enum tspp2_src_scrambling_ctrl scrambling_0_ctrl; + enum tspp2_src_scrambling_ctrl scrambling_1_ctrl; + enum tspp2_src_scrambling_ctrl scrambling_2_ctrl; + enum tspp2_src_scrambling_ctrl scrambling_3_ctrl; + enum tspp2_src_scrambling_monitoring scrambling_bits_monitoring; +}; + +/** + * enum tspp2_src_pipe_mode - pipe mode + * + * @TSPP2_SRC_PIPE_INPUT: An input (consumer) pipe. + * @TSPP2_SRC_PIPE_OUTPUT: An output (producer) pipe. + */ +enum tspp2_src_pipe_mode { + TSPP2_SRC_PIPE_INPUT, + TSPP2_SRC_PIPE_OUTPUT +}; + +/** + * struct tspp2_pipe_pull_mode_params - Pipe pull mode parameters + * + * @is_stalling: Whether this pipe is stalling when working in pull mode. + * Relevant for the source the pipe is being attached to. + * Relevant only for output pipes. + * @threshold: The threshold used for flow control (in bytes). The + * same threshold must be used for all sources. + */ +struct tspp2_pipe_pull_mode_params { + int is_stalling; + u16 threshold; +}; + +/** + * struct tspp2_pipe_sps_params - Pipe SPS configuration parameters + * + * @descriptor_size: Size of each pipe descriptor, in bytes. + * @descriptor_flags: Descriptor flags (SPS_IOVEC_FLAG_XXX). + * @setting: Pipe settings. + * @wakeup_events: Pipe wakeup events. + * @callback: A callback function invoked on pipe events. + * @user_info: User information reported with each event. + */ +struct tspp2_pipe_sps_params { + u32 descriptor_size; + u32 descriptor_flags; + enum sps_option setting; + enum sps_option wakeup_events; + void (*callback)(struct sps_event_notify *notify); + void *user_info; +}; + +/** + * struct tspp2_pipe_config_params - Pipe configuration parameters + * + * @ion_client: The ION client used to allocate the buffer. + * @buffer_handle: The ION handle representing the buffer. + * @buffer_size: The memory buffer size. + * @is_secure: Is this a securely allocated and locked buffer or not. + * @pipe_mode: Pipe mode (input / output). + * @sps_cfg: Pipe SPS configuration. + */ +struct tspp2_pipe_config_params { + struct ion_client *ion_client; + struct ion_handle *buffer_handle; + u32 buffer_size; + int is_secure; + enum tspp2_src_pipe_mode pipe_mode; + struct tspp2_pipe_sps_params sps_cfg; +}; + +/** + * enum tspp2_operation_type - Operation types + * + * @TSPP2_OP_PES_ANALYSIS: PES analysis operation parses the PES header + * and extracts necessary variables from it. Use + * this operation before any other PES transmit + * operation, otherwise the output buffer will be + * empty. + * PID filters that includes any PES operation, and + * specifically PES analysis, must have a mask that + * will match a single PID. + * @TSPP2_OP_RAW_TRANSMIT: RAW transmit operation, used to send whole TS + * packets to the output pipe. A timestamp can also + * be appended. + * Use this operation for PIDs that carry section + * information, and for recording. + * @TSPP2_OP_PES_TRANSMIT: PES transmit operation, used to assemble PES + * packets. There are two modes for this operation: + * 1. Full PES transmit: the full PES, both header + * and payload are written to the output pipe. + * 2. Separated PES header and payload: the PES + * header is written to one pipe and the payload is + * written to a different pipe. + * @TSPP2_OP_PCR_EXTRACTION: PCR extraction operation, used to extract TS + * packets with PCR. No processing is performed on + * the PCR. This operation simply outputs the + * packet and the timestamp. It is recommended that + * PCR extraction operation will be set before + * other operations (PES analysis, cipher) so that + * failures in those operation will not affect it. + * @TSPP2_OP_CIPHER: Cipher operation, used to encrypt / decrypt TS + * packets. + * @TSPP2_OP_INDEXING: Indexing operation, used for searching patterns + * in the PES payload or for indexing using the + * random access indicator. + * In order to perform pattern search, a PES + * Analysis operation must precede the indexing + * operation. For random access indicator indexing + * this is not mandatory. + * Indexing is performed on video streams. + * Use only a single indexing operation per filter. + * @TSPP2_OP_COPY_PACKET: Copy packet operation, used to copy the packet + * from one sketch buffer to the other. + */ +enum tspp2_operation_type { + TSPP2_OP_PES_ANALYSIS, + TSPP2_OP_RAW_TRANSMIT, + TSPP2_OP_PES_TRANSMIT, + TSPP2_OP_PCR_EXTRACTION, + TSPP2_OP_CIPHER, + TSPP2_OP_INDEXING, + TSPP2_OP_COPY_PACKET +}; + +/** + * enum tspp2_operation_buffer - Operation sketch buffer + * + * @TSPP2_OP_BUFFER_A: Sketch buffer A (initial) + * @TSPP2_OP_BUFFER_B: Sketch buffer B + */ +enum tspp2_operation_buffer { + TSPP2_OP_BUFFER_A, + TSPP2_OP_BUFFER_B +}; + +/** + * enum tspp2_operation_timestamp_mode - RAW transmit operation timestamp mode + * + * @TSPP2_OP_TIMESTAMP_NONE: Don't add timestamp. Output is 188 byte packets. + * @TSPP2_OP_TIMESTAMP_ZERO: Add 4-byte timestamp, value is all zeros. + * @TSPP2_OP_TIMESTAMP_STC: Add 4-byte timestamp, value according to STC + * generated by TSIF. + */ +enum tspp2_operation_timestamp_mode { + TSPP2_OP_TIMESTAMP_NONE, + TSPP2_OP_TIMESTAMP_ZERO, + TSPP2_OP_TIMESTAMP_STC +}; + +/** + * enum tspp2_operation_cipher_mode - Cipher operation mode + * + * @TSPP2_OP_CIPHER_DECRYPT: Decrypt packet. + * @TSPP2_OP_CIPHER_ENCRYPT: Encrypt packet. + */ +enum tspp2_operation_cipher_mode { + TSPP2_OP_CIPHER_DECRYPT, + TSPP2_OP_CIPHER_ENCRYPT +}; + +/** + * enum tspp2_operation_cipher_scrambling_mode - Cipher operation scrambling mode + * + * @TSPP2_OP_CIPHER_AS_IS: Use the original scrambling bits to + * decide which key to use (even, odd or + * pass-through). If enabled, the operation + * will not modify the scrambling bits in + * the TS packet header. + * @TSPP2_OP_CIPHER_SET_SCRAMBLING_0: Set TS packet scrambling bits to '00'. + * @TSPP2_OP_CIPHER_SET_SCRAMBLING_1: Set TS packet scrambling bits to '01'. + * @TSPP2_OP_CIPHER_SET_SCRAMBLING_2: Set TS packet scrambling bits to '10'. + * @TSPP2_OP_CIPHER_SET_SCRAMBLING_3: Set TS packet scrambling bits to '11'. + */ +enum tspp2_operation_cipher_scrambling_mode { + TSPP2_OP_CIPHER_AS_IS, + TSPP2_OP_CIPHER_SET_SCRAMBLING_0, + TSPP2_OP_CIPHER_SET_SCRAMBLING_1, + TSPP2_OP_CIPHER_SET_SCRAMBLING_2, + TSPP2_OP_CIPHER_SET_SCRAMBLING_3 +}; + +/** + * enum tspp2_op_pes_transmit_mode - PES transmit operation mode + * + * TSPP2_OP_PES_TRANSMIT_SEPARATED: Separated PES mode. + * TSPP2_OP_PES_TRANSMIT_FULL: Full PES mode. + */ +enum tspp2_op_pes_transmit_mode { + TSPP2_OP_PES_TRANSMIT_SEPARATED, + TSPP2_OP_PES_TRANSMIT_FULL +}; + +/** + * struct tspp2_op_pes_analysis_params - PES analysis operation parameters + * + * @input: Input buffer for this operation. + * @skip_ts_errs: If set, TS packet with an error + * indication will not be processed by this + * operation. The implication would be that + * if a PES started with an erred packet, + * the entire PES will be lost. This + * parameter affects all PES operations + * later in the sequence: PES transmit and + * indexing. For indexing, the implications + * might be that a pattern will not be + * found and the frame will not be indexed. + */ +struct tspp2_op_pes_analysis_params { + enum tspp2_operation_buffer input; + int skip_ts_errs; +}; + +/** + * struct tspp2_op_raw_transmit_params - Raw transmit operation parameters + * + * @input: Input buffer for this operation. + * @timestamp_mode: Determines timestamp mode. + * @timestamp_position: Determines timestamp position, if added. + * @support_indexing: If set, then the indexing information + * generated by a following indexing + * operation refers to the data in the + * output pipe used by this RAW operation. + * When a filter has multiple RAW + * operations, only one of them should set + * the support_indexing option. + * @skip_ts_errs: If set, TS packet with an error + * indication will not be processed by this + * operation. The implication depends on + * the content which the PID carries. + * @output_pipe_handle: Handle of the output pipe. + */ +struct tspp2_op_raw_transmit_params { + enum tspp2_operation_buffer input; + enum tspp2_operation_timestamp_mode timestamp_mode; + enum tspp2_packet_format timestamp_position; + int support_indexing; + int skip_ts_errs; + u32 output_pipe_handle; +}; + +/** + * struct tspp2_op_pes_transmit_params - PES transmit operation parameters + * + * @input: Input buffer for this operation. + * @mode: Seperated / Full PES mode. + * @enable_sw_indexing: Enable the PES addressing which is + * appended to the PES payload. + * @attach_stc_flags: Attach STC and flags to the PES. + * Relevant only when mode is full PES. + * @disable_tx_on_pes_discontinuity: Disable transmission of PES payload + * after a discontinuity. When set, TSPP2 + * waits until a new PUSI is received and + * all the packets until then are + * discarded. The current PES will be + * closed when the new PUSI arrives. + * @output_pipe_handle: Handle of the output pipe in full PES + * mode, or the payload output pipe in + * separated PES mode. + * @header_output_pipe_handle: Handle of the PES header output pipe in + * separated PES mode. + */ +struct tspp2_op_pes_transmit_params { + enum tspp2_operation_buffer input; + enum tspp2_op_pes_transmit_mode mode; + int enable_sw_indexing; + int attach_stc_flags; + int disable_tx_on_pes_discontinuity; + u32 output_pipe_handle; + u32 header_output_pipe_handle; +}; + +/** + * struct tspp2_op_pcr_extraction_params - PCR extraction operation parameters + * + * @input: Input buffer for this operation. + * @skip_ts_errs: If set, TS packet with an error + * indication will not be processed by this + * operation. The implication would be that + * a PCR packet may be lost. + * @extract_pcr: Extract TS packets containing PCR. + * @extract_opcr: Extract TS packets containing OPCR. + * @extract_splicing_point: Extract TS packets containing a splicing + * point indication. + * @extract_transport_private_data: Extract TS packets containig private + * data. + * @extract_af_extension: Extract TS packets with an adaptation + * field extension. + * @extract_all_af: Extract all TS packets with an adaptaion + * field. + * @output_pipe_handle: Handle of the output pipe. + */ +struct tspp2_op_pcr_extraction_params { + enum tspp2_operation_buffer input; + int skip_ts_errs; + int extract_pcr; + int extract_opcr; + int extract_splicing_point; + int extract_transport_private_data; + int extract_af_extension; + int extract_all_af; + u32 output_pipe_handle; +}; + +/** + * struct tspp2_op_cipher_params - Cipher operation parameters + * + * @input: Input buffer for this operation. + * @mode: Decrypt / encrypt. + * @decrypt_pes_header: Decrypt PES header TS packets (use if + * PES header is encrypted). + * @skip_ts_errs: If set, TS packet with an error + * indication will not be processed by this + * operation. + * @key_ladder_index: Key ladder index. + * @scrambling_mode: Scrambling bits manipulation mode. + * @output: Output buffer for this operation. + */ +struct tspp2_op_cipher_params { + enum tspp2_operation_buffer input; + enum tspp2_operation_cipher_mode mode; + int decrypt_pes_header; + int skip_ts_errs; + u32 key_ladder_index; + enum tspp2_operation_cipher_scrambling_mode scrambling_mode; + enum tspp2_operation_buffer output; +}; + +/** + * struct tspp2_op_indexing_params - Indexing operation parameters + * + * @input: Input buffer for this operation. + * @random_access_indicator_indexing: If set, do indexing according to the + * random access indicator in the TS packet + * header. TSPP2 will not look for the + * patterns defined in the specified table. + * @indexing_table_id: Indexing table ID. + * @skip_ts_errs: If set, TS packet with an error + * indication will not be processed by this + * operation. + * @output_pipe_handle: Handle of the output pipe. + */ +struct tspp2_op_indexing_params { + enum tspp2_operation_buffer input; + int random_access_indicator_indexing; + u8 indexing_table_id; + int skip_ts_errs; + u32 output_pipe_handle; +}; + +/** + * struct tspp2_op_copy_packet_params - Copy packet operation parameters + * + * @input: Input buffer for this operation. + */ +struct tspp2_op_copy_packet_params { + enum tspp2_operation_buffer input; +}; + +/** + * struct tspp2_operation - Operation + * + * @type: Operation type. + * @params: Operation-specific parameters. + */ +struct tspp2_operation { + enum tspp2_operation_type type; + union { + struct tspp2_op_pes_analysis_params pes_analysis; + struct tspp2_op_raw_transmit_params raw_transmit; + struct tspp2_op_pes_transmit_params pes_transmit; + struct tspp2_op_pcr_extraction_params pcr_extraction; + struct tspp2_op_cipher_params cipher; + struct tspp2_op_indexing_params indexing; + struct tspp2_op_copy_packet_params copy_packet; + } params; +}; + +/* TSPP2 device open / close API */ +int tspp2_device_open(u32 dev_id); + +int tspp2_device_close(u32 dev_id); + +/* Global configuration API */ +int tspp2_config_set(u32 dev_id, const struct tspp2_config *cfg); + +int tspp2_config_get(u32 dev_id, struct tspp2_config *cfg); + +/* Indexing tables API functions */ +int tspp2_indexing_prefix_set(u32 dev_id, + u8 table_id, + u32 value, + u32 mask); + +int tspp2_indexing_patterns_add(u32 dev_id, + u8 table_id, + const u32 *values, + const u32 *masks, + u8 patterns_num); + +int tspp2_indexing_patterns_clear(u32 dev_id, + u8 table_id); + +/* Pipe API functions */ +int tspp2_pipe_open(u32 dev_id, + const struct tspp2_pipe_config_params *cfg, + ion_phys_addr_t *iova, + u32 *pipe_handle); + +int tspp2_pipe_close(u32 pipe_handle); + +/* Source API functions */ +int tspp2_src_open(u32 dev_id, + struct tspp2_src_cfg *cfg, + u32 *src_handle); + +int tspp2_src_close(u32 src_handle); + +int tspp2_src_parsing_option_set(u32 src_handle, + enum tspp2_src_parsing_option option, + int value); + +int tspp2_src_parsing_option_get(u32 src_handle, + enum tspp2_src_parsing_option option, + int *value); + +int tspp2_src_sync_byte_config_set(u32 src_handle, + int check_sync_byte, + u8 sync_byte_value); + +int tspp2_src_sync_byte_config_get(u32 src_handle, + int *check_sync_byte, + u8 *sync_byte_value); + +int tspp2_src_scrambling_config_set(u32 src_handle, + const struct tspp2_src_scrambling_config *cfg); + +int tspp2_src_scrambling_config_get(u32 src_handle, + struct tspp2_src_scrambling_config *cfg); + +int tspp2_src_packet_format_set(u32 src_handle, + enum tspp2_packet_format format); + +int tspp2_src_pipe_attach(u32 src_handle, + u32 pipe_handle, + const struct tspp2_pipe_pull_mode_params *cfg); + +int tspp2_src_pipe_detach(u32 src_handle, u32 pipe_handle); + +int tspp2_src_enable(u32 src_handle); + +int tspp2_src_disable(u32 src_handle); + +int tspp2_src_filters_clear(u32 src_handle); + +/* Filters and Operations API functions */ +int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle); + +int tspp2_filter_close(u32 filter_handle); + +int tspp2_filter_enable(u32 filter_handle); + +int tspp2_filter_disable(u32 filter_handle); + +int tspp2_filter_operations_set(u32 filter_handle, + const struct tspp2_operation *ops, + u8 operations_num); + +int tspp2_filter_operations_clear(u32 filter_handle); + +int tspp2_filter_current_scrambling_bits_get(u32 filter_handle, + u8 *scrambling_bits_value); + +/* Data-path API functions */ +int tspp2_pipe_descriptor_get(u32 pipe_handle, struct sps_iovec *desc); + +int tspp2_pipe_descriptor_put(u32 pipe_handle, u32 addr, u32 size, u32 flags); + +int tspp2_pipe_last_address_used_get(u32 pipe_handle, u32 *address); + +int tspp2_data_write(u32 src_handle, u32 offset, u32 size); + +int tspp2_tsif_data_write(u32 src_handle, u32 *data); + +/* Event notification API functions */ + +/* Global events */ +#define TSPP2_GLOBAL_EVENT_INVALID_AF_CTRL 0x00000001 +#define TSPP2_GLOBAL_EVENT_INVALID_AF_LENGTH 0x00000002 +#define TSPP2_GLOBAL_EVENT_PES_NO_SYNC 0x00000004 +#define TSPP2_GLOBAL_EVENT_TX_FAIL 0x00000008 +/* Source events */ +#define TSPP2_SRC_EVENT_TSIF_LOST_SYNC 0x00000001 +#define TSPP2_SRC_EVENT_TSIF_TIMEOUT 0x00000002 +#define TSPP2_SRC_EVENT_TSIF_OVERFLOW 0x00000004 +#define TSPP2_SRC_EVENT_TSIF_PKT_READ_ERROR 0x00000008 +#define TSPP2_SRC_EVENT_TSIF_PKT_WRITE_ERROR 0x00000010 +#define TSPP2_SRC_EVENT_MEMORY_READ_ERROR 0x00000020 +#define TSPP2_SRC_EVENT_FLOW_CTRL_STALL 0x00000040 +/* Filter events */ +#define TSPP2_FILTER_EVENT_SCRAMBLING_HIGH 0x00000001 +#define TSPP2_FILTER_EVENT_SCRAMBLING_LOW 0x00000002 + + +int tspp2_global_event_notification_register(u32 dev_id, + u32 global_event_bitmask, + void (*callback)(void *cookie, u32 event_bitmask), + void *cookie); + +int tspp2_src_event_notification_register(u32 src_handle, + u32 src_event_bitmask, + void (*callback)(void *cookie, u32 event_bitmask), + void *cookie); + +int tspp2_filter_event_notification_register(u32 filter_handle, + u32 filter_event_bitmask, + void (*callback)(void *cookie, u32 event_bitmask), + void *cookie); + +int tspp2_get_reserved_hw_index(u32 src_handle); + +int tspp2_get_filter_hw_index(u32 filter_handle); + +int tspp2_get_ops_array(u32 filter_handle, + struct tspp2_operation ops_array[TSPP2_MAX_OPS_PER_FILTER], + u8 *num_of_ops); + +#endif /* _MSM_TSPP2_H_ */ + diff --git a/arch/arm/mach-msm/include/mach/msm_xo.h b/arch/arm/mach-msm/include/mach/msm_xo.h new file mode 100644 index 000000000000..f9ccfee96370 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_xo.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2010-2012, 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. + */ +#ifndef __MACH_MSM_XO_H +#define __MACH_MSM_XO_H + +enum msm_xo_ids { + MSM_XO_TCXO_D0, + MSM_XO_TCXO_D1, + MSM_XO_TCXO_A0, + MSM_XO_TCXO_A1, + MSM_XO_TCXO_A2, + MSM_XO_CORE, + NUM_MSM_XO_IDS +}; + +enum msm_xo_modes { + MSM_XO_MODE_OFF, + MSM_XO_MODE_PIN_CTRL, + MSM_XO_MODE_ON, + NUM_MSM_XO_MODES +}; + +struct msm_xo_voter; + +#ifdef CONFIG_MSM_XO +struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id, const char *voter); +void msm_xo_put(struct msm_xo_voter *xo_voter); +int msm_xo_mode_vote(struct msm_xo_voter *xo_voter, enum msm_xo_modes xo_mode); +int __init msm_xo_init(void); +#else +static inline struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id, + const char *voter) +{ + return NULL; +} + +static inline void msm_xo_put(struct msm_xo_voter *xo_voter) { } + +static inline int msm_xo_mode_vote(struct msm_xo_voter *xo_voter, + enum msm_xo_modes xo_mode) +{ + return 0; +} +static inline int msm_xo_init(void) { return 0; } +#endif /* CONFIG_MSM_XO */ + +#endif diff --git a/arch/arm/mach-msm/include/mach/proc_comm.h b/arch/arm/mach-msm/include/mach/proc_comm.h new file mode 100644 index 000000000000..655692abca3a --- /dev/null +++ b/arch/arm/mach-msm/include/mach/proc_comm.h @@ -0,0 +1,181 @@ +/* arch/arm/mach-msm/include/mach/proc_comm.h + * + * Copyright (c) 2007-2009,2011 The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_ +#define _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_ + +enum { + PCOM_CMD_IDLE = 0x0, + PCOM_CMD_DONE, + PCOM_RESET_APPS, + PCOM_RESET_CHIP, + PCOM_CONFIG_NAND_MPU, + PCOM_CONFIG_USB_CLKS, + PCOM_GET_POWER_ON_STATUS, + PCOM_GET_WAKE_UP_STATUS, + PCOM_GET_BATT_LEVEL, + PCOM_CHG_IS_CHARGING, + PCOM_POWER_DOWN, + PCOM_USB_PIN_CONFIG, + PCOM_USB_PIN_SEL, + PCOM_SET_RTC_ALARM, + PCOM_NV_READ, + PCOM_NV_WRITE, + PCOM_GET_UUID_HIGH, + PCOM_GET_UUID_LOW, + PCOM_GET_HW_ENTROPY, + PCOM_RPC_GPIO_TLMM_CONFIG_REMOTE, + PCOM_CLKCTL_RPC_ENABLE, + PCOM_CLKCTL_RPC_DISABLE, + PCOM_CLKCTL_RPC_RESET, + PCOM_CLKCTL_RPC_SET_FLAGS, + PCOM_CLKCTL_RPC_SET_RATE, + PCOM_CLKCTL_RPC_MIN_RATE, + PCOM_CLKCTL_RPC_MAX_RATE, + PCOM_CLKCTL_RPC_RATE, + PCOM_CLKCTL_RPC_PLL_REQUEST, + PCOM_CLKCTL_RPC_ENABLED, + PCOM_VREG_SWITCH, + PCOM_VREG_SET_LEVEL, + PCOM_GPIO_TLMM_CONFIG_GROUP, + PCOM_GPIO_TLMM_UNCONFIG_GROUP, + PCOM_NV_WRITE_BYTES_4_7, + PCOM_CONFIG_DISP, + PCOM_GET_FTM_BOOT_COUNT, + PCOM_RPC_GPIO_TLMM_CONFIG_EX, + PCOM_PM_MPP_CONFIG, + PCOM_GPIO_IN, + PCOM_GPIO_OUT, + PCOM_RESET_MODEM, + PCOM_RESET_CHIP_IMM, + PCOM_PM_VID_EN, + PCOM_VREG_PULLDOWN, + PCOM_GET_MODEM_VERSION, + PCOM_CLK_REGIME_SEC_RESET, + PCOM_CLK_REGIME_SEC_RESET_ASSERT, + PCOM_CLK_REGIME_SEC_RESET_DEASSERT, + PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP, + PCOM_CLK_REGIME_SEC_ENABLE, + PCOM_CLK_REGIME_SEC_DISABLE, + PCOM_CLK_REGIME_SEC_IS_ON, + PCOM_CLK_REGIME_SEC_SEL_CLK_INV, + PCOM_CLK_REGIME_SEC_SEL_CLK_SRC, + PCOM_CLK_REGIME_SEC_SEL_CLK_DIV, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE, + PCOM_CLK_REGIME_SEC_SEL_SPEED, + PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP, + PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP, + PCOM_CLK_REGIME_SEC_USB_XTAL_ON, + PCOM_CLK_REGIME_SEC_USB_XTAL_OFF, + PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE, + PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK, + PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ, + PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ, + PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ, + PCOM_CLK_REGIME_SEC_SEL_VFE_SRC, + PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK, + PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK, + PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VFE_RAIL_ON, + PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF, + PCOM_CLK_REGIME_SEC_GRP_RAIL_ON, + PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VDC_RAIL_ON, + PCOM_CLK_REGIME_SEC_LCD_CTRL, + PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP, + PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER, + PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP, + PCOM_GPIO_CONFIG, + PCOM_GPIO_CONFIGURE_GROUP, + PCOM_GPIO_TLMM_SET_PORT, + PCOM_GPIO_TLMM_CONFIG_EX, + PCOM_SET_FTM_BOOT_COUNT, + PCOM_RESERVED0, + PCOM_RESERVED1, + PCOM_CUSTOMER_CMD1, + PCOM_CUSTOMER_CMD2, + PCOM_CUSTOMER_CMD3, + PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_SEC_RAIL_DISABLE, + PCOM_CLK_REGIME_SEC_RAIL_ENABLE, + PCOM_CLK_REGIME_SEC_RAIL_CONTROL, + PCOM_SET_SW_WATCHDOG_STATE, + PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, + PCOM_PM_MPP_CONFIG_I_SINK, + PCOM_RESERVED_101, + PCOM_MSM_HSUSB_PHY_RESET, + PCOM_GET_BATT_MV_LEVEL, + PCOM_CHG_USB_IS_PC_CONNECTED, + PCOM_CHG_USB_IS_CHARGER_CONNECTED, + PCOM_CHG_USB_IS_DISCONNECTED, + PCOM_CHG_USB_IS_AVAILABLE, + PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ, + PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY, + PCOM_CLKCTL_RPC_RESET_ASSERT, + PCOM_CLKCTL_RPC_RESET_DEASSERT, + PCOM_CLKCTL_RPC_RAIL_ON, + PCOM_CLKCTL_RPC_RAIL_OFF, + PCOM_CLKCTL_RPC_RAIL_ENABLE, + PCOM_CLKCTL_RPC_RAIL_DISABLE, + PCOM_CLKCTL_RPC_RAIL_CONTROL, + PCOM_CLKCTL_RPC_MIN_MSMC1, + PCOM_CLKCTL_RPC_SRC_REQUEST, + PCOM_NPA_INIT, + PCOM_NPA_ISSUE_REQUIRED_REQUEST, + PCOM_CLKCTL_RPC_SET_EXT_CONFIG, +}; + +enum { + PCOM_OEM_FIRST_CMD = 0x10000000, + PCOM_OEM_TEST_CMD = PCOM_OEM_FIRST_CMD, + + /* add OEM PROC COMM commands here */ + + PCOM_OEM_LAST = PCOM_OEM_TEST_CMD, +}; + +enum { + PCOM_INVALID_STATUS = 0x0, + PCOM_READY, + PCOM_CMD_RUNNING, + PCOM_CMD_SUCCESS, + PCOM_CMD_FAIL, + PCOM_CMD_FAIL_FALSE_RETURNED, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT, + PCOM_CMD_FAIL_CMD_UNREGISTERED, + PCOM_CMD_FAIL_CMD_LOCKED, + PCOM_CMD_FAIL_SERVER_NOT_YET_READY, + PCOM_CMD_FAIL_BAD_DESTINATION, + PCOM_CMD_FAIL_SERVER_RESET, + PCOM_CMD_FAIL_SMSM_NOT_INIT, + PCOM_CMD_FAIL_PROC_COMM_BUSY, + PCOM_CMD_FAIL_PROC_COMM_NOT_INIT, +}; + +#ifdef CONFIG_MSM_PROC_COMM +void msm_proc_comm_reset_modem_now(void); +int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2); +#else +static inline void msm_proc_comm_reset_modem_now(void) { } +static inline int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2) +{ return 0; } +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h new file mode 100644 index 000000000000..e31feb041f5d --- /dev/null +++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h @@ -0,0 +1,228 @@ +/* Copyright (c) 2010-2012, 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. + */ + +#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H +#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H + +#include <linux/regulator/machine.h> + +#define RPM_REGULATOR_DEV_NAME "rpm-regulator" + +/** + * enum rpm_vreg_version - supported RPM regulator versions + */ +enum rpm_vreg_version { + RPM_VREG_VERSION_8660, + RPM_VREG_VERSION_8960, + RPM_VREG_VERSION_9615, + RPM_VREG_VERSION_8930, + RPM_VREG_VERSION_8930_PM8917, + RPM_VREG_VERSION_8960_PM8917, + RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8960_PM8917, +}; + +#define RPM_VREG_PIN_CTRL_NONE 0x00 + +/** + * enum rpm_vreg_state - enable state for switch or NCP + */ +enum rpm_vreg_state { + RPM_VREG_STATE_OFF, + RPM_VREG_STATE_ON, +}; + +/** + * enum rpm_vreg_freq - switching frequency for SMPS or NCP + */ +enum rpm_vreg_freq { + RPM_VREG_FREQ_NONE, + RPM_VREG_FREQ_19p20, + RPM_VREG_FREQ_9p60, + RPM_VREG_FREQ_6p40, + RPM_VREG_FREQ_4p80, + RPM_VREG_FREQ_3p84, + RPM_VREG_FREQ_3p20, + RPM_VREG_FREQ_2p74, + RPM_VREG_FREQ_2p40, + RPM_VREG_FREQ_2p13, + RPM_VREG_FREQ_1p92, + RPM_VREG_FREQ_1p75, + RPM_VREG_FREQ_1p60, + RPM_VREG_FREQ_1p48, + RPM_VREG_FREQ_1p37, + RPM_VREG_FREQ_1p28, + RPM_VREG_FREQ_1p20, +}; + +/** + * enum rpm_vreg_voltage_corner - possible voltage corner values + * + * These should be used in regulator_set_voltage and rpm_vreg_set_voltage calls + * for corner type regulators as if they had units of uV. + */ +enum rpm_vreg_voltage_corner { + RPM_VREG_CORNER_NONE = 1, + RPM_VREG_CORNER_LOW, + RPM_VREG_CORNER_NOMINAL, + RPM_VREG_CORNER_HIGH, +}; + +/** + * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs + */ +enum rpm_vreg_voter { + RPM_VREG_VOTER_REG_FRAMEWORK, /* for internal use only */ + RPM_VREG_VOTER1, /* for use by the acpu-clock driver */ + RPM_VREG_VOTER2, /* for use by the acpu-clock driver */ + RPM_VREG_VOTER3, /* for use by other drivers */ + RPM_VREG_VOTER4, /* for use by the acpu-clock driver */ + RPM_VREG_VOTER5, /* for use by the acpu-clock driver */ + RPM_VREG_VOTER6, /* for use by the acpu-clock driver */ + RPM_VREG_VOTER_COUNT, +}; + +/** + * struct rpm_regulator_init_data - RPM regulator initialization data + * @init_data: regulator constraints + * @id: regulator id; from enum rpm_vreg_id + * @sleep_selectable: flag which indicates that regulator should be accessable + * by external private API + * @system_uA: current drawn from regulator not accounted for by any + * regulator framework consumer + * @enable_time: time in us taken to enable a regulator to the maximum + * allowed voltage for the system. This is dependent upon + * the load and capacitance for a regulator on the board. + * @pull_down_enable: 0 = no pulldown, 1 = pulldown when regulator disabled + * @freq: enum value representing the switching frequency of an + * SMPS or NCP + * @pin_ctrl: pin control inputs to use for the regulator; should be + * a combination of RPM_VREG_PIN_CTRL_* values + * @pin_fn: action to perform when pin control pin(s) is/are active + * @force_mode: used to specify a force mode which overrides the votes + * of other RPM masters. + * @sleep_set_force_mode: force mode to use in sleep-set requests + * @power_mode: mode to use as HPM (typically PWM or hysteretic) when + * utilizing Auto mode selection + * @default_uV: initial voltage to set the regulator to if enable is + * called before set_voltage (e.g. when boot_on or + * always_on is set). + * @peak_uA: initial peak load requirement sent in RPM request; used + * to determine initial mode. + * @avg_uA: average load requirement sent in RPM request + * @state: initial enable state sent in RPM request for switch or + * NCP + */ +struct rpm_regulator_init_data { + struct regulator_init_data init_data; + int id; + int sleep_selectable; + int system_uA; + int enable_time; + unsigned pull_down_enable; + enum rpm_vreg_freq freq; + unsigned pin_ctrl; + int pin_fn; + int force_mode; + int sleep_set_force_mode; + int power_mode; + int default_uV; + unsigned peak_uA; + unsigned avg_uA; + enum rpm_vreg_state state; +}; + +/** + * struct rpm_regulator_consumer_mapping - mapping used by private consumers + */ +struct rpm_regulator_consumer_mapping { + const char *dev_name; + const char *supply; + int vreg_id; + enum rpm_vreg_voter voter; + int sleep_also; +}; + +/** + * struct rpm_regulator_platform_data - RPM regulator platform data + */ +struct rpm_regulator_platform_data { + struct rpm_regulator_init_data *init_data; + int num_regulators; + enum rpm_vreg_version version; + int vreg_id_vdd_mem; + int vreg_id_vdd_dig; + bool requires_tcxo_workaround; + struct rpm_regulator_consumer_mapping *consumer_map; + int consumer_map_len; +}; + +#ifdef CONFIG_MSM_RPM_REGULATOR +/** + * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor + * @vreg: ID for regulator + * @voter: ID for the voter + * @min_uV: minimum acceptable voltage (in uV) that is voted for + * @max_uV: maximum acceptable voltage (in uV) that is voted for + * @sleep_also: 0 for active set only, non-0 for active set and sleep set + * + * Returns 0 on success or errno. + * + * This function is used to vote for the voltage of a regulator without + * using the regulator framework. It is needed for consumers which wish to only + * vote for active set regulator voltage. + * + * If sleep_also == 0, then a sleep-set value of 0V will be voted for. + * + * This function may only be called for regulators which have the sleep flag + * specified in their private data. + * + * Consumers can vote to disable a regulator with this function by passing + * min_uV = 0 and max_uV = 0. + * + * Voltage switch type regulators may be controlled via rpm_vreg_set_voltage + * as well. For this type of regulator, max_uV > 0 is treated as an enable + * request and max_uV == 0 is treated as a disable request. + */ +int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV, + int max_uV, int sleep_also); + +/** + * rpm_vreg_set_frequency - sets the frequency of a switching regulator + * @vreg: ID for regulator + * @freq: enum corresponding to desired frequency + * + * Returns 0 on success or errno. + */ +int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq); + +#else + +/* + * These stubs exist to allow consumers of these APIs to compile and run + * in absence of a real RPM regulator driver. It is assumed that they are + * aware of the state of their regulators and have either set them + * correctly by some other means or don't care about their state at all. + */ +static inline int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, + int min_uV, int max_uV, int sleep_also) +{ + return 0; +} + +static inline int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq) +{ + return 0; +} + +#endif /* CONFIG_MSM_RPM_REGULATOR */ + +#endif diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h new file mode 100644 index 000000000000..7b7313a3b8c4 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/rpm.h @@ -0,0 +1,1186 @@ +/* Copyright (c) 2010-2013, 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_RPM_H +#define __ARCH_ARM_MACH_MSM_RPM_H + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/semaphore.h> + +#define SEL_MASK_SIZE (5) + +enum { + MSM_RPM_PAGE_STATUS, + MSM_RPM_PAGE_CTRL, + MSM_RPM_PAGE_REQ, + MSM_RPM_PAGE_ACK, + MSM_RPM_PAGE_COUNT +}; + +enum { + MSM_RPM_CTX_SET_0, + MSM_RPM_CTX_SET_SLEEP, + MSM_RPM_CTX_SET_COUNT, + + MSM_RPM_CTX_NOTIFICATION = 30, + MSM_RPM_CTX_REJECTED = 31, +}; + +/* RPM control message RAM enums */ +enum { + MSM_RPM_CTRL_VERSION_MAJOR, + MSM_RPM_CTRL_VERSION_MINOR, + MSM_RPM_CTRL_VERSION_BUILD, + + MSM_RPM_CTRL_REQ_CTX_0, + MSM_RPM_CTRL_REQ_SEL_0, + MSM_RPM_CTRL_ACK_CTX_0, + MSM_RPM_CTRL_ACK_SEL_0, + + MSM_RPM_CTRL_LAST, +}; + +enum { + MSM_RPM_ID_NOTIFICATION_CONFIGURED_0 = 0, + MSM_RPM_ID_NOTIFICATION_CONFIGURED_7 = + MSM_RPM_ID_NOTIFICATION_CONFIGURED_0 + 7, + + MSM_RPM_ID_NOTIFICATION_REGISTERED_0, + MSM_RPM_ID_NOTIFICATION_REGISTERED_7 = + MSM_RPM_ID_NOTIFICATION_REGISTERED_0 + 7, + + MSM_RPM_ID_INVALIDATE_0, + MSM_RPM_ID_INVALIDATE_7 = + MSM_RPM_ID_INVALIDATE_0 + 7, + + MSM_RPM_ID_TRIGGER_TIMED_TO, + MSM_RPM_ID_TRIGGER_TIMED_0, + MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT, + + MSM_RPM_ID_RPM_CTL, + + /* TRIGGER_CLEAR/SET deprecated in these 24 RESERVED bytes */ + MSM_RPM_ID_RESERVED_0, + MSM_RPM_ID_RESERVED_5 = + MSM_RPM_ID_RESERVED_0 + 5, + + MSM_RPM_ID_CXO_CLK, + MSM_RPM_ID_PXO_CLK, + MSM_RPM_ID_APPS_FABRIC_CLK, + MSM_RPM_ID_SYSTEM_FABRIC_CLK, + MSM_RPM_ID_MM_FABRIC_CLK, + MSM_RPM_ID_DAYTONA_FABRIC_CLK, + MSM_RPM_ID_SFPB_CLK, + MSM_RPM_ID_CFPB_CLK, + MSM_RPM_ID_MMFPB_CLK, + MSM_RPM_ID_EBI1_CLK, + + MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0, + MSM_RPM_ID_APPS_FABRIC_HALT_0 = + MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0, + MSM_RPM_ID_APPS_FABRIC_CFG_HALT_1, + MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_0, + MSM_RPM_ID_APPS_FABRIC_CLOCK_MODE_0 = + MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_0, + MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_1, + MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_2, + MSM_RPM_ID_APPS_FABRIC_CFG_IOCTL, + MSM_RPM_ID_APPS_FABRIC_ARB_0, + MSM_RPM_ID_APPS_FABRIC_ARB_11 = + MSM_RPM_ID_APPS_FABRIC_ARB_0 + 11, + + MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0, + MSM_RPM_ID_SYSTEM_FABRIC_HALT_0 = + MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0, + MSM_RPM_ID_SYS_FABRIC_CFG_HALT_1, + MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_0, + MSM_RPM_ID_SYSTEM_FABRIC_CLOCK_MODE_0 = + MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_0, + MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_1, + MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_2, + MSM_RPM_ID_SYS_FABRIC_CFG_IOCTL, + MSM_RPM_ID_SYSTEM_FABRIC_ARB_0, + MSM_RPM_ID_SYSTEM_FABRIC_ARB_29 = + MSM_RPM_ID_SYSTEM_FABRIC_ARB_0 + 29, + + MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0, + MSM_RPM_ID_MM_FABRIC_HALT_0 = + MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0, + MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_1, + MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_0, + MSM_RPM_ID_MM_FABRIC_CLOCK_MODE_0 = + MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_0, + MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_1, + MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_2, + MSM_RPM_ID_MMSS_FABRIC_CFG_IOCTL, + MSM_RPM_ID_MM_FABRIC_ARB_0, + MSM_RPM_ID_MM_FABRIC_ARB_22 = + MSM_RPM_ID_MM_FABRIC_ARB_0 + 22, + + MSM_RPM_ID_PM8921_S1_0, + MSM_RPM_ID_PM8921_S1_1, + MSM_RPM_ID_PM8921_S2_0, + MSM_RPM_ID_PM8921_S2_1, + MSM_RPM_ID_PM8921_S3_0, + MSM_RPM_ID_PM8921_S3_1, + MSM_RPM_ID_PM8921_S4_0, + MSM_RPM_ID_PM8921_S4_1, + MSM_RPM_ID_PM8921_S5_0, + MSM_RPM_ID_PM8921_S5_1, + MSM_RPM_ID_PM8921_S6_0, + MSM_RPM_ID_PM8921_S6_1, + MSM_RPM_ID_PM8921_S7_0, + MSM_RPM_ID_PM8921_S7_1, + MSM_RPM_ID_PM8921_S8_0, + MSM_RPM_ID_PM8921_S8_1, + MSM_RPM_ID_PM8921_L1_0, + MSM_RPM_ID_PM8921_L1_1, + MSM_RPM_ID_PM8921_L2_0, + MSM_RPM_ID_PM8921_L2_1, + MSM_RPM_ID_PM8921_L3_0, + MSM_RPM_ID_PM8921_L3_1, + MSM_RPM_ID_PM8921_L4_0, + MSM_RPM_ID_PM8921_L4_1, + MSM_RPM_ID_PM8921_L5_0, + MSM_RPM_ID_PM8921_L5_1, + MSM_RPM_ID_PM8921_L6_0, + MSM_RPM_ID_PM8921_L6_1, + MSM_RPM_ID_PM8921_L7_0, + MSM_RPM_ID_PM8921_L7_1, + MSM_RPM_ID_PM8921_L8_0, + MSM_RPM_ID_PM8921_L8_1, + MSM_RPM_ID_PM8921_L9_0, + MSM_RPM_ID_PM8921_L9_1, + MSM_RPM_ID_PM8921_L10_0, + MSM_RPM_ID_PM8921_L10_1, + MSM_RPM_ID_PM8921_L11_0, + MSM_RPM_ID_PM8921_L11_1, + MSM_RPM_ID_PM8921_L12_0, + MSM_RPM_ID_PM8921_L12_1, + MSM_RPM_ID_PM8921_L13_0, + MSM_RPM_ID_PM8921_L13_1, + MSM_RPM_ID_PM8921_L14_0, + MSM_RPM_ID_PM8921_L14_1, + MSM_RPM_ID_PM8921_L15_0, + MSM_RPM_ID_PM8921_L15_1, + MSM_RPM_ID_PM8921_L16_0, + MSM_RPM_ID_PM8921_L16_1, + MSM_RPM_ID_PM8921_L17_0, + MSM_RPM_ID_PM8921_L17_1, + MSM_RPM_ID_PM8921_L18_0, + MSM_RPM_ID_PM8921_L18_1, + MSM_RPM_ID_PM8921_L19_0, + MSM_RPM_ID_PM8921_L19_1, + MSM_RPM_ID_PM8921_L20_0, + MSM_RPM_ID_PM8921_L20_1, + MSM_RPM_ID_PM8921_L21_0, + MSM_RPM_ID_PM8921_L21_1, + MSM_RPM_ID_PM8921_L22_0, + MSM_RPM_ID_PM8921_L22_1, + MSM_RPM_ID_PM8921_L23_0, + MSM_RPM_ID_PM8921_L23_1, + MSM_RPM_ID_PM8921_L24_0, + MSM_RPM_ID_PM8921_L24_1, + MSM_RPM_ID_PM8921_L25_0, + MSM_RPM_ID_PM8921_L25_1, + MSM_RPM_ID_PM8921_L26_0, + MSM_RPM_ID_PM8921_L26_1, + MSM_RPM_ID_PM8921_L27_0, + MSM_RPM_ID_PM8921_L27_1, + MSM_RPM_ID_PM8921_L28_0, + MSM_RPM_ID_PM8921_L28_1, + MSM_RPM_ID_PM8921_L29_0, + MSM_RPM_ID_PM8921_L29_1, + MSM_RPM_ID_PM8921_CLK1_0, + MSM_RPM_ID_PM8921_CLK1_1, + MSM_RPM_ID_PM8921_CLK2_0, + MSM_RPM_ID_PM8921_CLK2_1, + MSM_RPM_ID_PM8921_LVS1, + MSM_RPM_ID_PM8921_LVS2, + MSM_RPM_ID_PM8921_LVS3, + MSM_RPM_ID_PM8921_LVS4, + MSM_RPM_ID_PM8921_LVS5, + MSM_RPM_ID_PM8921_LVS6, + MSM_RPM_ID_PM8921_LVS7, + MSM_RPM_ID_NCP_0, + MSM_RPM_ID_NCP_1, + MSM_RPM_ID_CXO_BUFFERS, + MSM_RPM_ID_USB_OTG_SWITCH, + MSM_RPM_ID_HDMI_SWITCH, + MSM_RPM_ID_DDR_DMM_0, + MSM_RPM_ID_DDR_DMM_1, + MSM_RPM_ID_QDSS_CLK, + + /* 8660 specific ids */ + MSM_RPM_ID_TRIGGER_SET_FROM, + MSM_RPM_ID_TRIGGER_SET_TO, + MSM_RPM_ID_TRIGGER_SET_TRIGGER, + + MSM_RPM_ID_TRIGGER_CLEAR_FROM, + MSM_RPM_ID_TRIGGER_CLEAR_TO, + MSM_RPM_ID_TRIGGER_CLEAR_TRIGGER, + MSM_RPM_ID_PLL_4, + MSM_RPM_ID_SMI_CLK, + MSM_RPM_ID_APPS_L2_CACHE_CTL, + + /* pmic 8901 */ + MSM_RPM_ID_SMPS0B_0, + MSM_RPM_ID_SMPS0B_1, + MSM_RPM_ID_SMPS1B_0, + MSM_RPM_ID_SMPS1B_1, + MSM_RPM_ID_SMPS2B_0, + MSM_RPM_ID_SMPS2B_1, + MSM_RPM_ID_SMPS3B_0, + MSM_RPM_ID_SMPS3B_1, + MSM_RPM_ID_SMPS4B_0, + MSM_RPM_ID_SMPS4B_1, + MSM_RPM_ID_LDO0B_0, + MSM_RPM_ID_LDO0B_1, + MSM_RPM_ID_LDO1B_0, + MSM_RPM_ID_LDO1B_1, + MSM_RPM_ID_LDO2B_0, + MSM_RPM_ID_LDO2B_1, + MSM_RPM_ID_LDO3B_0, + MSM_RPM_ID_LDO3B_1, + MSM_RPM_ID_LDO4B_0, + MSM_RPM_ID_LDO4B_1, + MSM_RPM_ID_LDO5B_0, + MSM_RPM_ID_LDO5B_1, + MSM_RPM_ID_LDO6B_0, + MSM_RPM_ID_LDO6B_1, + MSM_RPM_ID_LVS0B, + MSM_RPM_ID_LVS1B, + MSM_RPM_ID_LVS2B, + MSM_RPM_ID_LVS3B, + MSM_RPM_ID_MVS, + + /* pmic 8058 */ + MSM_RPM_ID_SMPS0_0, + MSM_RPM_ID_SMPS0_1, + MSM_RPM_ID_SMPS1_0, + MSM_RPM_ID_SMPS1_1, + MSM_RPM_ID_SMPS2_0, + MSM_RPM_ID_SMPS2_1, + MSM_RPM_ID_SMPS3_0, + MSM_RPM_ID_SMPS3_1, + MSM_RPM_ID_SMPS4_0, + MSM_RPM_ID_SMPS4_1, + MSM_RPM_ID_LDO0_0, + MSM_RPM_ID_LDO0_1, + MSM_RPM_ID_LDO1_0, + MSM_RPM_ID_LDO1_1, + MSM_RPM_ID_LDO2_0, + MSM_RPM_ID_LDO2_1, + MSM_RPM_ID_LDO3_0, + MSM_RPM_ID_LDO3_1, + MSM_RPM_ID_LDO4_0, + MSM_RPM_ID_LDO4_1, + MSM_RPM_ID_LDO5_0, + MSM_RPM_ID_LDO5_1, + MSM_RPM_ID_LDO6_0, + MSM_RPM_ID_LDO6_1, + MSM_RPM_ID_LDO7_0, + MSM_RPM_ID_LDO7_1, + MSM_RPM_ID_LDO8_0, + MSM_RPM_ID_LDO8_1, + MSM_RPM_ID_LDO9_0, + MSM_RPM_ID_LDO9_1, + MSM_RPM_ID_LDO10_0, + MSM_RPM_ID_LDO10_1, + MSM_RPM_ID_LDO11_0, + MSM_RPM_ID_LDO11_1, + MSM_RPM_ID_LDO12_0, + MSM_RPM_ID_LDO12_1, + MSM_RPM_ID_LDO13_0, + MSM_RPM_ID_LDO13_1, + MSM_RPM_ID_LDO14_0, + MSM_RPM_ID_LDO14_1, + MSM_RPM_ID_LDO15_0, + MSM_RPM_ID_LDO15_1, + MSM_RPM_ID_LDO16_0, + MSM_RPM_ID_LDO16_1, + MSM_RPM_ID_LDO17_0, + MSM_RPM_ID_LDO17_1, + MSM_RPM_ID_LDO18_0, + MSM_RPM_ID_LDO18_1, + MSM_RPM_ID_LDO19_0, + MSM_RPM_ID_LDO19_1, + MSM_RPM_ID_LDO20_0, + MSM_RPM_ID_LDO20_1, + MSM_RPM_ID_LDO21_0, + MSM_RPM_ID_LDO21_1, + MSM_RPM_ID_LDO22_0, + MSM_RPM_ID_LDO22_1, + MSM_RPM_ID_LDO23_0, + MSM_RPM_ID_LDO23_1, + MSM_RPM_ID_LDO24_0, + MSM_RPM_ID_LDO24_1, + MSM_RPM_ID_LDO25_0, + MSM_RPM_ID_LDO25_1, + MSM_RPM_ID_LVS0, + MSM_RPM_ID_LVS1, + + /* 9615 specific */ + MSM_RPM_ID_PM8018_S1_0, + MSM_RPM_ID_PM8018_S1_1, + MSM_RPM_ID_PM8018_S2_0, + MSM_RPM_ID_PM8018_S2_1, + MSM_RPM_ID_PM8018_S3_0, + MSM_RPM_ID_PM8018_S3_1, + MSM_RPM_ID_PM8018_S4_0, + MSM_RPM_ID_PM8018_S4_1, + MSM_RPM_ID_PM8018_S5_0, + MSM_RPM_ID_PM8018_S5_1, + MSM_RPM_ID_PM8018_L1_0, + MSM_RPM_ID_PM8018_L1_1, + MSM_RPM_ID_PM8018_L2_0, + MSM_RPM_ID_PM8018_L2_1, + MSM_RPM_ID_PM8018_L3_0, + MSM_RPM_ID_PM8018_L3_1, + MSM_RPM_ID_PM8018_L4_0, + MSM_RPM_ID_PM8018_L4_1, + MSM_RPM_ID_PM8018_L5_0, + MSM_RPM_ID_PM8018_L5_1, + MSM_RPM_ID_PM8018_L6_0, + MSM_RPM_ID_PM8018_L6_1, + MSM_RPM_ID_PM8018_L7_0, + MSM_RPM_ID_PM8018_L7_1, + MSM_RPM_ID_PM8018_L8_0, + MSM_RPM_ID_PM8018_L8_1, + MSM_RPM_ID_PM8018_L9_0, + MSM_RPM_ID_PM8018_L9_1, + MSM_RPM_ID_PM8018_L10_0, + MSM_RPM_ID_PM8018_L10_1, + MSM_RPM_ID_PM8018_L11_0, + MSM_RPM_ID_PM8018_L11_1, + MSM_RPM_ID_PM8018_L12_0, + MSM_RPM_ID_PM8018_L12_1, + MSM_RPM_ID_PM8018_L13_0, + MSM_RPM_ID_PM8018_L13_1, + MSM_RPM_ID_PM8018_L14_0, + MSM_RPM_ID_PM8018_L14_1, + MSM_RPM_ID_PM8018_LVS1, + + /* 8930 specific */ + MSM_RPM_ID_PM8038_S1_0, + MSM_RPM_ID_PM8038_S1_1, + MSM_RPM_ID_PM8038_S2_0, + MSM_RPM_ID_PM8038_S2_1, + MSM_RPM_ID_PM8038_S3_0, + MSM_RPM_ID_PM8038_S3_1, + MSM_RPM_ID_PM8038_S4_0, + MSM_RPM_ID_PM8038_S4_1, + MSM_RPM_ID_PM8038_S5_0, + MSM_RPM_ID_PM8038_S5_1, + MSM_RPM_ID_PM8038_S6_0, + MSM_RPM_ID_PM8038_S6_1, + MSM_RPM_ID_PM8038_L1_0, + MSM_RPM_ID_PM8038_L1_1, + MSM_RPM_ID_PM8038_L2_0, + MSM_RPM_ID_PM8038_L2_1, + MSM_RPM_ID_PM8038_L3_0, + MSM_RPM_ID_PM8038_L3_1, + MSM_RPM_ID_PM8038_L4_0, + MSM_RPM_ID_PM8038_L4_1, + MSM_RPM_ID_PM8038_L5_0, + MSM_RPM_ID_PM8038_L5_1, + MSM_RPM_ID_PM8038_L6_0, + MSM_RPM_ID_PM8038_L6_1, + MSM_RPM_ID_PM8038_L7_0, + MSM_RPM_ID_PM8038_L7_1, + MSM_RPM_ID_PM8038_L8_0, + MSM_RPM_ID_PM8038_L8_1, + MSM_RPM_ID_PM8038_L9_0, + MSM_RPM_ID_PM8038_L9_1, + MSM_RPM_ID_PM8038_L10_0, + MSM_RPM_ID_PM8038_L10_1, + MSM_RPM_ID_PM8038_L11_0, + MSM_RPM_ID_PM8038_L11_1, + MSM_RPM_ID_PM8038_L12_0, + MSM_RPM_ID_PM8038_L12_1, + MSM_RPM_ID_PM8038_L13_0, + MSM_RPM_ID_PM8038_L13_1, + MSM_RPM_ID_PM8038_L14_0, + MSM_RPM_ID_PM8038_L14_1, + MSM_RPM_ID_PM8038_L15_0, + MSM_RPM_ID_PM8038_L15_1, + MSM_RPM_ID_PM8038_L16_0, + MSM_RPM_ID_PM8038_L16_1, + MSM_RPM_ID_PM8038_L17_0, + MSM_RPM_ID_PM8038_L17_1, + MSM_RPM_ID_PM8038_L18_0, + MSM_RPM_ID_PM8038_L18_1, + MSM_RPM_ID_PM8038_L19_0, + MSM_RPM_ID_PM8038_L19_1, + MSM_RPM_ID_PM8038_L20_0, + MSM_RPM_ID_PM8038_L20_1, + MSM_RPM_ID_PM8038_L21_0, + MSM_RPM_ID_PM8038_L21_1, + MSM_RPM_ID_PM8038_L22_0, + MSM_RPM_ID_PM8038_L22_1, + MSM_RPM_ID_PM8038_L23_0, + MSM_RPM_ID_PM8038_L23_1, + MSM_RPM_ID_PM8038_L24_0, + MSM_RPM_ID_PM8038_L24_1, + MSM_RPM_ID_PM8038_L25_0, + MSM_RPM_ID_PM8038_L25_1, + MSM_RPM_ID_PM8038_L26_0, + MSM_RPM_ID_PM8038_L26_1, + MSM_RPM_ID_PM8038_L27_0, + MSM_RPM_ID_PM8038_L27_1, + MSM_RPM_ID_PM8038_CLK1_0, + MSM_RPM_ID_PM8038_CLK1_1, + MSM_RPM_ID_PM8038_CLK2_0, + MSM_RPM_ID_PM8038_CLK2_1, + MSM_RPM_ID_PM8038_LVS1, + MSM_RPM_ID_PM8038_LVS2, + + /* PM8917 specific */ + MSM_RPM_ID_PM8917_S1_0, + MSM_RPM_ID_PM8917_S1_1, + MSM_RPM_ID_PM8917_S2_0, + MSM_RPM_ID_PM8917_S2_1, + MSM_RPM_ID_PM8917_S3_0, + MSM_RPM_ID_PM8917_S3_1, + MSM_RPM_ID_PM8917_S4_0, + MSM_RPM_ID_PM8917_S4_1, + MSM_RPM_ID_PM8917_S5_0, + MSM_RPM_ID_PM8917_S5_1, + MSM_RPM_ID_PM8917_S6_0, + MSM_RPM_ID_PM8917_S6_1, + MSM_RPM_ID_PM8917_S7_0, + MSM_RPM_ID_PM8917_S7_1, + MSM_RPM_ID_PM8917_S8_0, + MSM_RPM_ID_PM8917_S8_1, + MSM_RPM_ID_PM8917_L1_0, + MSM_RPM_ID_PM8917_L1_1, + MSM_RPM_ID_PM8917_L2_0, + MSM_RPM_ID_PM8917_L2_1, + MSM_RPM_ID_PM8917_L3_0, + MSM_RPM_ID_PM8917_L3_1, + MSM_RPM_ID_PM8917_L4_0, + MSM_RPM_ID_PM8917_L4_1, + MSM_RPM_ID_PM8917_L5_0, + MSM_RPM_ID_PM8917_L5_1, + MSM_RPM_ID_PM8917_L6_0, + MSM_RPM_ID_PM8917_L6_1, + MSM_RPM_ID_PM8917_L7_0, + MSM_RPM_ID_PM8917_L7_1, + MSM_RPM_ID_PM8917_L8_0, + MSM_RPM_ID_PM8917_L8_1, + MSM_RPM_ID_PM8917_L9_0, + MSM_RPM_ID_PM8917_L9_1, + MSM_RPM_ID_PM8917_L10_0, + MSM_RPM_ID_PM8917_L10_1, + MSM_RPM_ID_PM8917_L11_0, + MSM_RPM_ID_PM8917_L11_1, + MSM_RPM_ID_PM8917_L12_0, + MSM_RPM_ID_PM8917_L12_1, + MSM_RPM_ID_PM8917_L14_0, + MSM_RPM_ID_PM8917_L14_1, + MSM_RPM_ID_PM8917_L15_0, + MSM_RPM_ID_PM8917_L15_1, + MSM_RPM_ID_PM8917_L16_0, + MSM_RPM_ID_PM8917_L16_1, + MSM_RPM_ID_PM8917_L17_0, + MSM_RPM_ID_PM8917_L17_1, + MSM_RPM_ID_PM8917_L18_0, + MSM_RPM_ID_PM8917_L18_1, + MSM_RPM_ID_PM8917_L21_0, + MSM_RPM_ID_PM8917_L21_1, + MSM_RPM_ID_PM8917_L22_0, + MSM_RPM_ID_PM8917_L22_1, + MSM_RPM_ID_PM8917_L23_0, + MSM_RPM_ID_PM8917_L23_1, + MSM_RPM_ID_PM8917_L24_0, + MSM_RPM_ID_PM8917_L24_1, + MSM_RPM_ID_PM8917_L25_0, + MSM_RPM_ID_PM8917_L25_1, + MSM_RPM_ID_PM8917_L26_0, + MSM_RPM_ID_PM8917_L26_1, + MSM_RPM_ID_PM8917_L27_0, + MSM_RPM_ID_PM8917_L27_1, + MSM_RPM_ID_PM8917_L28_0, + MSM_RPM_ID_PM8917_L28_1, + MSM_RPM_ID_PM8917_L29_0, + MSM_RPM_ID_PM8917_L29_1, + MSM_RPM_ID_PM8917_L30_0, + MSM_RPM_ID_PM8917_L30_1, + MSM_RPM_ID_PM8917_L31_0, + MSM_RPM_ID_PM8917_L31_1, + MSM_RPM_ID_PM8917_L32_0, + MSM_RPM_ID_PM8917_L32_1, + MSM_RPM_ID_PM8917_L33_0, + MSM_RPM_ID_PM8917_L33_1, + MSM_RPM_ID_PM8917_L34_0, + MSM_RPM_ID_PM8917_L34_1, + MSM_RPM_ID_PM8917_L35_0, + MSM_RPM_ID_PM8917_L35_1, + MSM_RPM_ID_PM8917_L36_0, + MSM_RPM_ID_PM8917_L36_1, + MSM_RPM_ID_PM8917_CLK1_0, + MSM_RPM_ID_PM8917_CLK1_1, + MSM_RPM_ID_PM8917_CLK2_0, + MSM_RPM_ID_PM8917_CLK2_1, + MSM_RPM_ID_PM8917_LVS1, + MSM_RPM_ID_PM8917_LVS3, + MSM_RPM_ID_PM8917_LVS4, + MSM_RPM_ID_PM8917_LVS5, + MSM_RPM_ID_PM8917_LVS6, + MSM_RPM_ID_PM8917_LVS7, + MSM_RPM_ID_VOLTAGE_CORNER, + + /* 8064 specific */ + MSM_RPM_ID_PM8821_S1_0, + MSM_RPM_ID_PM8821_S1_1, + MSM_RPM_ID_PM8821_S2_0, + MSM_RPM_ID_PM8821_S2_1, + MSM_RPM_ID_PM8821_L1_0, + MSM_RPM_ID_PM8821_L1_1, + MSM_RPM_ID_VDDMIN_GPIO, + + MSM_RPM_ID_LAST, +}; + +enum { + MSM_RPM_STATUS_ID_VERSION_MAJOR, + MSM_RPM_STATUS_ID_VERSION_MINOR, + MSM_RPM_STATUS_ID_VERSION_BUILD, + MSM_RPM_STATUS_ID_SUPPORTED_RESOURCES_0, + MSM_RPM_STATUS_ID_SUPPORTED_RESOURCES_1, + MSM_RPM_STATUS_ID_SUPPORTED_RESOURCES_2, + MSM_RPM_STATUS_ID_RESERVED_SUPPORTED_RESOURCES_0, + MSM_RPM_STATUS_ID_SEQUENCE, + MSM_RPM_STATUS_ID_RPM_CTL, + MSM_RPM_STATUS_ID_CXO_CLK, + MSM_RPM_STATUS_ID_PXO_CLK, + MSM_RPM_STATUS_ID_APPS_FABRIC_CLK, + MSM_RPM_STATUS_ID_SYSTEM_FABRIC_CLK, + MSM_RPM_STATUS_ID_MM_FABRIC_CLK, + MSM_RPM_STATUS_ID_DAYTONA_FABRIC_CLK, + MSM_RPM_STATUS_ID_SFPB_CLK, + MSM_RPM_STATUS_ID_CFPB_CLK, + MSM_RPM_STATUS_ID_MMFPB_CLK, + MSM_RPM_STATUS_ID_EBI1_CLK, + MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_HALT, + MSM_RPM_STATUS_ID_APPS_FABRIC_HALT = + MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_HALT, + MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_CLKMOD, + MSM_RPM_STATUS_ID_APPS_FABRIC_CLOCK_MODE = + MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_CLKMOD, + MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_IOCTL, + MSM_RPM_STATUS_ID_APPS_FABRIC_ARB, + MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_HALT, + MSM_RPM_STATUS_ID_SYSTEM_FABRIC_HALT = + MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_HALT, + MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_CLKMOD, + MSM_RPM_STATUS_ID_SYSTEM_FABRIC_CLOCK_MODE = + MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_CLKMOD, + MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_IOCTL, + MSM_RPM_STATUS_ID_SYSTEM_FABRIC_ARB, + MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_HALT, + MSM_RPM_STATUS_ID_MM_FABRIC_HALT = + MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_HALT, + MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD, + MSM_RPM_STATUS_ID_MM_FABRIC_CLOCK_MODE = + MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD, + MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_IOCTL, + MSM_RPM_STATUS_ID_MM_FABRIC_ARB, + MSM_RPM_STATUS_ID_PM8921_S1_0, + MSM_RPM_STATUS_ID_PM8921_S1_1, + MSM_RPM_STATUS_ID_PM8921_S2_0, + MSM_RPM_STATUS_ID_PM8921_S2_1, + MSM_RPM_STATUS_ID_PM8921_S3_0, + MSM_RPM_STATUS_ID_PM8921_S3_1, + MSM_RPM_STATUS_ID_PM8921_S4_0, + MSM_RPM_STATUS_ID_PM8921_S4_1, + MSM_RPM_STATUS_ID_PM8921_S5_0, + MSM_RPM_STATUS_ID_PM8921_S5_1, + MSM_RPM_STATUS_ID_PM8921_S6_0, + MSM_RPM_STATUS_ID_PM8921_S6_1, + MSM_RPM_STATUS_ID_PM8921_S7_0, + MSM_RPM_STATUS_ID_PM8921_S7_1, + MSM_RPM_STATUS_ID_PM8921_S8_0, + MSM_RPM_STATUS_ID_PM8921_S8_1, + MSM_RPM_STATUS_ID_PM8921_L1_0, + MSM_RPM_STATUS_ID_PM8921_L1_1, + MSM_RPM_STATUS_ID_PM8921_L2_0, + MSM_RPM_STATUS_ID_PM8921_L2_1, + MSM_RPM_STATUS_ID_PM8921_L3_0, + MSM_RPM_STATUS_ID_PM8921_L3_1, + MSM_RPM_STATUS_ID_PM8921_L4_0, + MSM_RPM_STATUS_ID_PM8921_L4_1, + MSM_RPM_STATUS_ID_PM8921_L5_0, + MSM_RPM_STATUS_ID_PM8921_L5_1, + MSM_RPM_STATUS_ID_PM8921_L6_0, + MSM_RPM_STATUS_ID_PM8921_L6_1, + MSM_RPM_STATUS_ID_PM8921_L7_0, + MSM_RPM_STATUS_ID_PM8921_L7_1, + MSM_RPM_STATUS_ID_PM8921_L8_0, + MSM_RPM_STATUS_ID_PM8921_L8_1, + MSM_RPM_STATUS_ID_PM8921_L9_0, + MSM_RPM_STATUS_ID_PM8921_L9_1, + MSM_RPM_STATUS_ID_PM8921_L10_0, + MSM_RPM_STATUS_ID_PM8921_L10_1, + MSM_RPM_STATUS_ID_PM8921_L11_0, + MSM_RPM_STATUS_ID_PM8921_L11_1, + MSM_RPM_STATUS_ID_PM8921_L12_0, + MSM_RPM_STATUS_ID_PM8921_L12_1, + MSM_RPM_STATUS_ID_PM8921_L13_0, + MSM_RPM_STATUS_ID_PM8921_L13_1, + MSM_RPM_STATUS_ID_PM8921_L14_0, + MSM_RPM_STATUS_ID_PM8921_L14_1, + MSM_RPM_STATUS_ID_PM8921_L15_0, + MSM_RPM_STATUS_ID_PM8921_L15_1, + MSM_RPM_STATUS_ID_PM8921_L16_0, + MSM_RPM_STATUS_ID_PM8921_L16_1, + MSM_RPM_STATUS_ID_PM8921_L17_0, + MSM_RPM_STATUS_ID_PM8921_L17_1, + MSM_RPM_STATUS_ID_PM8921_L18_0, + MSM_RPM_STATUS_ID_PM8921_L18_1, + MSM_RPM_STATUS_ID_PM8921_L19_0, + MSM_RPM_STATUS_ID_PM8921_L19_1, + MSM_RPM_STATUS_ID_PM8921_L20_0, + MSM_RPM_STATUS_ID_PM8921_L20_1, + MSM_RPM_STATUS_ID_PM8921_L21_0, + MSM_RPM_STATUS_ID_PM8921_L21_1, + MSM_RPM_STATUS_ID_PM8921_L22_0, + MSM_RPM_STATUS_ID_PM8921_L22_1, + MSM_RPM_STATUS_ID_PM8921_L23_0, + MSM_RPM_STATUS_ID_PM8921_L23_1, + MSM_RPM_STATUS_ID_PM8921_L24_0, + MSM_RPM_STATUS_ID_PM8921_L24_1, + MSM_RPM_STATUS_ID_PM8921_L25_0, + MSM_RPM_STATUS_ID_PM8921_L25_1, + MSM_RPM_STATUS_ID_PM8921_L26_0, + MSM_RPM_STATUS_ID_PM8921_L26_1, + MSM_RPM_STATUS_ID_PM8921_L27_0, + MSM_RPM_STATUS_ID_PM8921_L27_1, + MSM_RPM_STATUS_ID_PM8921_L28_0, + MSM_RPM_STATUS_ID_PM8921_L28_1, + MSM_RPM_STATUS_ID_PM8921_L29_0, + MSM_RPM_STATUS_ID_PM8921_L29_1, + MSM_RPM_STATUS_ID_PM8921_CLK1_0, + MSM_RPM_STATUS_ID_PM8921_CLK1_1, + MSM_RPM_STATUS_ID_PM8921_CLK2_0, + MSM_RPM_STATUS_ID_PM8921_CLK2_1, + MSM_RPM_STATUS_ID_PM8921_LVS1, + MSM_RPM_STATUS_ID_PM8921_LVS2, + MSM_RPM_STATUS_ID_PM8921_LVS3, + MSM_RPM_STATUS_ID_PM8921_LVS4, + MSM_RPM_STATUS_ID_PM8921_LVS5, + MSM_RPM_STATUS_ID_PM8921_LVS6, + MSM_RPM_STATUS_ID_PM8921_LVS7, + MSM_RPM_STATUS_ID_NCP_0, + MSM_RPM_STATUS_ID_NCP_1, + MSM_RPM_STATUS_ID_CXO_BUFFERS, + MSM_RPM_STATUS_ID_USB_OTG_SWITCH, + MSM_RPM_STATUS_ID_HDMI_SWITCH, + MSM_RPM_STATUS_ID_DDR_DMM_0, + MSM_RPM_STATUS_ID_DDR_DMM_1, + MSM_RPM_STATUS_ID_EBI1_CH0_RANGE, + MSM_RPM_STATUS_ID_EBI1_CH1_RANGE, + MSM_RPM_STATUS_ID_QDSS_CLK, + + /* 8930 aliases to simplify device mapping */ + MSM_RPM_STATUS_ID_PM8038_NCP_0 = MSM_RPM_STATUS_ID_NCP_0, + MSM_RPM_STATUS_ID_PM8038_NCP_1 = MSM_RPM_STATUS_ID_NCP_1, + MSM_RPM_STATUS_ID_PM8038_CXO_BUFFERS + = MSM_RPM_STATUS_ID_CXO_BUFFERS, + MSM_RPM_STATUS_ID_PM8038_USB_OTG_SWITCH + = MSM_RPM_STATUS_ID_USB_OTG_SWITCH, + MSM_RPM_STATUS_ID_PM8038_HDMI_SWITCH + = MSM_RPM_STATUS_ID_HDMI_SWITCH, + MSM_RPM_STATUS_ID_PM8038_QDSS_CLK + = MSM_RPM_STATUS_ID_QDSS_CLK, + + MSM_RPM_STATUS_ID_PM8917_NCP_0 = MSM_RPM_STATUS_ID_NCP_0, + MSM_RPM_STATUS_ID_PM8917_NCP_1 = MSM_RPM_STATUS_ID_NCP_1, + MSM_RPM_STATUS_ID_PM8917_CXO_BUFFERS + = MSM_RPM_STATUS_ID_CXO_BUFFERS, + MSM_RPM_STATUS_ID_PM8917_USB_OTG_SWITCH + = MSM_RPM_STATUS_ID_USB_OTG_SWITCH, + MSM_RPM_STATUS_ID_PM8917_HDMI_SWITCH + = MSM_RPM_STATUS_ID_HDMI_SWITCH, + MSM_RPM_STATUS_ID_PM8917_QDSS_CLK + = MSM_RPM_STATUS_ID_QDSS_CLK, + + /* 8660 Specific */ + MSM_RPM_STATUS_ID_PLL_4, + MSM_RPM_STATUS_ID_SMI_CLK, + MSM_RPM_STATUS_ID_APPS_L2_CACHE_CTL, + MSM_RPM_STATUS_ID_SMPS0B_0, + MSM_RPM_STATUS_ID_SMPS0B_1, + MSM_RPM_STATUS_ID_SMPS1B_0, + MSM_RPM_STATUS_ID_SMPS1B_1, + MSM_RPM_STATUS_ID_SMPS2B_0, + MSM_RPM_STATUS_ID_SMPS2B_1, + MSM_RPM_STATUS_ID_SMPS3B_0, + MSM_RPM_STATUS_ID_SMPS3B_1, + MSM_RPM_STATUS_ID_SMPS4B_0, + MSM_RPM_STATUS_ID_SMPS4B_1, + MSM_RPM_STATUS_ID_LDO0B_0, + MSM_RPM_STATUS_ID_LDO0B_1, + MSM_RPM_STATUS_ID_LDO1B_0, + MSM_RPM_STATUS_ID_LDO1B_1, + MSM_RPM_STATUS_ID_LDO2B_0, + MSM_RPM_STATUS_ID_LDO2B_1, + MSM_RPM_STATUS_ID_LDO3B_0, + MSM_RPM_STATUS_ID_LDO3B_1, + MSM_RPM_STATUS_ID_LDO4B_0, + MSM_RPM_STATUS_ID_LDO4B_1, + MSM_RPM_STATUS_ID_LDO5B_0, + MSM_RPM_STATUS_ID_LDO5B_1, + MSM_RPM_STATUS_ID_LDO6B_0, + MSM_RPM_STATUS_ID_LDO6B_1, + MSM_RPM_STATUS_ID_LVS0B, + MSM_RPM_STATUS_ID_LVS1B, + MSM_RPM_STATUS_ID_LVS2B, + MSM_RPM_STATUS_ID_LVS3B, + MSM_RPM_STATUS_ID_MVS, + MSM_RPM_STATUS_ID_SMPS0_0, + MSM_RPM_STATUS_ID_SMPS0_1, + MSM_RPM_STATUS_ID_SMPS1_0, + MSM_RPM_STATUS_ID_SMPS1_1, + MSM_RPM_STATUS_ID_SMPS2_0, + MSM_RPM_STATUS_ID_SMPS2_1, + MSM_RPM_STATUS_ID_SMPS3_0, + MSM_RPM_STATUS_ID_SMPS3_1, + MSM_RPM_STATUS_ID_SMPS4_0, + MSM_RPM_STATUS_ID_SMPS4_1, + MSM_RPM_STATUS_ID_LDO0_0, + MSM_RPM_STATUS_ID_LDO0_1, + MSM_RPM_STATUS_ID_LDO1_0, + MSM_RPM_STATUS_ID_LDO1_1, + MSM_RPM_STATUS_ID_LDO2_0, + MSM_RPM_STATUS_ID_LDO2_1, + MSM_RPM_STATUS_ID_LDO3_0, + MSM_RPM_STATUS_ID_LDO3_1, + MSM_RPM_STATUS_ID_LDO4_0, + MSM_RPM_STATUS_ID_LDO4_1, + MSM_RPM_STATUS_ID_LDO5_0, + MSM_RPM_STATUS_ID_LDO5_1, + MSM_RPM_STATUS_ID_LDO6_0, + MSM_RPM_STATUS_ID_LDO6_1, + MSM_RPM_STATUS_ID_LDO7_0, + MSM_RPM_STATUS_ID_LDO7_1, + MSM_RPM_STATUS_ID_LDO8_0, + MSM_RPM_STATUS_ID_LDO8_1, + MSM_RPM_STATUS_ID_LDO9_0, + MSM_RPM_STATUS_ID_LDO9_1, + MSM_RPM_STATUS_ID_LDO10_0, + MSM_RPM_STATUS_ID_LDO10_1, + MSM_RPM_STATUS_ID_LDO11_0, + MSM_RPM_STATUS_ID_LDO11_1, + MSM_RPM_STATUS_ID_LDO12_0, + MSM_RPM_STATUS_ID_LDO12_1, + MSM_RPM_STATUS_ID_LDO13_0, + MSM_RPM_STATUS_ID_LDO13_1, + MSM_RPM_STATUS_ID_LDO14_0, + MSM_RPM_STATUS_ID_LDO14_1, + MSM_RPM_STATUS_ID_LDO15_0, + MSM_RPM_STATUS_ID_LDO15_1, + MSM_RPM_STATUS_ID_LDO16_0, + MSM_RPM_STATUS_ID_LDO16_1, + MSM_RPM_STATUS_ID_LDO17_0, + MSM_RPM_STATUS_ID_LDO17_1, + MSM_RPM_STATUS_ID_LDO18_0, + MSM_RPM_STATUS_ID_LDO18_1, + MSM_RPM_STATUS_ID_LDO19_0, + MSM_RPM_STATUS_ID_LDO19_1, + MSM_RPM_STATUS_ID_LDO20_0, + MSM_RPM_STATUS_ID_LDO20_1, + MSM_RPM_STATUS_ID_LDO21_0, + MSM_RPM_STATUS_ID_LDO21_1, + MSM_RPM_STATUS_ID_LDO22_0, + MSM_RPM_STATUS_ID_LDO22_1, + MSM_RPM_STATUS_ID_LDO23_0, + MSM_RPM_STATUS_ID_LDO23_1, + MSM_RPM_STATUS_ID_LDO24_0, + MSM_RPM_STATUS_ID_LDO24_1, + MSM_RPM_STATUS_ID_LDO25_0, + MSM_RPM_STATUS_ID_LDO25_1, + MSM_RPM_STATUS_ID_LVS0, + MSM_RPM_STATUS_ID_LVS1, + + /* 9615 Specific */ + MSM_RPM_STATUS_ID_PM8018_S1_0, + MSM_RPM_STATUS_ID_PM8018_S1_1, + MSM_RPM_STATUS_ID_PM8018_S2_0, + MSM_RPM_STATUS_ID_PM8018_S2_1, + MSM_RPM_STATUS_ID_PM8018_S3_0, + MSM_RPM_STATUS_ID_PM8018_S3_1, + MSM_RPM_STATUS_ID_PM8018_S4_0, + MSM_RPM_STATUS_ID_PM8018_S4_1, + MSM_RPM_STATUS_ID_PM8018_S5_0, + MSM_RPM_STATUS_ID_PM8018_S5_1, + MSM_RPM_STATUS_ID_PM8018_L1_0, + MSM_RPM_STATUS_ID_PM8018_L1_1, + MSM_RPM_STATUS_ID_PM8018_L2_0, + MSM_RPM_STATUS_ID_PM8018_L2_1, + MSM_RPM_STATUS_ID_PM8018_L3_0, + MSM_RPM_STATUS_ID_PM8018_L3_1, + MSM_RPM_STATUS_ID_PM8018_L4_0, + MSM_RPM_STATUS_ID_PM8018_L4_1, + MSM_RPM_STATUS_ID_PM8018_L5_0, + MSM_RPM_STATUS_ID_PM8018_L5_1, + MSM_RPM_STATUS_ID_PM8018_L6_0, + MSM_RPM_STATUS_ID_PM8018_L6_1, + MSM_RPM_STATUS_ID_PM8018_L7_0, + MSM_RPM_STATUS_ID_PM8018_L7_1, + MSM_RPM_STATUS_ID_PM8018_L8_0, + MSM_RPM_STATUS_ID_PM8018_L8_1, + MSM_RPM_STATUS_ID_PM8018_L9_0, + MSM_RPM_STATUS_ID_PM8018_L9_1, + MSM_RPM_STATUS_ID_PM8018_L10_0, + MSM_RPM_STATUS_ID_PM8018_L10_1, + MSM_RPM_STATUS_ID_PM8018_L11_0, + MSM_RPM_STATUS_ID_PM8018_L11_1, + MSM_RPM_STATUS_ID_PM8018_L12_0, + MSM_RPM_STATUS_ID_PM8018_L12_1, + MSM_RPM_STATUS_ID_PM8018_L13_0, + MSM_RPM_STATUS_ID_PM8018_L13_1, + MSM_RPM_STATUS_ID_PM8018_L14_0, + MSM_RPM_STATUS_ID_PM8018_L14_1, + MSM_RPM_STATUS_ID_PM8018_LVS1, + + /* 8930 specific */ + MSM_RPM_STATUS_ID_PM8038_S1_0, + MSM_RPM_STATUS_ID_PM8038_S1_1, + MSM_RPM_STATUS_ID_PM8038_S2_0, + MSM_RPM_STATUS_ID_PM8038_S2_1, + MSM_RPM_STATUS_ID_PM8038_S3_0, + MSM_RPM_STATUS_ID_PM8038_S3_1, + MSM_RPM_STATUS_ID_PM8038_S4_0, + MSM_RPM_STATUS_ID_PM8038_S4_1, + MSM_RPM_STATUS_ID_PM8038_S5_0, + MSM_RPM_STATUS_ID_PM8038_S5_1, + MSM_RPM_STATUS_ID_PM8038_S6_0, + MSM_RPM_STATUS_ID_PM8038_S6_1, + MSM_RPM_STATUS_ID_PM8038_L1_0, + MSM_RPM_STATUS_ID_PM8038_L1_1, + MSM_RPM_STATUS_ID_PM8038_L2_0, + MSM_RPM_STATUS_ID_PM8038_L2_1, + MSM_RPM_STATUS_ID_PM8038_L3_0, + MSM_RPM_STATUS_ID_PM8038_L3_1, + MSM_RPM_STATUS_ID_PM8038_L4_0, + MSM_RPM_STATUS_ID_PM8038_L4_1, + MSM_RPM_STATUS_ID_PM8038_L5_0, + MSM_RPM_STATUS_ID_PM8038_L5_1, + MSM_RPM_STATUS_ID_PM8038_L6_0, + MSM_RPM_STATUS_ID_PM8038_L6_1, + MSM_RPM_STATUS_ID_PM8038_L7_0, + MSM_RPM_STATUS_ID_PM8038_L7_1, + MSM_RPM_STATUS_ID_PM8038_L8_0, + MSM_RPM_STATUS_ID_PM8038_L8_1, + MSM_RPM_STATUS_ID_PM8038_L9_0, + MSM_RPM_STATUS_ID_PM8038_L9_1, + MSM_RPM_STATUS_ID_PM8038_L10_0, + MSM_RPM_STATUS_ID_PM8038_L10_1, + MSM_RPM_STATUS_ID_PM8038_L11_0, + MSM_RPM_STATUS_ID_PM8038_L11_1, + MSM_RPM_STATUS_ID_PM8038_L12_0, + MSM_RPM_STATUS_ID_PM8038_L12_1, + MSM_RPM_STATUS_ID_PM8038_L13_0, + MSM_RPM_STATUS_ID_PM8038_L13_1, + MSM_RPM_STATUS_ID_PM8038_L14_0, + MSM_RPM_STATUS_ID_PM8038_L14_1, + MSM_RPM_STATUS_ID_PM8038_L15_0, + MSM_RPM_STATUS_ID_PM8038_L15_1, + MSM_RPM_STATUS_ID_PM8038_L16_0, + MSM_RPM_STATUS_ID_PM8038_L16_1, + MSM_RPM_STATUS_ID_PM8038_L17_0, + MSM_RPM_STATUS_ID_PM8038_L17_1, + MSM_RPM_STATUS_ID_PM8038_L18_0, + MSM_RPM_STATUS_ID_PM8038_L18_1, + MSM_RPM_STATUS_ID_PM8038_L19_0, + MSM_RPM_STATUS_ID_PM8038_L19_1, + MSM_RPM_STATUS_ID_PM8038_L20_0, + MSM_RPM_STATUS_ID_PM8038_L20_1, + MSM_RPM_STATUS_ID_PM8038_L21_0, + MSM_RPM_STATUS_ID_PM8038_L21_1, + MSM_RPM_STATUS_ID_PM8038_L22_0, + MSM_RPM_STATUS_ID_PM8038_L22_1, + MSM_RPM_STATUS_ID_PM8038_L23_0, + MSM_RPM_STATUS_ID_PM8038_L23_1, + MSM_RPM_STATUS_ID_PM8038_L24_0, + MSM_RPM_STATUS_ID_PM8038_L24_1, + MSM_RPM_STATUS_ID_PM8038_L25_0, + MSM_RPM_STATUS_ID_PM8038_L25_1, + MSM_RPM_STATUS_ID_PM8038_L26_0, + MSM_RPM_STATUS_ID_PM8038_L26_1, + MSM_RPM_STATUS_ID_PM8038_L27_0, + MSM_RPM_STATUS_ID_PM8038_L27_1, + MSM_RPM_STATUS_ID_PM8038_CLK1_0, + MSM_RPM_STATUS_ID_PM8038_CLK1_1, + MSM_RPM_STATUS_ID_PM8038_CLK2_0, + MSM_RPM_STATUS_ID_PM8038_CLK2_1, + MSM_RPM_STATUS_ID_PM8038_LVS1, + MSM_RPM_STATUS_ID_PM8038_LVS2, + + /* PMIC 8917 */ + MSM_RPM_STATUS_ID_PM8917_S1_0, + MSM_RPM_STATUS_ID_PM8917_S1_1, + MSM_RPM_STATUS_ID_PM8917_S2_0, + MSM_RPM_STATUS_ID_PM8917_S2_1, + MSM_RPM_STATUS_ID_PM8917_S3_0, + MSM_RPM_STATUS_ID_PM8917_S3_1, + MSM_RPM_STATUS_ID_PM8917_S4_0, + MSM_RPM_STATUS_ID_PM8917_S4_1, + MSM_RPM_STATUS_ID_PM8917_S5_0, + MSM_RPM_STATUS_ID_PM8917_S5_1, + MSM_RPM_STATUS_ID_PM8917_S6_0, + MSM_RPM_STATUS_ID_PM8917_S6_1, + MSM_RPM_STATUS_ID_PM8917_S7_0, + MSM_RPM_STATUS_ID_PM8917_S7_1, + MSM_RPM_STATUS_ID_PM8917_S8_0, + MSM_RPM_STATUS_ID_PM8917_S8_1, + MSM_RPM_STATUS_ID_PM8917_L1_0, + MSM_RPM_STATUS_ID_PM8917_L1_1, + MSM_RPM_STATUS_ID_PM8917_L2_0, + MSM_RPM_STATUS_ID_PM8917_L2_1, + MSM_RPM_STATUS_ID_PM8917_L3_0, + MSM_RPM_STATUS_ID_PM8917_L3_1, + MSM_RPM_STATUS_ID_PM8917_L4_0, + MSM_RPM_STATUS_ID_PM8917_L4_1, + MSM_RPM_STATUS_ID_PM8917_L5_0, + MSM_RPM_STATUS_ID_PM8917_L5_1, + MSM_RPM_STATUS_ID_PM8917_L6_0, + MSM_RPM_STATUS_ID_PM8917_L6_1, + MSM_RPM_STATUS_ID_PM8917_L7_0, + MSM_RPM_STATUS_ID_PM8917_L7_1, + MSM_RPM_STATUS_ID_PM8917_L8_0, + MSM_RPM_STATUS_ID_PM8917_L8_1, + MSM_RPM_STATUS_ID_PM8917_L9_0, + MSM_RPM_STATUS_ID_PM8917_L9_1, + MSM_RPM_STATUS_ID_PM8917_L10_0, + MSM_RPM_STATUS_ID_PM8917_L10_1, + MSM_RPM_STATUS_ID_PM8917_L11_0, + MSM_RPM_STATUS_ID_PM8917_L11_1, + MSM_RPM_STATUS_ID_PM8917_L12_0, + MSM_RPM_STATUS_ID_PM8917_L12_1, + MSM_RPM_STATUS_ID_PM8917_L14_0, + MSM_RPM_STATUS_ID_PM8917_L14_1, + MSM_RPM_STATUS_ID_PM8917_L15_0, + MSM_RPM_STATUS_ID_PM8917_L15_1, + MSM_RPM_STATUS_ID_PM8917_L16_0, + MSM_RPM_STATUS_ID_PM8917_L16_1, + MSM_RPM_STATUS_ID_PM8917_L17_0, + MSM_RPM_STATUS_ID_PM8917_L17_1, + MSM_RPM_STATUS_ID_PM8917_L18_0, + MSM_RPM_STATUS_ID_PM8917_L18_1, + MSM_RPM_STATUS_ID_PM8917_L21_0, + MSM_RPM_STATUS_ID_PM8917_L21_1, + MSM_RPM_STATUS_ID_PM8917_L22_0, + MSM_RPM_STATUS_ID_PM8917_L22_1, + MSM_RPM_STATUS_ID_PM8917_L23_0, + MSM_RPM_STATUS_ID_PM8917_L23_1, + MSM_RPM_STATUS_ID_PM8917_L24_0, + MSM_RPM_STATUS_ID_PM8917_L24_1, + MSM_RPM_STATUS_ID_PM8917_L25_0, + MSM_RPM_STATUS_ID_PM8917_L25_1, + MSM_RPM_STATUS_ID_PM8917_L26_0, + MSM_RPM_STATUS_ID_PM8917_L26_1, + MSM_RPM_STATUS_ID_PM8917_L27_0, + MSM_RPM_STATUS_ID_PM8917_L27_1, + MSM_RPM_STATUS_ID_PM8917_L28_0, + MSM_RPM_STATUS_ID_PM8917_L28_1, + MSM_RPM_STATUS_ID_PM8917_L29_0, + MSM_RPM_STATUS_ID_PM8917_L29_1, + MSM_RPM_STATUS_ID_PM8917_L30_0, + MSM_RPM_STATUS_ID_PM8917_L30_1, + MSM_RPM_STATUS_ID_PM8917_L31_0, + MSM_RPM_STATUS_ID_PM8917_L31_1, + MSM_RPM_STATUS_ID_PM8917_L32_0, + MSM_RPM_STATUS_ID_PM8917_L32_1, + MSM_RPM_STATUS_ID_PM8917_L33_0, + MSM_RPM_STATUS_ID_PM8917_L33_1, + MSM_RPM_STATUS_ID_PM8917_L34_0, + MSM_RPM_STATUS_ID_PM8917_L34_1, + MSM_RPM_STATUS_ID_PM8917_L35_0, + MSM_RPM_STATUS_ID_PM8917_L35_1, + MSM_RPM_STATUS_ID_PM8917_L36_0, + MSM_RPM_STATUS_ID_PM8917_L36_1, + MSM_RPM_STATUS_ID_PM8917_CLK1_0, + MSM_RPM_STATUS_ID_PM8917_CLK1_1, + MSM_RPM_STATUS_ID_PM8917_CLK2_0, + MSM_RPM_STATUS_ID_PM8917_CLK2_1, + MSM_RPM_STATUS_ID_PM8917_LVS1, + MSM_RPM_STATUS_ID_PM8917_LVS3, + MSM_RPM_STATUS_ID_PM8917_LVS4, + MSM_RPM_STATUS_ID_PM8917_LVS5, + MSM_RPM_STATUS_ID_PM8917_LVS6, + MSM_RPM_STATUS_ID_PM8917_LVS7, + MSM_RPM_STATUS_ID_VOLTAGE_CORNER, + MSM_RPM_STATUS_ID_PM8917_VOLTAGE_CORNER + = MSM_RPM_STATUS_ID_VOLTAGE_CORNER, + MSM_RPM_STATUS_ID_PM8038_VOLTAGE_CORNER + = MSM_RPM_STATUS_ID_VOLTAGE_CORNER, + + /* 8064 specific */ + MSM_RPM_STATUS_ID_PM8821_S1_0, + MSM_RPM_STATUS_ID_PM8821_S1_1, + MSM_RPM_STATUS_ID_PM8821_S2_0, + MSM_RPM_STATUS_ID_PM8821_S2_1, + MSM_RPM_STATUS_ID_PM8821_L1_0, + MSM_RPM_STATUS_ID_PM8821_L1_1, + MSM_RPM_STATUS_ID_VDDMIN_GPIO, + + MSM_RPM_STATUS_ID_LAST, +}; + +static inline uint32_t msm_rpm_get_ctx_mask(unsigned int ctx) +{ + return 1UL << ctx; +} + +static inline unsigned int msm_rpm_get_sel_mask_reg(unsigned int sel) +{ + return sel / 32; +} + +static inline uint32_t msm_rpm_get_sel_mask(unsigned int sel) +{ + return 1UL << (sel % 32); +} + +struct msm_rpm_iv_pair { + uint32_t id; + uint32_t value; +}; + +struct msm_rpm_notification { + struct list_head list; /* reserved for RPM use */ + struct semaphore sem; + uint32_t sel_masks[SEL_MASK_SIZE]; /* reserved for RPM use */ +}; + +struct msm_rpm_map_data { + uint32_t id; + uint32_t sel; + uint32_t count; +}; + +#define MSM_RPM_MAP(t, i, s, c) \ + [MSM_RPM_ID_##i] = \ + {\ + .id = MSM_RPM_##t##_ID_##i, \ + .sel = MSM_RPM_##t##_SEL_##s, \ + .count = c, \ + } + +#define MSM_RPM_MAP_PMIC(_target, _pmic, _id, _select, _count) \ + [MSM_RPM_ID_##_id] = \ + {\ + .id = MSM_RPM_##_target##_ID_PM##_pmic##_##_id, \ + .sel = MSM_RPM_##_target##_SEL_##_select, \ + .count = _count, \ + } + +#define MSM_RPM_STATUS_ID_VALID BIT(31) + +#define MSM_RPM_STATUS_ID_MAP(t, i) \ + [MSM_RPM_STATUS_ID_## i] = (MSM_RPM_##t##_STATUS_ID_##i \ + | MSM_RPM_STATUS_ID_VALID) + +#define MSM_RPM_CTRL_MAP(t, i) \ + [MSM_RPM_CTRL_##i] = MSM_RPM_##t##_CTRL_##i + + +struct msm_rpm_platform_data { + void __iomem *reg_base_addrs[MSM_RPM_PAGE_COUNT]; + unsigned int irq_ack; + unsigned int irq_err; + unsigned int irq_wakeup; + void *ipc_rpm_reg; + unsigned int ipc_rpm_val; + struct msm_rpm_map_data target_id[MSM_RPM_ID_LAST]; + unsigned int target_status[MSM_RPM_STATUS_ID_LAST]; + unsigned int target_ctrl_id[MSM_RPM_CTRL_LAST]; + unsigned int sel_invalidate, sel_notification, sel_last; + unsigned int ver[3]; +}; + +extern struct msm_rpm_platform_data msm8660_rpm_data; +extern struct msm_rpm_platform_data msm8960_rpm_data; +extern struct msm_rpm_platform_data msm9615_rpm_data; +extern struct msm_rpm_platform_data msm8930_rpm_data; +extern struct msm_rpm_platform_data msm8930_rpm_data_pm8917; +extern struct msm_rpm_platform_data apq8064_rpm_data; + + +static inline int msm_rpm_local_request_is_outstanding(void) +{ + return -ENODEV; +} + +static inline int msm_rpm_get_status(struct msm_rpm_iv_pair *status, int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_set(int ctx, struct msm_rpm_iv_pair *req, int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_set_noirq(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_set_nosleep( + int ctx, struct msm_rpm_iv_pair *req, int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_clear(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_clear_nosleep( + int ctx, struct msm_rpm_iv_pair *req, int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_register_notification(struct msm_rpm_notification *n, + struct msm_rpm_iv_pair *req, int count) +{ + return -ENODEV; +} + +static inline int msm_rpm_unregister_notification( + struct msm_rpm_notification *n) +{ + return -ENODEV; +} + +static inline int msm_rpm_init(struct msm_rpm_platform_data *data) +{ + return -ENODEV; +} + + +#endif /* __ARCH_ARM_MACH_MSM_RPM_H */ diff --git a/arch/arm/mach-msm/include/mach/scm-io.h b/arch/arm/mach-msm/include/mach/scm-io.h new file mode 100644 index 000000000000..46e3964c16af --- /dev/null +++ b/arch/arm/mach-msm/include/mach/scm-io.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2011-2013, 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. + */ +#ifndef __MACH_SCM_IO_H +#define __MACH_SCM_IO_H + +#include <linux/types.h> + + +#define secure_readl(c) readl(c) +#define secure_writel(v, c) writel(v, c) + + +#endif diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h index ef55868a5b8a..7b19d159c8bd 100644 --- a/arch/arm/mach-msm/include/mach/sirc.h +++ b/arch/arm/mach-msm/include/mach/sirc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2011, 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 @@ -25,13 +25,12 @@ struct sirc_regs_t { struct sirc_cascade_regs { void *int_status; unsigned int cascade_irq; + unsigned int cascade_fiq; }; void msm_init_sirc(void); -void msm_sirc_enter_sleep(void); -void msm_sirc_exit_sleep(void); -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP) #include <mach/msm_iomap.h> @@ -41,6 +40,10 @@ void msm_sirc_exit_sleep(void); #define FIRST_SIRC_IRQ (NR_MSM_IRQS + NR_GPIO_IRQS) +#if defined(CONFIG_ARCH_FSM9XXX) +#include <mach/sirc-fsm9xxx.h> +#else /* CONFIG_ARCH_FSM9XXX */ + #define INT_UART1 (FIRST_SIRC_IRQ + 0) #define INT_UART2 (FIRST_SIRC_IRQ + 1) #define INT_UART3 (FIRST_SIRC_IRQ + 2) @@ -78,8 +81,6 @@ void msm_sirc_exit_sleep(void); #define SIRC_MASK 0x007FFFFF #endif -#define LAST_SIRC_IRQ (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1) - #define SPSS_SIRC_INT_SELECT (MSM_SIRC_BASE + 0x00) #define SPSS_SIRC_INT_ENABLE (MSM_SIRC_BASE + 0x04) #define SPSS_SIRC_INT_ENABLE_CLEAR (MSM_SIRC_BASE + 0x08) @@ -93,6 +94,10 @@ void msm_sirc_exit_sleep(void); #define SPSS_SIRC_INT_CLEAR (MSM_SIRC_BASE + 0x28) #define SPSS_SIRC_SOFT_INT (MSM_SIRC_BASE + 0x2C) -#endif +#endif /* CONFIG_ARCH_FSM9XXX */ + +#define LAST_SIRC_IRQ (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1) + +#endif /* CONFIG_ARCH_MSM_SCORPION */ #endif diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h new file mode 100644 index 000000000000..1049799ea019 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h @@ -0,0 +1,17 @@ +/* Copyright (c) 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. + * + */ +/* + * This header is deprecated and will be deleted soon. Please include + * the header below instead. + */ +#include <soc/qcom/subsystem_restart.h> diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h new file mode 100644 index 000000000000..14eb271e553f --- /dev/null +++ b/arch/arm/mach-msm/include/mach/uncompress.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_UNCOMPRESS_H +#define __ASM_ARCH_MSM_UNCOMPRESS_H + +#include <asm/barrier.h> +#include <asm/processor.h> +#include <mach/msm_iomap.h> +#include <mach/msm_serial_hsl_regs.h> + +#define UART_CSR (*(volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x08)) +#define UART_TF (*(volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x0c)) + +#define UART_DM_SR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + UARTDM_SR_OFFSET))) +#define UART_DM_CR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + UARTDM_CR_OFFSET))) +#define UART_DM_ISR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + UARTDM_ISR_OFFSET))) +#define UART_DM_NCHAR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + UARTDM_NCF_TX_OFFSET))) +#define UART_DM_TF (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + UARTDM_TF_OFFSET))) + +static void putc(int c) +{ +#if defined(MSM_DEBUG_UART_PHYS) +#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS + /* + * Wait for TX_READY to be set; but skip it if we have a + * TX underrun. + */ + if (!(UART_DM_SR & 0x08)) + while (!(UART_DM_ISR & 0x80)) + cpu_relax(); + + UART_DM_CR = 0x300; + UART_DM_NCHAR = 0x1; + UART_DM_TF = c; +#else + while (!(UART_CSR & 0x04)) + cpu_relax(); + UART_TF = c; +#endif +#endif +} + +static inline void flush(void) +{ +} + +static inline void arch_decomp_setup(void) +{ +} + +#endif diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index b042dca1f633..db22ed7c5511 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -86,6 +86,22 @@ void __init msm_map_common_io(void) } #endif +#ifdef CONFIG_ARCH_MSM8916 +static struct map_desc msm8916_io_desc[] __initdata = { + MSM_CHIP_DEVICE(APCS_GCC, MSM8916), +#ifdef CONFIG_DEBUG_MSM8916_UART + MSM_DEVICE(DEBUG_UART), +#endif +}; + +void __init msm_map_msm8916_io(void) +{ + iotable_init(msm8916_io_desc, ARRAY_SIZE(msm8916_io_desc)); +} +#endif /* CONFIG_ARCH_MSM8916 */ + + + #ifdef CONFIG_ARCH_QSD8X50 static struct map_desc qsd8x50_io_desc[] __initdata = { MSM_DEVICE(VIC), diff --git a/arch/arm/mach-msm/keypad-surf-ffa.c b/arch/arm/mach-msm/keypad-surf-ffa.c new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/arch/arm/mach-msm/keypad-surf-ffa.c diff --git a/arch/arm/mach-msm/krait-scm.c b/arch/arm/mach-msm/krait-scm.c new file mode 100644 index 000000000000..d1316632cc24 --- /dev/null +++ b/arch/arm/mach-msm/krait-scm.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2012, 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 <linux/kernel.h> +#include <linux/workqueue.h> +#include <linux/percpu.h> +#include <linux/cpu.h> +#include <linux/smp.h> +#include <linux/sysfs.h> +#include <soc/qcom/scm.h> + + +#define CPU_CONFIG_CMD 5 +#define CPU_CONFIG_QUERY_CMD 6 + +static int query_cpu_config(void) +{ + struct cpu_config_query_req_resp { + u32 id; + u32 arg0; + u32 arg1; + u32 arg2; + } request; + struct cpu_config_query_resp { + u32 ret0; + u32 ret1; + u32 ret2; + u32 ret3; + } response = {0}; + int ret; + + request.id = 1; + ret = scm_call(SCM_SVC_BOOT, CPU_CONFIG_QUERY_CMD, &request, + sizeof(request), &response, sizeof(response)); + return ret ? : response.ret0; +} + +static void set_cpu_config(int enable) +{ + struct cpu_config_req { + u32 id; + u32 arg0; + u32 arg1; + u32 arg2; + } request; + + request.id = 1; + request.arg0 = enable; + scm_call(SCM_SVC_BOOT, CPU_CONFIG_CMD, &request, sizeof(request), + NULL, 0); +} + +void enable_cpu_config(struct work_struct *work) +{ + set_cpu_config(1); +} + +void disable_cpu_config(struct work_struct *work) +{ + set_cpu_config(0); +} + +int cpu_config_on_each_cpu(bool enable) +{ + work_func_t func = enable ? enable_cpu_config : disable_cpu_config; + return schedule_on_each_cpu(func); +} + +static ssize_t show_cpuctl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", query_cpu_config()); +} + +static ssize_t store_cpuctl(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned val; + int ret; + + ret = kstrtouint(buf, 10, &val); + if (ret < 0) + return ret; + ret = cpu_config_on_each_cpu(val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(cpuctl, 0600, show_cpuctl, store_cpuctl); + +static int __init init_scm_cpu(void) +{ + return device_create_file(cpu_subsys.dev_root, &dev_attr_cpuctl); +} +module_init(init_scm_cpu); diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c new file mode 100644 index 000000000000..b2693ff51066 --- /dev/null +++ b/arch/arm/mach-msm/memory.c @@ -0,0 +1,223 @@ +/* arch/arm/mach-msm/memory.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/mm.h> +#include <linux/mm_types.h> +#include <linux/bootmem.h> +#include <linux/module.h> +#include <linux/memblock.h> +#include <asm/memblock.h> +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include <asm/cacheflush.h> +#include <asm/setup.h> +#include <mach/msm_memtypes.h> +#include <mach/memory.h> +#include <linux/hardirq.h> +#include <mach/msm_iomap.h> +#include <soc/qcom/socinfo.h> +#include <linux/sched.h> +#include <linux/of_fdt.h> + +char *memtype_name[] = { + "EBI0", + "EBI1" +}; + +static int __init check_for_compat(unsigned long node) +{ + char **start = __compat_exports_start; + + for ( ; start < __compat_exports_end; start++) + if (of_flat_dt_is_compatible(node, *start)) + return 1; + + return 0; +} + +int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned int *memory_remove_prop; + unsigned long memory_remove_prop_length; + unsigned int *memory_reserve_prop; + unsigned long memory_reserve_prop_length; + unsigned int memory_size; + unsigned int memory_start; + unsigned int num_holes = 0; + int i; + int ret; + + memory_remove_prop = of_get_flat_dt_prop(node, + "qcom,memblock-remove", + &memory_remove_prop_length); + + memory_reserve_prop = of_get_flat_dt_prop(node, + "qcom,memblock-reserve", + &memory_reserve_prop_length); + + if (memory_remove_prop || memory_reserve_prop) { + if (!check_for_compat(node)) + goto out; + } else { + goto out; + } + + if (memory_remove_prop) { + if (!memory_remove_prop_length || (memory_remove_prop_length % + (2 * sizeof(unsigned int)) != 0)) { + WARN(1, "Memory remove malformed\n"); + goto mem_reserve; + } + + num_holes = memory_remove_prop_length / + (2 * sizeof(unsigned int)); + + for (i = 0; i < (num_holes * 2); i += 2) { + memory_start = be32_to_cpu(memory_remove_prop[i]); + memory_size = be32_to_cpu(memory_remove_prop[i+1]); + + ret = memblock_remove(memory_start, memory_size); + if (ret) + WARN(1, "Failed to remove memory %x-%x\n", + memory_start, memory_start+memory_size); + else + pr_info("Node %s removed memory %x-%x\n", uname, + memory_start, memory_start+memory_size); + } + } + +mem_reserve: + + if (memory_reserve_prop) { + if (memory_reserve_prop_length != (2*sizeof(unsigned int))) { + WARN(1, "Memory reserve malformed\n"); + goto out; + } + + memory_start = be32_to_cpu(memory_reserve_prop[0]); + memory_size = be32_to_cpu(memory_reserve_prop[1]); + + ret = memblock_reserve(memory_start, memory_size); + if (ret) + WARN(1, "Failed to reserve memory %x-%x\n", + memory_start, memory_start+memory_size); + else + pr_info("Node %s memblock_reserve memory %x-%x\n", + uname, memory_start, memory_start+memory_size); + } + +out: + return 0; +} + +/* Function to remove any meminfo blocks which are of size zero */ +static void merge_meminfo(void) +{ + int i = 0; + + while (i < meminfo.nr_banks) { + struct membank *bank = &meminfo.bank[i]; + + if (bank->size == 0) { + memmove(bank, bank + 1, + (meminfo.nr_banks - i) * sizeof(*bank)); + meminfo.nr_banks--; + continue; + } + i++; + } +} + +/* + * Function to scan the device tree and adjust the meminfo table to + * reflect the memory holes. + */ +int __init dt_scan_for_memory_hole(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned int *memory_remove_prop; + unsigned long memory_remove_prop_length; + unsigned long hole_start; + unsigned long hole_size; + unsigned int num_holes = 0; + int i = 0; + + memory_remove_prop = of_get_flat_dt_prop(node, + "qcom,memblock-remove", + &memory_remove_prop_length); + + if (memory_remove_prop) { + if (!check_for_compat(node)) + goto out; + } else { + goto out; + } + + if (memory_remove_prop) { + if (!memory_remove_prop_length || (memory_remove_prop_length % + (2 * sizeof(unsigned int)) != 0)) { + WARN(1, "Memory remove malformed\n"); + goto out; + } + + num_holes = memory_remove_prop_length / + (2 * sizeof(unsigned int)); + + for (i = 0; i < (num_holes * 2); i += 2) { + hole_start = be32_to_cpu(memory_remove_prop[i]); + hole_size = be32_to_cpu(memory_remove_prop[i+1]); + + adjust_meminfo(hole_start, hole_size); + } + } + +out: + return 0; +} + +/* + * Split the memory bank to reflect the hole, if present, + * using the start and end of the memory hole. + */ +void adjust_meminfo(unsigned long start, unsigned long size) +{ + int i; + + for (i = 0; i < meminfo.nr_banks; i++) { + struct membank *bank = &meminfo.bank[i]; + + if (((start + size) <= (bank->start + bank->size)) && + (start >= bank->start)) { + memmove(bank + 1, bank, + (meminfo.nr_banks - i) * sizeof(*bank)); + meminfo.nr_banks++; + i++; + + bank->size = start - bank->start; + bank[1].start = (start + size); + bank[1].size -= (bank->size + size); + bank[1].highmem = 0; + merge_meminfo(); + } + } +} + +/* Provide a string that anonymous device tree allocations (those not + * directly associated with any driver) can use for their "compatible" + * field */ +EXPORT_COMPAT("qcom,msm-contig-mem"); diff --git a/arch/arm/mach-msm/msm-buspm-dev.c b/arch/arm/mach-msm/msm-buspm-dev.c new file mode 100644 index 000000000000..5862e055cdd8 --- /dev/null +++ b/arch/arm/mach-msm/msm-buspm-dev.c @@ -0,0 +1,335 @@ +/* Copyright (c) 2011-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. + */ + +/* #define DEBUG */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/dma-mapping.h> +#include <soc/qcom/rpm-smd.h> +#include "msm-buspm-dev.h" + +#define MSM_BUSPM_DRV_NAME "msm-buspm-dev" + +enum msm_buspm_spdm_res { + SPDM_RES_ID = 0, + SPDM_RES_TYPE = 0x63707362, + SPDM_KEY = 0x00006e65, + SPDM_SIZE = 4, +}; +/* + * Allocate kernel buffer. + * Currently limited to one buffer per file descriptor. If alloc() is + * called twice for the same descriptor, the original buffer is freed. + * There is also no locking protection so the same descriptor can not be shared. + */ + +static inline void *msm_buspm_dev_get_vaddr(struct file *filp) +{ + struct msm_buspm_map_dev *dev = filp->private_data; + + return (dev) ? dev->vaddr : NULL; +} + +static inline unsigned int msm_buspm_dev_get_buflen(struct file *filp) +{ + struct msm_buspm_map_dev *dev = filp->private_data; + + return dev ? dev->buflen : 0; +} + +static inline unsigned long msm_buspm_dev_get_paddr(struct file *filp) +{ + struct msm_buspm_map_dev *dev = filp->private_data; + + return (dev) ? dev->paddr : 0L; +} + +static void msm_buspm_dev_free(struct file *filp) +{ + struct msm_buspm_map_dev *dev = filp->private_data; + + if (dev && dev->vaddr) { + pr_debug("freeing memory at 0x%p\n", dev->vaddr); + dma_free_coherent(NULL, dev->buflen, dev->vaddr, dev->paddr); + dev->paddr = 0L; + dev->vaddr = NULL; + } +} + +static int msm_buspm_dev_open(struct inode *inode, struct file *filp) +{ + struct msm_buspm_map_dev *dev; + + if (capable(CAP_SYS_ADMIN)) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev) + filp->private_data = dev; + else + return -ENOMEM; + } else { + return -EPERM; + } + + return 0; +} + +static int +msm_buspm_dev_alloc(struct file *filp, struct buspm_alloc_params data) +{ + dma_addr_t paddr; + void *vaddr; + struct msm_buspm_map_dev *dev = filp->private_data; + + /* If buffer already allocated, then free it */ + if (dev->vaddr) + msm_buspm_dev_free(filp); + + /* Allocate uncached memory */ + vaddr = dma_alloc_coherent(NULL, data.size, &paddr, GFP_KERNEL); + + if (vaddr == NULL) { + pr_err("allocation of 0x%x bytes failed", data.size); + return -ENOMEM; + } + + dev->vaddr = vaddr; + dev->paddr = paddr; + dev->buflen = data.size; + filp->f_pos = 0; + pr_debug("virt addr = 0x%p\n", dev->vaddr); + pr_debug("phys addr = 0x%lx\n", dev->paddr); + + return 0; +} + +static int msm_bus_rpm_req(u32 rsc_type, u32 key, u32 hwid, + int ctx, u32 val) +{ + struct msm_rpm_request *rpm_req; + int ret, msg_id; + + rpm_req = msm_rpm_create_request(ctx, rsc_type, SPDM_RES_ID, 1); + if (rpm_req == NULL) { + pr_err("RPM: Couldn't create RPM Request\n"); + return -ENXIO; + } + + ret = msm_rpm_add_kvp_data(rpm_req, key, (const uint8_t *)&val, + (int)(sizeof(uint32_t))); + if (ret) { + pr_err("RPM: Add KVP failed for RPM Req:%u\n", + rsc_type); + goto err; + } + + pr_debug("Added Key: %d, Val: %u, size: %d\n", key, + (uint32_t)val, sizeof(uint32_t)); + msg_id = msm_rpm_send_request(rpm_req); + if (!msg_id) { + pr_err("RPM: No message ID for req\n"); + ret = -ENXIO; + goto err; + } + + ret = msm_rpm_wait_for_ack(msg_id); + if (ret) { + pr_err("RPM: Ack failed\n"); + goto err; + } + +err: + msm_rpm_free_request(rpm_req); + return ret; +} + +static int msm_buspm_ioc_cmds(uint32_t arg) +{ + switch (arg) { + case MSM_BUSPM_SPDM_CLK_DIS: + case MSM_BUSPM_SPDM_CLK_EN: + return msm_bus_rpm_req(SPDM_RES_TYPE, SPDM_KEY, 0, + MSM_RPM_CTX_ACTIVE_SET, arg); + default: + pr_warn("Unsupported ioctl command: %d\n", arg); + return -EINVAL; + } +} + + + +static long +msm_buspm_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct buspm_xfer_req xfer; + struct buspm_alloc_params alloc_data; + unsigned long paddr; + int retval = 0; + void *buf = msm_buspm_dev_get_vaddr(filp); + unsigned int buflen = msm_buspm_dev_get_buflen(filp); + unsigned char *dbgbuf = buf; + + if (_IOC_TYPE(cmd) != MSM_BUSPM_IOC_MAGIC) { + pr_err("Wrong IOC_MAGIC.Exiting\n"); + return -ENOTTY; + } + + switch (cmd) { + case MSM_BUSPM_IOC_FREE: + pr_debug("cmd = 0x%x (FREE)\n", cmd); + msm_buspm_dev_free(filp); + break; + + case MSM_BUSPM_IOC_ALLOC: + pr_debug("cmd = 0x%x (ALLOC)\n", cmd); + retval = __get_user(alloc_data.size, (size_t __user *)arg); + + if (retval == 0) + retval = msm_buspm_dev_alloc(filp, alloc_data); + break; + + case MSM_BUSPM_IOC_RD_PHYS_ADDR: + pr_debug("Read Physical Address\n"); + paddr = msm_buspm_dev_get_paddr(filp); + if (paddr == 0L) { + retval = -EINVAL; + } else { + pr_debug("phys addr = 0x%lx\n", paddr); + retval = __put_user(paddr, + (unsigned long __user *)arg); + } + break; + + case MSM_BUSPM_IOC_RDBUF: + pr_debug("Read Buffer: 0x%x%x%x%x\n", + dbgbuf[0], dbgbuf[1], dbgbuf[2], dbgbuf[3]); + + if (!buf) { + retval = -EINVAL; + break; + } + + if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) { + retval = -EFAULT; + break; + } + + if ((xfer.size <= buflen) && + (copy_to_user((void __user *)xfer.data, buf, + xfer.size))) { + retval = -EFAULT; + break; + } + break; + + case MSM_BUSPM_IOC_WRBUF: + pr_debug("Write Buffer\n"); + + if (!buf) { + retval = -EINVAL; + break; + } + + if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) { + retval = -EFAULT; + break; + } + + if ((buflen <= xfer.size) && + (copy_from_user(buf, (void __user *)xfer.data, + xfer.size))) { + retval = -EFAULT; + break; + } + break; + + case MSM_BUSPM_IOC_CMD: + pr_debug("IOCTL command: cmd: %d arg: %lu\n", cmd, arg); + retval = msm_buspm_ioc_cmds(arg); + break; + + default: + pr_debug("Unknown command 0x%x\n", cmd); + retval = -EINVAL; + break; + } + + return retval; +} + +static int msm_buspm_dev_release(struct inode *inode, struct file *filp) +{ + struct msm_buspm_map_dev *dev = filp->private_data; + + msm_buspm_dev_free(filp); + kfree(dev); + filp->private_data = NULL; + + return 0; +} + +static int msm_buspm_dev_mmap(struct file *filp, struct vm_area_struct *vma) +{ + pr_debug("vma = 0x%p\n", vma); + + /* Mappings are uncached */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EFAULT; + + return 0; +} + +static const struct file_operations msm_buspm_dev_fops = { + .owner = THIS_MODULE, + .mmap = msm_buspm_dev_mmap, + .open = msm_buspm_dev_open, + .unlocked_ioctl = msm_buspm_dev_ioctl, + .llseek = noop_llseek, + .release = msm_buspm_dev_release, +}; + +struct miscdevice msm_buspm_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = MSM_BUSPM_DRV_NAME, + .fops = &msm_buspm_dev_fops, +}; + +static int __init msm_buspm_dev_init(void) +{ + int ret = 0; + + ret = misc_register(&msm_buspm_misc); + if (ret < 0) + pr_err("%s: Cannot register misc device\n", __func__); + + return ret; +} + +static void __exit msm_buspm_dev_exit(void) +{ + misc_deregister(&msm_buspm_misc); +} +module_init(msm_buspm_dev_init); +module_exit(msm_buspm_dev_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:"MSM_BUSPM_DRV_NAME); diff --git a/arch/arm/mach-msm/msm-buspm-dev.h b/arch/arm/mach-msm/msm-buspm-dev.h new file mode 100644 index 000000000000..9c428fb37211 --- /dev/null +++ b/arch/arm/mach-msm/msm-buspm-dev.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2011,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. + */ + +#ifndef __MSM_BUSPM_DEV_H__ +#define __MSM_BUSPM_DEV_H__ + +#include <linux/ioctl.h> + +struct msm_buspm_map_dev { + void *vaddr; + unsigned long paddr; + size_t buflen; +}; + +/* Read/write data into kernel buffer */ +struct buspm_xfer_req { + unsigned int size; /* Size of this request, in bytes */ + void *data; /* Data buffer to transfer data to/from */ +}; + +struct buspm_alloc_params { + size_t size; +}; + +enum msm_buspm_ioc_cmds { + MSM_BUSPM_SPDM_CLK_DIS = 0, + MSM_BUSPM_SPDM_CLK_EN, +}; + +#define MSM_BUSPM_IOC_MAGIC 'p' + +#define MSM_BUSPM_IOC_FREE \ + _IOW(MSM_BUSPM_IOC_MAGIC, 0, void *) + +#define MSM_BUSPM_IOC_ALLOC \ + _IOW(MSM_BUSPM_IOC_MAGIC, 1, size_t) + +#define MSM_BUSPM_IOC_RDBUF \ + _IOW(MSM_BUSPM_IOC_MAGIC, 2, struct buspm_xfer_req) + +#define MSM_BUSPM_IOC_WRBUF \ + _IOW(MSM_BUSPM_IOC_MAGIC, 3, struct buspm_xfer_req) + +#define MSM_BUSPM_IOC_RD_PHYS_ADDR \ + _IOR(MSM_BUSPM_IOC_MAGIC, 4, unsigned long) + +#define MSM_BUSPM_IOC_CMD \ + _IOR(MSM_BUSPM_IOC_MAGIC, 5, uint32_t) +#endif diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c new file mode 100644 index 000000000000..20a6cde2d320 --- /dev/null +++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011-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 <linux/spinlock.h> +#include <linux/module.h> +#include <linux/msm_rtb.h> +#include <asm/cputype.h> + +DEFINE_RAW_SPINLOCK(l2_access_lock); + +void set_l2_indirect_reg(u32 reg_addr, u32 val) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&l2_access_lock, flags); + mb(); + uncached_logk(LOGK_L2CPWRITE, (void *)reg_addr); + asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t" + "isb\n\t" + "mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t" + "isb\n\t" + : + : [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val) + ); + raw_spin_unlock_irqrestore(&l2_access_lock, flags); +} +EXPORT_SYMBOL(set_l2_indirect_reg); + +u32 get_l2_indirect_reg(u32 reg_addr) +{ + u32 val; + unsigned long flags; + + raw_spin_lock_irqsave(&l2_access_lock, flags); + uncached_logk(LOGK_L2CPREAD, (void *)reg_addr); + asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t" + "isb\n\t" + "mrc p15, 3, %[l2cpdr], c15, c0, 7\n\t" + : [l2cpdr]"=r" (val) + : [l2cpselr]"r" (reg_addr) + ); + raw_spin_unlock_irqrestore(&l2_access_lock, flags); + + return val; +} +EXPORT_SYMBOL(get_l2_indirect_reg); diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c new file mode 100644 index 000000000000..8d5dcc5001b7 --- /dev/null +++ b/arch/arm/mach-msm/msm_cache_dump.c @@ -0,0 +1,274 @@ +/* Copyright (c) 2012-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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <soc/qcom/scm.h> +#include <asm/cacheflush.h> +#include <mach/msm_cache_dump.h> +#include <mach/msm_iomap.h> +#include <soc/qcom/memory_dump.h> + +#define L2_DUMP_OFFSET 0x14 + +static dma_addr_t msm_cache_dump_addr; +static void *msm_cache_dump_vaddr; + +/* + * These should not actually be dereferenced. There's no + * need for a virtual mapping, but the physical address is + * necessary. + */ +static struct l1_cache_dump *l1_dump; +static struct l2_cache_dump *l2_dump; + +static int msm_cache_dump_panic(struct notifier_block *this, + unsigned long event, void *ptr) +{ +#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC + scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2); + scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1); +#endif + return 0; +} + +static struct notifier_block msm_cache_dump_blk = { + .notifier_call = msm_cache_dump_panic, + /* + * higher priority to ensure this runs before another panic handler + * flushes the caches. + */ + .priority = 1, +}; + +static int msm_cache_dump_probe(struct platform_device *pdev) +{ + struct msm_cache_dump_platform_data *d = pdev->dev.platform_data; + struct msm_client_dump l1_dump_entry, l2_dump_entry; + struct msm_dump_entry dump_entry; + struct msm_dump_data *l1_inst_data, *l1_data_data, *l2_data; + int ret, cpu; + struct { + unsigned long buf; + unsigned long size; + } l1_cache_data; + u32 l1_size, l2_size; + unsigned long total_size; + u32 l1_inst_size, l1_data_size; + phys_addr_t l1_inst_start, l1_data_start, l2_start; + + if (pdev->dev.of_node) { + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,l1-dump-size", &l1_size); + if (ret) + return ret; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,l2-dump-size", &l2_size); + if (ret) + return ret; + } else { + l1_size = d->l1_size; + l2_size = d->l2_size; + }; + + total_size = l1_size + l2_size; + msm_cache_dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev, + total_size, &msm_cache_dump_addr, + GFP_KERNEL); + + if (!msm_cache_dump_vaddr) { + pr_err("%s: Could not get memory for cache dumping\n", + __func__); + return -ENOMEM; + } + + memset(msm_cache_dump_vaddr, 0xFF, total_size); + /* Clean caches before sending buffer to TZ */ + dmac_clean_range(msm_cache_dump_vaddr, + msm_cache_dump_vaddr + total_size); + + l1_cache_data.buf = msm_cache_dump_addr; + l1_cache_data.size = l1_size; + + ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID, + &l1_cache_data, sizeof(l1_cache_data), NULL, 0); + + if (ret) + pr_err("%s: could not register L1 buffer ret = %d.\n", + __func__, ret); + + l1_dump = (struct l1_cache_dump *)(uint32_t)msm_cache_dump_addr; + l2_dump = (struct l2_cache_dump *)(uint32_t)(msm_cache_dump_addr + + l1_size); + +#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC) + l1_cache_data.buf = msm_cache_dump_addr + l1_size; + l1_cache_data.size = l2_size; + + ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID, + &l1_cache_data, sizeof(l1_cache_data), NULL, 0); + + if (ret) + pr_err("%s: could not register L2 buffer ret = %d.\n", + __func__, ret); +#endif + + if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1) { + l1_dump_entry.id = MSM_L1_CACHE; + l1_dump_entry.start_addr = msm_cache_dump_addr; + l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1; + + l2_dump_entry.id = MSM_L2_CACHE; + l2_dump_entry.start_addr = msm_cache_dump_addr + l1_size; + l2_dump_entry.end_addr = l2_dump_entry.start_addr + l2_size - 1; + + ret = msm_dump_tbl_register(&l1_dump_entry); + if (ret) + pr_err("Could not register L1 dump area: %d\n", ret); + + ret = msm_dump_tbl_register(&l2_dump_entry); + if (ret) + pr_err("Could not register L2 dump area: %d\n", ret); + } else { + l1_inst_data = kzalloc(sizeof(struct msm_dump_data) * + num_present_cpus(), GFP_KERNEL); + if (!l1_inst_data) { + pr_err("l1 inst data structure allocation failed\n"); + ret = -ENOMEM; + goto err0; + } + + l1_data_data = kzalloc(sizeof(struct msm_dump_data) * + num_present_cpus(), GFP_KERNEL); + if (!l1_data_data) { + pr_err("l1 data data structure allocation failed\n"); + ret = -ENOMEM; + goto err1; + } + + l1_inst_start = msm_cache_dump_addr; + l1_data_start = msm_cache_dump_addr + (l1_size / 2); + l1_inst_size = l1_size / (num_present_cpus() * 2); + l1_data_size = l1_inst_size; + + for_each_cpu(cpu, cpu_present_mask) { + l1_inst_data[cpu].addr = l1_inst_start + + cpu * l1_inst_size; + l1_inst_data[cpu].len = l1_inst_size; + dump_entry.id = MSM_DUMP_DATA_L1_INST_CACHE + cpu; + dump_entry.addr = virt_to_phys(&l1_inst_data[cpu]); + ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, + &dump_entry); + /* + * Don't free the buffers in case of error since + * registration may have succeeded for some cpus. + */ + if (ret) + pr_err("cpu %d l1 inst dump setup failed\n", + cpu); + + l1_data_data[cpu].addr = l1_data_start + + cpu * l1_data_size; + l1_data_data[cpu].len = l1_data_size; + dump_entry.id = MSM_DUMP_DATA_L1_DATA_CACHE + cpu; + dump_entry.addr = virt_to_phys(&l1_data_data[cpu]); + ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, + &dump_entry); + /* + * Don't free the buffers in case of error since + * registration may have succeeded for some cpus. + */ + if (ret) + pr_err("cpu %d l1 data dump setup failed\n", + cpu); + } + + l2_data = kzalloc(sizeof(struct msm_dump_data) * + num_present_cpus(), GFP_KERNEL); + if (!l2_data) { + pr_err("l2 data structure allocation failed\n"); + ret = -ENOMEM; + goto err2; + } + + l2_start = msm_cache_dump_addr + l1_size; + + l2_data->addr = l2_start; + l2_data->len = l2_size; + dump_entry.id = MSM_DUMP_DATA_L2_CACHE; + dump_entry.addr = virt_to_phys(l2_data); + ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, + &dump_entry); + if (ret) + pr_err("l2 dump setup failed\n"); + } + + atomic_notifier_chain_register(&panic_notifier_list, + &msm_cache_dump_blk); + return 0; +err2: + kfree(l1_data_data); +err1: + kfree(l1_inst_data); +err0: + dma_free_coherent(&pdev->dev, total_size, msm_cache_dump_vaddr, + msm_cache_dump_addr); + return ret; +} + +static int msm_cache_dump_remove(struct platform_device *pdev) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, + &msm_cache_dump_blk); + return 0; +} + +static struct of_device_id cache_dump_match_table[] = { + { .compatible = "qcom,cache_dump", }, + {} +}; +EXPORT_COMPAT("qcom,cache_dump"); + +static struct platform_driver msm_cache_dump_driver = { + .remove = msm_cache_dump_remove, + .driver = { + .name = "msm_cache_dump", + .owner = THIS_MODULE, + .of_match_table = cache_dump_match_table, + }, +}; + +static int __init msm_cache_dump_init(void) +{ + return platform_driver_probe(&msm_cache_dump_driver, + msm_cache_dump_probe); +} + +static void __exit msm_cache_dump_exit(void) +{ + platform_driver_unregister(&msm_cache_dump_driver); +} +late_initcall(msm_cache_dump_init); +module_exit(msm_cache_dump_exit) diff --git a/arch/arm/mach-msm/msm_mem_hole.c b/arch/arm/mach-msm/msm_mem_hole.c new file mode 100644 index 000000000000..736219b63ab1 --- /dev/null +++ b/arch/arm/mach-msm/msm_mem_hole.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012, 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. + */ + +/** + * This module exists for the express purpose of removing memory + * via the msm memory-remove mechanism (see + * Documentation/devicetree/bindings/arm/msm/memory-reserve.txt). Compiling + * this module into a kernel is essentially the means by which any + * nodes in the device tree with compatible = + * "qcom,msm-mem-hole" will be "activated", thus providing a + * convenient mechanism for enabling/disabling memory removal + * (qcom,memory-*). + */ + +#include <linux/module.h> + +#define MSM_MEM_HOLE_COMPAT_STR "qcom,msm-mem-hole" + +EXPORT_COMPAT(MSM_MEM_HOLE_COMPAT_STR); diff --git a/arch/arm/mach-msm/msm_mpmctr.c b/arch/arm/mach-msm/msm_mpmctr.c new file mode 100644 index 000000000000..cc0c1c36d7c8 --- /dev/null +++ b/arch/arm/mach-msm/msm_mpmctr.c @@ -0,0 +1,99 @@ +/* Copyright (c) 2013, 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 <linux/kernel.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/smp.h> +#include <linux/clk.h> +#include <linux/cpu.h> +#include <linux/sched.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <mach/msm_mpmctr.h> + +static void __iomem *mpm_timer_base; + +uint32_t msm_mpm_get_count(void) +{ + uint32_t count; + if (!mpm_timer_base) + return 0; + + count = __raw_readl_no_log(mpm_timer_base); + pr_debug("mpm sclk sync:(%u)", count); + return count; +} +EXPORT_SYMBOL(msm_mpm_get_count); + +static inline void msm_mpmctr_show_count(void) +{ + unsigned long long t; + unsigned long nsec_rem; + + t = sched_clock(); + + nsec_rem = do_div(t, 1000000000)/1000; + + printk(KERN_INFO "mpm_counter: [%5lu.%06lu]:(%u)\n", + (unsigned long)t, nsec_rem, + msm_mpm_get_count()); + +} + +static struct of_device_id msm_mpmctr_of_match[] = { + {.compatible = "qcom,mpm2-sleep-counter"}, + {} +}; + +static struct platform_driver msm_mpmctr_driver = { + .driver = { + .name = "msm_mpctr", + .owner = THIS_MODULE, + .of_match_table = msm_mpmctr_of_match, + }, +}; + +static int __init mpmctr_set_register(struct device_node *np) +{ + if (of_get_address(np, 0, NULL, NULL)) { + mpm_timer_base = of_iomap(np, 0); + if (!mpm_timer_base) { + pr_err("%s: cannot map timer base\n", __func__); + return -ENOMEM; + } + } + return 0; +} + +static int __init msm_mpmctr_probe(struct platform_device *pdev) +{ + if (!pdev->dev.of_node) + return -ENODEV; + + if (mpmctr_set_register(pdev->dev.of_node)) + return -ENODEV; + + msm_mpmctr_show_count(); + + return 0; +} + +static int __init mpmctr_init(void) +{ + return platform_driver_probe(&msm_mpmctr_driver, msm_mpmctr_probe); +} + +module_init(mpmctr_init) diff --git a/arch/arm/mach-msm/msm_watchdog.h b/arch/arm/mach-msm/msm_watchdog.h new file mode 100644 index 000000000000..6818680d6814 --- /dev/null +++ b/arch/arm/mach-msm/msm_watchdog.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2011-2012, 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. + */ + +#ifndef __ARCH_ARM_MACH_MSM_MSM_WATCHDOG_H +#define __ARCH_ARM_MACH_MSM_MSM_WATCHDOG_H + +/* The base is just address of the WDT_RST register */ +#define WDT0_OFFSET 0x38 +#define WDT1_OFFSET 0x60 + +struct msm_watchdog_pdata { + /* pet interval period in ms */ + unsigned int pet_time; + /* bark timeout in ms */ + unsigned int bark_time; + bool has_secure; + bool needs_expired_enable; + bool has_vic; + /* You have to be running in secure mode to use FIQ */ + bool use_kernel_fiq; + void __iomem *base; +}; + +struct msm_watchdog_dump { + uint32_t magic; + uint32_t curr_cpsr; + uint32_t usr_r0; + uint32_t usr_r1; + uint32_t usr_r2; + uint32_t usr_r3; + uint32_t usr_r4; + uint32_t usr_r5; + uint32_t usr_r6; + uint32_t usr_r7; + uint32_t usr_r8; + uint32_t usr_r9; + uint32_t usr_r10; + uint32_t usr_r11; + uint32_t usr_r12; + uint32_t usr_r13; + uint32_t usr_r14; + uint32_t irq_spsr; + uint32_t irq_r13; + uint32_t irq_r14; + uint32_t svc_spsr; + uint32_t svc_r13; + uint32_t svc_r14; + uint32_t abt_spsr; + uint32_t abt_r13; + uint32_t abt_r14; + uint32_t und_spsr; + uint32_t und_r13; + uint32_t und_r14; + uint32_t fiq_spsr; + uint32_t fiq_r8; + uint32_t fiq_r9; + uint32_t fiq_r10; + uint32_t fiq_r11; + uint32_t fiq_r12; + uint32_t fiq_r13; + uint32_t fiq_r14; +}; + +void msm_wdog_fiq_setup(void *stack); +extern unsigned int msm_wdog_fiq_length, msm_wdog_fiq_start; +extern unsigned int msm7k_fiq_start, msm7k_fiq_length; + +#ifdef CONFIG_MSM_WATCHDOG +void pet_watchdog(void); +#else +static inline void pet_watchdog(void) { } +#endif + +#endif diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c new file mode 100644 index 000000000000..8b07d6f6d24c --- /dev/null +++ b/arch/arm/mach-msm/perf_debug.c @@ -0,0 +1,83 @@ +/* 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 <linux/types.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> + +/* + * Subsequent patches should add an entry to end of this string. + * Format is incrementing sequence number followed by text of + * patch commit title with newline. + * Note trailing ';' is on its own line to simplify addition of + * future strings. + */ +static char *descriptions = + " 0 msm: perf: add debug patch logging framework\n" + " 1 Perf: port perf-events to 3.10 kernel\n" + " 2 Perf: keep events across hotplug\n" + " 3 Perf: bring CPU online if needed when disabling irq\n" + " 4 Perf: Support sw events across hotplug\n" + " 5 msm: perf: initialise krait perf L2 counter enables\n" + " 6 msm: perf: clean up duplicate constraint events\n" + " 7 Perf: Add L1 counters to tracepoints\n" + " 8 Perf: Make per-process counters configurable\n" + " 9 msm: perf: Add L2 support for tracecounters\n" + "10 ARM: dts: msm: add perf-events support for apq8084\n" + "11 ARM: dts: msm: add perf-events support for msmsamarium\n" + "12 Perf: Make per-process counters cumulative\n" + "13 Perf: Fix PID for tracepoints\n" + "14 Perf: preserve registers across hotplug\n" + "15 msm: perf: Fix cpu id logic in tracectr notifier\n" + "16 msm: perf: tracectr: Initialize cnts after hotplug\n" + "17 Perf: Reset pmu after hotplug\n" + "18 ARM: dts: msm: add perf-events support for msm8916\n" + "19 Perf: Enable pmuv3 on 32 bit kernel\n" +; + +static ssize_t desc_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + return simple_read_from_buffer(buf, count, pos, descriptions, + strlen(descriptions)); +} + +static const struct file_operations perf_debug_desc_fops = { + .read = desc_read, +}; + +static int msm_perf_debugfs_init(void) +{ + int ret = 0; + struct dentry *dir; + struct dentry *file; + + dir = debugfs_create_dir("msm-perf-patches", NULL); + if (IS_ERR_OR_NULL(dir)) { + pr_err("failed to create msm-perf-patches dir in debugfs\n"); + ret = PTR_ERR(dir); + goto init_exit; + } + + file = debugfs_create_file("descriptions", 0444, dir, NULL, + &perf_debug_desc_fops); + if (IS_ERR_OR_NULL(file)) { + debugfs_remove(dir); + pr_err("failed to create descriptions file for msm-perf-patches\n"); + ret = PTR_ERR(file); + goto init_exit; + } + +init_exit: + return ret; +} +late_initcall(msm_perf_debugfs_init); diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c new file mode 100644 index 000000000000..47816c9c04a8 --- /dev/null +++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2011, 2012 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 <linux/irq.h> +#include <asm/pmu.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#include <mach/msm-krait-l2-accessors.h> + +/* + * The L2 PMU is shared between all CPU's, so protect + * its bitmap access. + */ +struct pmu_constraints { + u64 pmu_bitmap; + u8 codes[64]; + raw_spinlock_t lock; +} l2_pmu_constraints = { + .pmu_bitmap = 0, + .codes = {-1}, + .lock = __RAW_SPIN_LOCK_UNLOCKED(l2_pmu_constraints.lock), +}; + +/* NRCCG format for perf RAW codes. */ +PMU_FORMAT_ATTR(l2_prefix, "config:16-19"); +PMU_FORMAT_ATTR(l2_reg, "config:12-15"); +PMU_FORMAT_ATTR(l2_code, "config:4-11"); +PMU_FORMAT_ATTR(l2_grp, "config:0-3"); + +static struct attribute *msm_l2_ev_formats[] = { + &format_attr_l2_prefix.attr, + &format_attr_l2_reg.attr, + &format_attr_l2_code.attr, + &format_attr_l2_grp.attr, + NULL, +}; + +/* + * Format group is essential to access PMU's from userspace + * via their .name field. + */ +static struct attribute_group msm_l2_pmu_format_group = { + .name = "format", + .attrs = msm_l2_ev_formats, +}; + +static const struct attribute_group *msm_l2_pmu_attr_grps[] = { + &msm_l2_pmu_format_group, + NULL, +}; + +static u32 l2_orig_filter_prefix = 0x000f0030; + +/* L2 slave port traffic filtering */ +static u32 l2_slv_filter_prefix = 0x000f0010; + +static int total_l2_ctrs; +static int l2_cycle_ctr_idx; + +static u32 pmu_type; +static u32 from_idle; + +static struct arm_pmu krait_l2_pmu; +static struct arm_pmu *krait_l2_pmu_addr = &krait_l2_pmu; + +static struct perf_event *l2_events[MAX_KRAIT_L2_CTRS]; +static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_KRAIT_L2_CTRS)]; + +static struct pmu_hw_events krait_l2_pmu_hw_events = { + .events = l2_events, + .used_mask = l2_used_mask, + .from_idle = &from_idle, + .pmu_lock = __RAW_SPIN_LOCK_UNLOCKED(krait_l2_pmu_hw_events.pmu_lock), +}; + +struct event_desc { + int event_groupsel; + int event_reg; + int event_group_code; +}; + +static struct pmu_hw_events *krait_l2_get_hw_events(void) +{ + return &krait_l2_pmu_hw_events; +} + +void get_event_desc(u64 config, struct event_desc *evdesc) +{ + /* L2PMEVCNTRX */ + evdesc->event_reg = (config & EVENT_REG_MASK) >> EVENT_REG_SHIFT; + /* Group code (row ) */ + evdesc->event_group_code = + (config & EVENT_GROUPCODE_MASK) >> EVENT_GROUPCODE_SHIFT; + /* Group sel (col) */ + evdesc->event_groupsel = (config & EVENT_GROUPSEL_MASK); + + pr_debug("%s: reg: %x, group_code: %x, groupsel: %x\n", __func__, + evdesc->event_reg, evdesc->event_group_code, + evdesc->event_groupsel); +} + +static void set_evcntcr(int ctr) +{ + u32 evtcr_reg = (ctr * 16) + IA_L2PMXEVCNTCR_BASE; + + set_l2_indirect_reg(evtcr_reg, 0x0); +} + +static void set_evtyper(int event_groupsel, int event_reg, int ctr) +{ + u32 evtype_reg = (ctr * 16) + IA_L2PMXEVTYPER_BASE; + u32 evtype_val = event_groupsel + (4 * event_reg); + + set_l2_indirect_reg(evtype_reg, evtype_val); +} + +static void set_evres(int event_groupsel, int event_reg, int event_group_code) +{ + u32 group_reg = event_reg + IA_L2PMRESX_BASE; + u32 group_val = + RESRX_VALUE_EN | (event_group_code << (8 * event_groupsel)); + u32 resr_val; + u32 group_byte = 0xff; + u32 group_mask = ~(group_byte << (8 * event_groupsel)); + + resr_val = get_l2_indirect_reg(group_reg); + resr_val &= group_mask; + resr_val |= group_val; + + set_l2_indirect_reg(group_reg, resr_val); +} + +static void set_evfilter_task_mode(int ctr, unsigned int is_slv) +{ + u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE; + u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id(); + + if (is_slv) + filter_val = l2_slv_filter_prefix; + + set_l2_indirect_reg(filter_reg, filter_val); +} + +static void set_evfilter_sys_mode(int ctr, unsigned int is_slv, int cpu, + unsigned int is_tracectr) +{ + u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE; + u32 filter_val = l2_orig_filter_prefix | 0xf; + + if (is_slv == 1) + filter_val = l2_slv_filter_prefix; + if (is_tracectr == 1) + filter_val = l2_orig_filter_prefix | 1 << cpu; + + set_l2_indirect_reg(filter_reg, filter_val); +} + +static void enable_intenset(u32 idx) +{ + if (idx == l2_cycle_ctr_idx) + set_l2_indirect_reg(L2PMINTENSET, 1 << L2CYCLE_CTR_BIT); + else + set_l2_indirect_reg(L2PMINTENSET, 1 << idx); +} + +static void disable_intenclr(u32 idx) +{ + if (idx == l2_cycle_ctr_idx) + set_l2_indirect_reg(L2PMINTENCLR, 1 << L2CYCLE_CTR_BIT); + else + set_l2_indirect_reg(L2PMINTENCLR, 1 << idx); +} + +static void enable_counter(u32 idx) +{ + if (idx == l2_cycle_ctr_idx) + set_l2_indirect_reg(L2PMCNTENSET, 1 << L2CYCLE_CTR_BIT); + else + set_l2_indirect_reg(L2PMCNTENSET, 1 << idx); +} + +static void disable_counter(u32 idx) +{ + if (idx == l2_cycle_ctr_idx) + set_l2_indirect_reg(L2PMCNTENCLR, 1 << L2CYCLE_CTR_BIT); + else + set_l2_indirect_reg(L2PMCNTENCLR, 1 << idx); +} + +static u32 krait_l2_read_counter(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + u32 val; + u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE; + + if (idx == l2_cycle_ctr_idx) + val = get_l2_indirect_reg(L2PMCCNTR); + else + val = get_l2_indirect_reg(counter_reg); + + return val; +} + +static void krait_l2_write_counter(struct perf_event *event, u32 val) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE; + + if (idx == l2_cycle_ctr_idx) + set_l2_indirect_reg(L2PMCCNTR, val); + else + set_l2_indirect_reg(counter_reg, val); +} + +static void krait_l2_stop_counter(struct hw_perf_event *hwc, int idx) +{ + disable_intenclr(idx); + disable_counter(idx); + + pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, + hwc->config_base, idx); +} + +static void krait_l2_enable(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + struct event_desc evdesc; + unsigned long iflags; + unsigned int is_slv = 0; + unsigned int is_tracectr = 0; + unsigned int evt_prefix; + + raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags); + + if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) + goto out; + + /* Check if user requested any special origin filtering. */ + evt_prefix = (hwc->config_base & + EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT; + + if (evt_prefix == L2_SLAVE_EV_PREFIX) + is_slv = 1; + else if (evt_prefix == L2_TRACECTR_PREFIX) + is_tracectr = 1; + + set_evcntcr(idx); + + memset(&evdesc, 0, sizeof(evdesc)); + + get_event_desc(hwc->config_base, &evdesc); + + set_evtyper(evdesc.event_groupsel, evdesc.event_reg, idx); + + set_evres(evdesc.event_groupsel, evdesc.event_reg, + evdesc.event_group_code); + + if (event->cpu < 0) + set_evfilter_task_mode(idx, is_slv); + else + set_evfilter_sys_mode(idx, is_slv, event->cpu, is_tracectr); + +out: + enable_intenset(idx); + enable_counter(idx); + + raw_spin_unlock_irqrestore(&krait_l2_pmu_hw_events.pmu_lock, iflags); + + pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n", + __func__, idx, hwc->config_base, hwc->config, smp_processor_id()); +} + +static void krait_l2_disable(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + unsigned long iflags; + + raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags); + + krait_l2_stop_counter(hwc, idx); + + raw_spin_unlock_irqrestore(&krait_l2_pmu_hw_events.pmu_lock, iflags); + + pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base); + +} + +static int krait_l2_get_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int ctr = 0; + + if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) { + if (test_and_set_bit(l2_cycle_ctr_idx, cpuc->used_mask)) + return -EAGAIN; + + return l2_cycle_ctr_idx; + } + + for (ctr = 0; ctr < total_l2_ctrs - 1; ctr++) { + if (!test_and_set_bit(ctr, cpuc->used_mask)) + return ctr; + } + + return -EAGAIN; +} + +static void krait_l2_start(struct arm_pmu *l2_pmu) +{ + isb(); + set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_ENABLE); +} + +static void krait_l2_stop(struct arm_pmu *l2_pmu) +{ + set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_DISABLE); + isb(); +} + +u32 get_reset_pmovsr(void) +{ + int val; + + val = get_l2_indirect_reg(L2PMOVSR); + /* reset it */ + val &= 0xffffffff; + set_l2_indirect_reg(L2PMOVSR, val); + + return val; +} + +static irqreturn_t krait_l2_handle_irq(int irq_num, void *dev) +{ + unsigned long pmovsr; + struct perf_sample_data data; + struct pt_regs *regs; + struct perf_event *event; + struct hw_perf_event *hwc; + int bitp; + int idx = 0; + + pmovsr = get_reset_pmovsr(); + + if (!(pmovsr & 0xffffffff)) + return IRQ_NONE; + + regs = get_irq_regs(); + + while (pmovsr) { + bitp = __ffs(pmovsr); + + if (bitp == L2CYCLE_CTR_BIT) + idx = l2_cycle_ctr_idx; + else + idx = bitp; + + event = krait_l2_pmu_hw_events.events[idx]; + + if (!event) + goto next; + + if (!test_bit(idx, krait_l2_pmu_hw_events.used_mask)) + goto next; + + hwc = &event->hw; + armpmu_event_update(event); + perf_sample_data_init(&data, 0, hwc->last_period); + + if (!armpmu_event_set_period(event)) + goto next; + + if (perf_event_overflow(event, &data, regs)) + disable_counter(hwc->idx); +next: + pmovsr &= (pmovsr - 1); + } + + irq_work_run(); + + return IRQ_HANDLED; +} + +static int krait_l2_map_event(struct perf_event *event) +{ + if (pmu_type > 0 && pmu_type == event->attr.type) + return event->attr.config & L2_EVT_MASK; + else + return -ENOENT; +} + +static int +krait_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq, void *dev_id) +{ + return request_irq(irq, *handle_irq, + IRQF_DISABLED | IRQF_NOBALANCING, + "krait-l2-armpmu", &krait_l2_pmu_addr); +} + +static void +krait_l2_pmu_generic_free_irq(int irq, void *dev_id) +{ + if (irq >= 0) + free_irq(irq, &krait_l2_pmu_addr); +} + +static int msm_l2_test_set_ev_constraint(struct perf_event *event) +{ + u32 evt_type = event->attr.config & L2_EVT_MASK; + u8 evt_prefix = (evt_type & EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT; + u8 reg = (evt_type & 0x0F000) >> 12; + u8 group = evt_type & 0x0000F; + u8 code = (evt_type & 0x00FF0) >> 4; + unsigned long flags; + u32 err = 0; + u64 bitmap_t; + u32 shift_idx; + + if (evt_prefix == L2_TRACECTR_PREFIX) + return err; + /* + * Cycle counter collision is detected in + * get_event_idx(). + */ + if (evt_type == L2CYCLE_CTR_RAW_CODE) + return err; + + raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags); + + shift_idx = ((reg * 4) + group); + + bitmap_t = 1 << shift_idx; + + if (!(l2_pmu_constraints.pmu_bitmap & bitmap_t)) { + l2_pmu_constraints.pmu_bitmap |= bitmap_t; + l2_pmu_constraints.codes[shift_idx] = code; + goto out; + } else { + /* + * If NRCCG's are identical, + * its not column exclusion. + */ + if (l2_pmu_constraints.codes[shift_idx] != code) + err = -EPERM; + else + /* + * If the event is counted in syswide mode + * then we want to count only on one CPU + * and set its filter to count from all. + * This sets the event OFF on all but one + * CPU. + */ + if (!(event->cpu < 0)) { + event->state = PERF_EVENT_STATE_OFF; + event->attr.constraint_duplicate = 1; + } + } +out: + raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags); + return err; +} + +static int msm_l2_clear_ev_constraint(struct perf_event *event) +{ + u32 evt_type = event->attr.config & L2_EVT_MASK; + u8 evt_prefix = (evt_type & EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT; + u8 reg = (evt_type & 0x0F000) >> 12; + u8 group = evt_type & 0x0000F; + unsigned long flags; + u64 bitmap_t; + u32 shift_idx; + + if (evt_prefix == L2_TRACECTR_PREFIX) + return 1; + raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags); + + shift_idx = ((reg * 4) + group); + + bitmap_t = 1 << shift_idx; + + /* Clear constraint bit. */ + l2_pmu_constraints.pmu_bitmap &= ~bitmap_t; + + /* Clear code. */ + l2_pmu_constraints.codes[shift_idx] = -1; + + raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags); + return 1; +} + +int get_num_events(void) +{ + int val; + + val = get_l2_indirect_reg(L2PMCR); + + /* + * Read bits 15:11 of the L2PMCR and add 1 + * for the cycle counter. + */ + return ((val >> PMCR_NUM_EV_SHIFT) & PMCR_NUM_EV_MASK) + 1; +} + +static struct arm_pmu krait_l2_pmu = { + .name = (char *)"msm-l2", + .start = krait_l2_start, + .stop = krait_l2_stop, + .handle_irq = krait_l2_handle_irq, + .request_pmu_irq = krait_l2_pmu_generic_request_irq, + .free_pmu_irq = krait_l2_pmu_generic_free_irq, + .enable = krait_l2_enable, + .disable = krait_l2_disable, + .get_event_idx = krait_l2_get_event_idx, + .read_counter = krait_l2_read_counter, + .write_counter = krait_l2_write_counter, + .map_event = krait_l2_map_event, + .max_period = MAX_L2_PERIOD, + .get_hw_events = krait_l2_get_hw_events, + .request_irq = cpu_pmu_request_irq, + .free_irq = cpu_pmu_free_irq, + .test_set_event_constraints = msm_l2_test_set_ev_constraint, + .clear_event_constraints = msm_l2_clear_ev_constraint, + .pmu.attr_groups = msm_l2_pmu_attr_grps, +}; + +/* + * PMU platform driver and devicetree bindings. + */ +static struct of_device_id l2pmu_of_device_ids[] = { + {.compatible = "qcom,l2-pmu"}, + {}, +}; + +static int krait_l2_pmu_device_probe(struct platform_device *pdev) +{ + krait_l2_pmu.plat_device = pdev; + + if (!armpmu_register(&krait_l2_pmu, -1)) + pmu_type = krait_l2_pmu.pmu.type; + + return 0; +} + +static struct platform_driver krait_l2_pmu_driver = { + .driver = { + .name = "l2-pmu", + .of_match_table = l2pmu_of_device_ids, + }, + .probe = krait_l2_pmu_device_probe, +}; + +static int __init register_krait_l2_pmu_driver(void) +{ + int i; + + /* Reset all ctrs */ + set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL); + + /* Get num of counters in the L2cc PMU. */ + total_l2_ctrs = get_num_events(); + krait_l2_pmu.num_events = total_l2_ctrs; + + pr_info("Detected %d counters on the L2CC PMU.\n", + total_l2_ctrs); + + /* + * The L2 cycle counter index in the used_mask + * bit stream is always after the other counters. + * Counter indexes begin from 0 to keep it consistent + * with the h/w. + */ + l2_cycle_ctr_idx = total_l2_ctrs - 1; + + /* Avoid spurious interrupt if any */ + get_reset_pmovsr(); + + /* Clear counter enables */ + disable_counter(l2_cycle_ctr_idx); + for (i = 0; i < total_l2_ctrs; i++) + disable_counter(i); + + return platform_driver_register(&krait_l2_pmu_driver); +} +device_initcall(register_krait_l2_pmu_driver); diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c new file mode 100644 index 000000000000..43165c9b9f2f --- /dev/null +++ b/arch/arm/mach-msm/perf_trace_counters.c @@ -0,0 +1,185 @@ +/* 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 <asm/thread_notify.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/cpu.h> +#define CREATE_TRACE_POINTS +#include "perf_trace_counters.h" + +static unsigned int tp_pid_state; + +DEFINE_PER_CPU(u32, previous_ccnt); +DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts); +DEFINE_PER_CPU(u32[NUM_L2_PERCPU], previous_l2_cnts); +DEFINE_PER_CPU(u32, old_pid); +DEFINE_PER_CPU(u32, hotplug_flag); +/* Reset per_cpu variables that store counter values uppn CPU hotplug */ +static int tracectr_cpu_hotplug_notifier(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + int ret = NOTIFY_OK; + int cpu = (int)hcpu; + + if ((action & (~CPU_TASKS_FROZEN)) == CPU_STARTING) + per_cpu(hotplug_flag, cpu) = 1; + + return ret; +} + +static struct notifier_block tracectr_cpu_hotplug_notifier_block = { + .notifier_call = tracectr_cpu_hotplug_notifier, +}; + +static void setup_prev_cnts(u32 cpu) +{ + int i; + u32 cnten_val; + + /* Read PMCNTENSET */ + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(cnten_val)); + /* Disable all the counters that were enabled */ + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(cnten_val)); + if (cnten_val & CC) { + /* Read value */ + asm volatile("mrc p15, 0, %0, c9, c13, 0" + : "=r"(per_cpu(previous_ccnt, cpu))); + } + + for (i = 0; i < NUM_L1_CTRS; i++) { + if (cnten_val & (1 << i)) { + /* Select */ + asm volatile("mcr p15, 0, %0, c9, c12, 5" + : : "r"(i)); + /* Read value */ + asm volatile("mrc p15, 0, %0, c9, c13, 2" + : "=r"(per_cpu(previous_l1_cnts[i], cpu))); + } + } + /* Enable all the counters that were disabled */ + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(cnten_val)); +} + +static int tracectr_notifier(struct notifier_block *self, unsigned long cmd, + void *v) +{ + struct thread_info *thread = v; + int current_pid; + u32 cpu = thread->cpu; + + if (cmd != THREAD_NOTIFY_SWITCH) + return -EFAULT; + + current_pid = thread->task->pid; + if (per_cpu(old_pid, cpu) != -1) { + if (per_cpu(hotplug_flag, cpu) == 1) { + per_cpu(hotplug_flag, cpu) = 0; + setup_prev_cnts(cpu); + } else + trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu), + current_pid); + } + per_cpu(old_pid, cpu) = current_pid; + return NOTIFY_OK; +} + +static struct notifier_block tracectr_notifier_block = { + .notifier_call = tracectr_notifier, +}; + +static void enable_tp_pid(void) +{ + if (tp_pid_state == 0) { + tp_pid_state = 1; + thread_register_notifier(&tracectr_notifier_block); + } +} + +static void disable_tp_pid(void) +{ + if (tp_pid_state == 1) { + tp_pid_state = 0; + thread_unregister_notifier(&tracectr_notifier_block); + } +} + +static ssize_t read_enabled_perftp_file_bool(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[2]; + buf[1] = '\n'; + if (tp_pid_state == 0) + buf[0] = '0'; + else + buf[0] = '1'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t write_enabled_perftp_file_bool(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + size_t buf_size; + + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + switch (buf[0]) { + case 'y': + case 'Y': + case '1': + enable_tp_pid(); + break; + case 'n': + case 'N': + case '0': + disable_tp_pid(); + break; + } + + return count; +} + +static const struct file_operations fops_perftp = { + .read = read_enabled_perftp_file_bool, + .write = write_enabled_perftp_file_bool, + .llseek = default_llseek, +}; + +int __init init_tracecounters(void) +{ + struct dentry *dir; + struct dentry *file; + unsigned int value = 1; + int cpu; + + dir = debugfs_create_dir("perf_debug_tp", NULL); + if (!dir) + return -ENOMEM; + file = debugfs_create_file("enabled", 0660, dir, + &value, &fops_perftp); + if (!file) { + debugfs_remove(dir); + return -ENOMEM; + } + register_cpu_notifier(&tracectr_cpu_hotplug_notifier_block); + for_each_possible_cpu(cpu) + per_cpu(old_pid, cpu) = -1; + return 0; +} + +int __exit exit_tracecounters(void) +{ + unregister_cpu_notifier(&tracectr_cpu_hotplug_notifier_block); + return 0; +} +late_initcall(init_tracecounters); diff --git a/arch/arm/mach-msm/perf_trace_counters.h b/arch/arm/mach-msm/perf_trace_counters.h new file mode 100644 index 000000000000..c738bedc97b4 --- /dev/null +++ b/arch/arm/mach-msm/perf_trace_counters.h @@ -0,0 +1,161 @@ +/* Copyright (c) 2013, 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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM perf_trace_counters + +#if !defined(_PERF_TRACE_COUNTERS_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _PERF_TRACE_COUNTERS_H_ + +/* Ctr index for PMCNTENSET/CLR */ +#define CC 0x80000000 +#define C0 0x1 +#define C1 0x2 +#define C2 0x4 +#define C3 0x8 +#define C_ALL (CC | C0 | C1 | C2 | C3) +#define NUM_L1_CTRS 4 +#define NUM_L2_PERCPU 2 + +#include <linux/sched.h> +#include <linux/cpumask.h> +#include <linux/tracepoint.h> +#include <mach/msm-krait-l2-accessors.h> + +DECLARE_PER_CPU(u32, previous_ccnt); +DECLARE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts); +DECLARE_PER_CPU(u32[NUM_L2_PERCPU], previous_l2_cnts); +TRACE_EVENT(sched_switch_with_ctrs, + + TP_PROTO(pid_t prev, pid_t next), + + TP_ARGS(prev, next), + + TP_STRUCT__entry( + __field(pid_t, old_pid) + __field(pid_t, new_pid) + __field(u32, cctr) + __field(u32, ctr0) + __field(u32, ctr1) + __field(u32, ctr2) + __field(u32, ctr3) + __field(u32, lctr0) + __field(u32, lctr1) + ), + + TP_fast_assign( + u32 cpu = smp_processor_id(); + u32 idx; + u32 i; + u32 counter_reg; + u32 val; + u32 cnten_val; + u32 num_l2ctrs; + u32 num_cores = nr_cpu_ids; + u32 total_ccnt = 0; + u32 total_cnt = 0; + u32 delta_l1_cnts[NUM_L1_CTRS]; + u32 delta_l2_cnts[NUM_L2_PERCPU]; + __entry->old_pid = prev; + __entry->new_pid = next; + + val = get_l2_indirect_reg(L2PMCR); + num_l2ctrs = ((val >> 11) & 0x1f) + 1; + + /* Read PMCNTENSET */ + asm volatile("mrc p15, 0, %0, c9, c12, 1" + : "=r"(cnten_val)); + /* Disable all the counters that were enabled */ + asm volatile("mcr p15, 0, %0, c9, c12, 2" + : : "r"(cnten_val)); + if (cnten_val & CC) { + /* Read value */ + asm volatile("mrc p15, 0, %0, c9, c13, 0" + : "=r"(total_ccnt)); + __entry->cctr = total_ccnt - + per_cpu(previous_ccnt, cpu); + per_cpu(previous_ccnt, cpu) = total_ccnt; + } + for (i = 0; i < NUM_L1_CTRS; i++) { + if (cnten_val & (1 << i)) { + /* Select */ + asm volatile( + "mcr p15, 0, %0, c9, c12, 5" + : : "r"(i)); + /* Read value */ + asm volatile( + "mrc p15, 0, %0, c9, c13, 2" + : "=r"(total_cnt)); + + delta_l1_cnts[i] = total_cnt - + per_cpu(previous_l1_cnts[i], cpu); + per_cpu(previous_l1_cnts[i], cpu) = + total_cnt; + } else + delta_l1_cnts[i] = 0; + } + /* Enable all the counters that were disabled */ + asm volatile("mcr p15, 0, %0, c9, c12, 1" + : : "r"(cnten_val)); + + /* L2 counters */ + /* Assign L2 counters to cores sequentially starting + * from zero. A core could have multiple L2 counters + * allocated if # L2 counters is more than the # cores + */ + cnten_val = get_l2_indirect_reg(L2PMCNTENSET); + for (i = 0; i < NUM_L2_PERCPU; i++) { + idx = cpu + (num_cores * i); + if (idx < num_l2ctrs && + (cnten_val & (1 << idx))) { + /* Disable */ + set_l2_indirect_reg(L2PMCNTENCLR, + (1 << idx)); + /* L2PMEVCNTR values go from 0x421, + * 0x431.. + * So we multiply idx by 16 to get the + * counter reg value + */ + counter_reg = (idx * 16) + + IA_L2PMXEVCNTR_BASE; + total_cnt = + get_l2_indirect_reg(counter_reg); + /* Enable */ + set_l2_indirect_reg(L2PMCNTENSET, + (1 << idx)); + delta_l2_cnts[i] = total_cnt - + per_cpu(previous_l2_cnts[i], cpu); + per_cpu(previous_l2_cnts[i], cpu) = + total_cnt; + } else + delta_l2_cnts[i] = 0; + } + __entry->ctr0 = delta_l1_cnts[0]; + __entry->ctr1 = delta_l1_cnts[1]; + __entry->ctr2 = delta_l1_cnts[2]; + __entry->ctr3 = delta_l1_cnts[3]; + __entry->lctr0 = delta_l2_cnts[0]; + __entry->lctr1 = delta_l2_cnts[1]; + ), + + TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, L2CTR0: %u, L2CTR1: %u", + __entry->old_pid, __entry->new_pid, + __entry->cctr, __entry->ctr0, __entry->ctr1, + __entry->ctr2, __entry->ctr3, + __entry->lctr0, __entry->lctr1) +); + +#endif +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../arch/arm/mach-msm +#define TRACE_INCLUDE_FILE perf_trace_counters +#include <trace/define_trace.h> diff --git a/arch/arm/mach-msm/perfmap.c b/arch/arm/mach-msm/perfmap.c new file mode 100644 index 000000000000..244716a0fc0e --- /dev/null +++ b/arch/arm/mach-msm/perfmap.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2013, 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. + */ + +/* Character device driver for memory mapped performance counter interface */ +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/cpu_pm.h> +#include <linux/cpu.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/debugfs.h> +#include <linux/sched.h> +#include <linux/cdev.h> + +uint32_t perfmap_base; +uint32_t PERF_BASE_SIZE; + + +static dev_t perfmap_dev; +static struct cdev perfmap_cdev; +static struct class *perfmap_devclass; + +static struct of_device_id perfmap_of_device_ids[] = { + {.compatible = "qcom,perfmap"}, + {}, +}; + +static int perfmap_device_probe(struct platform_device *pdev) +{ + struct resource *resource; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!resource) + return -EINVAL; + perfmap_base = resource->start; + + return 0; +} + +static struct platform_driver perfmap_pmu_driver = { + .driver = { + .name = "perfmap", + .of_match_table = perfmap_of_device_ids, + }, + .probe = perfmap_device_probe, +}; + +static int perfmap_mmap(struct file *filep, struct vm_area_struct *vma) +{ + int ret = 0; + unsigned long pfn_num; + + pfn_num = perfmap_base>>PAGE_SHIFT; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (remap_pfn_range(vma, vma->vm_start, pfn_num, + vma->vm_end-vma->vm_start, + vma->vm_page_prot)) { + return -EAGAIN; + } + return ret; +} + +static const struct file_operations perfmap_fops = { + .mmap = perfmap_mmap, +}; + +static int perfmap_init(void) +{ + int result = 0; + + platform_driver_register(&perfmap_pmu_driver); + if (alloc_chrdev_region(&perfmap_dev, 0, 1, "perfmap") < 0) { + pr_err("perfmap: Error in alloc_chrdev_region\n"); + goto alloc_err; + } + perfmap_devclass = class_create(THIS_MODULE, "chardrv"); + if (IS_ERR(perfmap_devclass)) { + pr_err("perfmap: Error in class_create\n"); + goto class_err; + } + if (device_create(perfmap_devclass, NULL, perfmap_dev, NULL, + "perfmap0") == NULL) { + pr_err("perfmap: Error in device_create\n"); + goto create_err; + } + cdev_init(&perfmap_cdev, &perfmap_fops); + if (cdev_add(&perfmap_cdev, perfmap_dev, 1) == -1) { + pr_err("perfmap: Error in cdev_add\n"); + goto add_err; + } + return result; +add_err: + device_destroy(perfmap_devclass, perfmap_dev); +create_err: + class_destroy(perfmap_devclass); +class_err: + unregister_chrdev_region(perfmap_dev, 1); +alloc_err: + result = -ENODEV; + return result; +} + +static void perfmap_exit(void) +{ + cdev_del(&perfmap_cdev); + device_destroy(perfmap_devclass, perfmap_dev); + class_destroy(perfmap_devclass); + unregister_chrdev_region(perfmap_dev, 1); + platform_driver_unregister(&perfmap_pmu_driver); +} + +module_init(perfmap_init); +module_exit(perfmap_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c new file mode 100644 index 000000000000..af66b8e860b4 --- /dev/null +++ b/arch/arm/mach-msm/platsmp.c @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * Copyright (c) 2010-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 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/regulator/krait-regulator.h> +// AGSTUB +//#include <soc/qcom/spm.h> +#include <soc/qcom/pm.h> +#include <soc/qcom/scm-boot.h> + +#include <asm/cacheflush.h> +#include <asm/cputype.h> +#include <asm/mach-types.h> +#include <asm/smp_plat.h> + +#include <soc/qcom/socinfo.h> +#include <mach/hardware.h> +#include <mach/msm_iomap.h> + +#include "platsmp.h" + +#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0 +#define SCSS_CPU1CORE_RESET 0xD80 +#define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 +#define MSM8960_SAW2_BASE_ADDR 0x02089000 +#define MSM8962_SAW2_BASE_ADDR 0xF9089000 +#define APCS_ALIAS0_BASE_ADDR 0xF9088000 + +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +void __cpuinit write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + +static DEFINE_SPINLOCK(boot_lock); + +void __cpuinit msm_secondary_init(unsigned int cpu) +{ + WARN_ON(msm_platform_secondary_init(cpu)); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + write_pen_release(-1); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static int __cpuinit release_secondary_sim(unsigned long base, unsigned int cpu) +{ + void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K); + if (!base_ptr) + return -ENODEV; + + writel_relaxed(0x800, base_ptr+0x04); + writel_relaxed(0x3FFF, base_ptr+0x14); + + mb(); + iounmap(base_ptr); + return 0; +} + +static int __cpuinit scorpion_release_secondary(void) +{ + void *base_ptr = ioremap_nocache(0x00902000, SZ_4K*2); + if (!base_ptr) + return -EINVAL; + + writel_relaxed(0, base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL); + dmb(); + writel_relaxed(0, base_ptr + SCSS_CPU1CORE_RESET); + writel_relaxed(3, base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP); + mb(); + iounmap(base_ptr); + + return 0; +} + +static int __cpuinit msm8960_release_secondary(unsigned long base, + unsigned int cpu) +{ + void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K); + if (!base_ptr) + return -ENODEV; + +// AGSTUB +// msm_spm_turn_on_cpu_rail(MSM8960_SAW2_BASE_ADDR, cpu); + + writel_relaxed(0x109, base_ptr+0x04); + writel_relaxed(0x101, base_ptr+0x04); + mb(); + ndelay(300); + + writel_relaxed(0x121, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x120, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x100, base_ptr+0x04); + mb(); + udelay(100); + + writel_relaxed(0x180, base_ptr+0x04); + mb(); + iounmap(base_ptr); + return 0; +} + +static int __cpuinit msm8974_release_secondary(unsigned long base, + unsigned int cpu) +{ + void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K); + + if (!base_ptr) + return -ENODEV; + + secondary_cpu_hs_init(base_ptr, cpu); + + writel_relaxed(0x021, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x020, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x000, base_ptr+0x04); + mb(); + + writel_relaxed(0x080, base_ptr+0x04); + mb(); + iounmap(base_ptr); + return 0; +} + +static int __cpuinit msm8962_release_secondary(unsigned long base, + unsigned int cpu) +{ + void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K); + + if (!base_ptr) + return -ENODEV; + +// AGSTUB +// msm_spm_turn_on_cpu_rail(MSM8962_SAW2_BASE_ADDR, cpu); + + writel_relaxed(0x021, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x020, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x000, base_ptr+0x04); + mb(); + + writel_relaxed(0x080, base_ptr+0x04); + mb(); + iounmap(base_ptr); + return 0; +} + +static int __cpuinit arm_release_secondary(unsigned long base, unsigned int cpu) +{ + void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K); + if (!base_ptr) + return -ENODEV; + + writel_relaxed(0x00000033, base_ptr+0x04); + mb(); + + writel_relaxed(0x10000001, base_ptr+0x14); + mb(); + udelay(2); + + writel_relaxed(0x00000031, base_ptr+0x04); + mb(); + + writel_relaxed(0x00000039, base_ptr+0x04); + mb(); + udelay(2); + + writel_relaxed(0x00020038, base_ptr+0x04); + mb(); + udelay(2); + + + writel_relaxed(0x00020008, base_ptr+0x04); + mb(); + + writel_relaxed(0x00020088, base_ptr+0x04); + mb(); + + iounmap(base_ptr); + return 0; +} + +static int __cpuinit release_from_pen(unsigned int cpu) +{ + unsigned long timeout; + + /* Set preset_lpj to avoid subsequent lpj recalculations */ + preset_lpj = loops_per_jiffy; + + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + write_pen_release(cpu_logical_map(cpu)); + + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +DEFINE_PER_CPU(int, cold_boot_done); + +int __cpuinit scorpion_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + scorpion_release_secondary(); + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +int __cpuinit msm8960_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + msm8960_release_secondary(0x02088000, cpu); + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +int __cpuinit msm8974_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + if (of_board_is_sim()) + release_secondary_sim(APCS_ALIAS0_BASE_ADDR, cpu); + else if (!of_board_is_rumi()) + msm8974_release_secondary(APCS_ALIAS0_BASE_ADDR, cpu); + + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +int __cpuinit msm8962_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + if (of_board_is_sim()) + release_secondary_sim(APCS_ALIAS0_BASE_ADDR, cpu); + else if (!of_board_is_rumi()) + msm8962_release_secondary(APCS_ALIAS0_BASE_ADDR, cpu); + + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +static int __cpuinit msm8916_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + if (of_board_is_sim()) + release_secondary_sim(0xb088000, cpu); + else if (!of_board_is_rumi()) + arm_release_secondary(0xb088000, cpu); + + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +static int __cpuinit msm8936_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + u32 mpidr = cpu_logical_map(cpu); + u32 apcs_base = MPIDR_AFFINITY_LEVEL(mpidr, 1) ? + 0xb088000 : 0xb188000; + if (of_board_is_sim()) + release_secondary_sim(apcs_base, + MPIDR_AFFINITY_LEVEL(mpidr, 0)); + else if (!of_board_is_rumi()) + arm_release_secondary(apcs_base, + MPIDR_AFFINITY_LEVEL(mpidr, 0)); + + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +int __cpuinit arm_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + pr_debug("Starting secondary CPU %d\n", cpu); + + if (per_cpu(cold_boot_done, cpu) == false) { + if (of_board_is_sim()) + release_secondary_sim(APCS_ALIAS0_BASE_ADDR, cpu); + else if (!of_board_is_rumi()) + arm_release_secondary(APCS_ALIAS0_BASE_ADDR, cpu); + + per_cpu(cold_boot_done, cpu) = true; + } + return release_from_pen(cpu); +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +static void __init msm_smp_init_cpus(void) +{ + unsigned int i, ncores = get_core_count(); + + if (ncores > nr_cpu_ids) { + pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", + ncores, nr_cpu_ids); + ncores = nr_cpu_ids; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +static void __init arm_smp_init_cpus(void) +{ + unsigned int i, ncores; + + ncores = (__raw_readl(MSM_APCS_GCC_BASE + 0x30)) & 0xF; + + if (ncores > nr_cpu_ids) { + pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", + ncores, nr_cpu_ids); + ncores = nr_cpu_ids; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +static int cold_boot_flags[] __initdata = { + 0, + SCM_FLAG_COLDBOOT_CPU1, + SCM_FLAG_COLDBOOT_CPU2, + SCM_FLAG_COLDBOOT_CPU3, +}; + +static void __init msm_platform_smp_prepare_cpus_mc(unsigned int max_cpus) +{ + int cpu, map; + u32 aff0_mask = 0; + u32 aff1_mask = 0; + u32 aff2_mask = 0; + + for_each_present_cpu(cpu) { + map = cpu_logical_map(cpu); + aff0_mask |= BIT(MPIDR_AFFINITY_LEVEL(map, 0)); + aff1_mask |= BIT(MPIDR_AFFINITY_LEVEL(map, 1)); + aff2_mask |= BIT(MPIDR_AFFINITY_LEVEL(map, 2)); + } + + if (scm_set_boot_addr_mc(virt_to_phys(msm_secondary_startup), + aff0_mask, aff1_mask, aff2_mask, SCM_FLAG_COLDBOOT_MC)) + pr_warn("Failed to set CPU boot address\n"); +} + +static void __init msm_platform_smp_prepare_cpus(unsigned int max_cpus) +{ + int cpu, map; + unsigned int flags = 0; + + if (scm_is_mc_boot_available()) + return msm_platform_smp_prepare_cpus_mc(max_cpus); + + for_each_present_cpu(cpu) { + map = cpu_logical_map(cpu); + if (map > ARRAY_SIZE(cold_boot_flags)) { + set_cpu_present(cpu, false); + __WARN(); + continue; + } + flags |= cold_boot_flags[map]; + } + + if (scm_set_boot_addr(virt_to_phys(msm_secondary_startup), flags)) + pr_warn("Failed to set CPU boot address\n"); +} + +struct smp_operations arm_smp_ops __initdata = { + .smp_init_cpus = arm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = arm_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; + +struct smp_operations msm8916_smp_ops __initdata = { + .smp_init_cpus = arm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm8916_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; + +struct smp_operations msm8936_smp_ops __initdata = { + .smp_init_cpus = arm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm8936_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; + +struct smp_operations msm8974_smp_ops __initdata = { + .smp_init_cpus = msm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm8974_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; + +struct smp_operations msm8962_smp_ops __initdata = { + .smp_init_cpus = msm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm8962_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; + +struct smp_operations msm8960_smp_ops __initdata = { + .smp_init_cpus = msm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm8960_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; + +struct smp_operations scorpion_smp_ops __initdata = { + .smp_init_cpus = msm_smp_init_cpus, + .smp_prepare_cpus = msm_platform_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = scorpion_boot_secondary, +#ifdef CONFIG_HOTPLUG + .cpu_die = msm_cpu_die, + .cpu_kill = msm_cpu_kill, +#endif +}; diff --git a/arch/arm/mach-msm/platsmp.h b/arch/arm/mach-msm/platsmp.h new file mode 100644 index 000000000000..c321069a5c9c --- /dev/null +++ b/arch/arm/mach-msm/platsmp.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2012-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. + */ + +void msm_secondary_startup(void); +void write_pen_release(int val); + +void msm_cpu_die(unsigned int cpu); +int msm_cpu_kill(unsigned int cpu); + +extern struct smp_operations arm_smp_ops; +extern struct smp_operations msm8960_smp_ops; +extern struct smp_operations msm8974_smp_ops; +extern struct smp_operations msm8962_smp_ops; +extern struct smp_operations msm8625_smp_ops; +extern struct smp_operations scorpion_smp_ops; +extern struct smp_operations msm8916_smp_ops; +extern struct smp_operations msm8936_smp_ops; diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h new file mode 100644 index 000000000000..722a4ff79697 --- /dev/null +++ b/arch/arm/mach-msm/rpm_resources.h @@ -0,0 +1,263 @@ +/* Copyright (c) 2010-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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H +#define __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H + +#include <mach/rpm.h> +#include <linux/notifier.h> +#include <soc/qcom/pm.h> +#include "test-lpm.h" + +enum { + MSM_RPMRS_ID_PXO_CLK = 0, + MSM_RPMRS_ID_L2_CACHE_CTL = 1, + MSM_RPMRS_ID_VDD_DIG_0 = 2, + MSM_RPMRS_ID_VDD_DIG_1 = 3, + MSM_RPMRS_ID_VDD_MEM_0 = 4, + MSM_RPMRS_ID_VDD_MEM_1 = 5, + MSM_RPMRS_ID_RPM_CTL = 6, + MSM_RPMRS_ID_LAST, +}; + +enum { + MSM_RPMRS_PXO_OFF = 0, + MSM_RPMRS_PXO_ON = 1, +}; + +enum { + MSM_RPMRS_L2_CACHE_HSFS_OPEN = 0, + MSM_RPMRS_L2_CACHE_GDHS = 1, + MSM_RPMRS_L2_CACHE_RETENTION = 2, + MSM_RPMRS_L2_CACHE_ACTIVE = 3, +}; + +enum { + MSM_RPMRS_MASK_RPM_CTL_CPU_HALT = 1, + MSM_RPMRS_MASK_RPM_CTL_MULTI_TIER = 2, +}; + +enum { + MSM_RPMRS_VDD_MEM_RET_LOW = 0, + MSM_RPMRS_VDD_MEM_RET_HIGH = 1, + MSM_RPMRS_VDD_MEM_ACTIVE = 2, + MSM_RPMRS_VDD_MEM_MAX = 3, + MSM_RPMRS_VDD_MEM_LAST, +}; + +enum { + MSM_RPMRS_VDD_DIG_RET_LOW = 0, + MSM_RPMRS_VDD_DIG_RET_HIGH = 1, + MSM_RPMRS_VDD_DIG_ACTIVE = 2, + MSM_RPMRS_VDD_DIG_MAX = 3, + MSM_RPMRS_VDD_DIG_LAST, +}; + +#define MSM_RPMRS_LIMITS(_pxo, _l2, _vdd_upper_b, _vdd) { \ + MSM_RPMRS_PXO_##_pxo, \ + MSM_RPMRS_L2_CACHE_##_l2, \ + MSM_RPMRS_VDD_MEM_##_vdd_upper_b, \ + MSM_RPMRS_VDD_MEM_##_vdd, \ + MSM_RPMRS_VDD_DIG_##_vdd_upper_b, \ + MSM_RPMRS_VDD_DIG_##_vdd, \ + {0}, {0}, \ +} + +struct msm_rpmrs_limits { + uint32_t pxo; + uint32_t l2_cache; + uint32_t vdd_mem_upper_bound; + uint32_t vdd_mem; + uint32_t vdd_dig_upper_bound; + uint32_t vdd_dig; + + uint32_t latency_us[NR_CPUS]; + uint32_t power[NR_CPUS]; +}; + +struct msm_rpmrs_level { + enum msm_pm_sleep_mode sleep_mode; + struct msm_rpmrs_limits rs_limits; + bool available; + uint32_t latency_us; + uint32_t steady_state_power; + uint32_t energy_overhead; + uint32_t time_overhead_us; +}; + +struct msm_rpmrs_platform_data { + struct msm_rpmrs_level *levels; + unsigned int num_levels; + unsigned int vdd_mem_levels[MSM_RPMRS_VDD_MEM_LAST]; + unsigned int vdd_dig_levels[MSM_RPMRS_VDD_DIG_LAST]; + unsigned int vdd_mask; + unsigned int rpmrs_target_id[MSM_RPMRS_ID_LAST]; +}; + +enum { + MSM_LPM_STATE_ENTER = 0, + MSM_LPM_STATE_EXIT = 1, +}; + +/** + * struct msm_lpm_sleep_data - abstraction to get sleep data + * @limits: pointer to the msm_rpmrs_limits structure + * @kernel_sleep: kernel sleep time as decided by the power calculation + * algorithm + * + * This structure is an abstraction to get the limits and kernel sleep time + * during enter sleep. + */ + +struct msm_lpm_sleep_data { + struct msm_rpmrs_limits *limits; + uint32_t kernel_sleep; +}; + +#define MSM_PM(field) MSM_RPMRS_##field + +/** + * msm_pm_get_pxo() - get the limits for pxo + * @limits: pointer to the msm_rpmrs_limits structure + * + * This function gets the limits to the resource pxo on + * 8960 + */ + +uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits); + +/** + * msm_pm_get_l2_cache() - get the limits for l2 cache + * @limits: pointer to the msm_rpmrs_limits structure + * + * This function gets the limits to the resource l2 cache + * on 8960 + */ + +uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits); + +/** + * msm_pm_get_vdd_mem() - get the limits for pxo + * @limits: pointer to the msm_rpmrs_limits structure + * + * This function gets the limits to the resource vdd mem + * on 8960 + */ + +uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits); + +/** + * msm_pm_get_vdd_dig() - get the limits for vdd dig + * @limits: pointer to the msm_rpmrs_limits structure + * + * This function gets the limits to the resource vdd dig + * on 8960 + */ + +uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits); + +/** + * msm_lpm_register_notifier() - register for notifications + * @cpu: cpu to debug + * @level_iter: low power level index to debug + * @nb: notifier block to callback on notifications + * @is_latency_measure: is it latency measure + * + * This function sets the permitted level to the index of the + * level under test and registers notifier for callback. + */ + +int msm_lpm_register_notifier(int cpu, int level_iter, + struct notifier_block *nb, bool is_latency_measure); + +/** + * msm_lpm_unregister_notifier() - unregister from notifications + * @cpu: cpu to debug + * @nb: notifier block to callback on notifications + * + * This function sets the permitted level to a value one more than + * available levels count which indicates that all levels are + * permitted and it also unregisters notifier for callback. + */ + +int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb); + + +static inline int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpmrs_set_noirq(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpmrs_set_bits_noirq(int ctx, struct msm_rpm_iv_pair *req, + int count, int *mask) +{ + return -ENODEV; +} + +static inline int msm_rpmrs_set_nosleep( + int ctx, struct msm_rpm_iv_pair *req, int count) +{ + return -ENODEV; +} + +static inline int msm_rpmrs_clear(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpmrs_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, + int count) +{ + return -ENODEV; +} + +static inline int msm_rpmrs_clear_nosleep( + int ctx, struct msm_rpm_iv_pair *req, int count) +{ + return -ENODEV; +} + +static inline struct msm_rpmrs_limits *msm_rpmrs_lowest_limits( + bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us, + uint32_t sleep_us) +{ + return NULL; +} + +static inline int msm_rpmrs_enter_sleep(uint32_t sclk_count, + struct msm_rpmrs_limits *limits, bool from_idle, bool notify_rpm) +{ + return -ENODEV; +} + +static inline void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, + bool from_idle, bool notify_rpm, bool collapsed) +{ + return; +} + +static inline int msm_rpmrs_levels_init(struct msm_rpmrs_platform_data *data) +{ + return -ENODEV; +} + + +#endif /* __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H */ diff --git a/arch/arm/mach-msm/scm-xpu.c b/arch/arm/mach-msm/scm-xpu.c new file mode 100644 index 000000000000..e05c7b371cdd --- /dev/null +++ b/arch/arm/mach-msm/scm-xpu.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2013, 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 <linux/init.h> +#include <linux/kernel.h> +#include <soc/qcom/scm.h> + + +#define ERR_FATAL_ENABLE 0x0 +#define ERR_FATAL_DISABLE 0x1 +#define ERR_FATAL_READ 0x2 +#define XPU_ERR_FATAL 0xe + +static int __init xpu_err_fatal_init(void) +{ + int ret, response; + struct { + unsigned int config; + unsigned int spare; + } cmd; + cmd.config = ERR_FATAL_ENABLE; + cmd.spare = 0; + + ret = scm_call(SCM_SVC_MP, XPU_ERR_FATAL, &cmd, sizeof(cmd), &response, + sizeof(response)); + + if (ret != 0) + pr_warn("Failed to set XPU violations as fatal errors: %d\n", + ret); + else + pr_info("Configuring XPU violations to be fatal errors\n"); + + return ret; +} +early_initcall(xpu_err_fatal_init); diff --git a/arch/arm/mach-msm/smcmod.c b/arch/arm/mach-msm/smcmod.c new file mode 100644 index 000000000000..554b9f2880b9 --- /dev/null +++ b/arch/arm/mach-msm/smcmod.c @@ -0,0 +1,831 @@ +/* Copyright (c) 2012-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. + * + */ + +#define KMSG_COMPONENT "SMCMOD" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/miscdevice.h> +#include <linux/mutex.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/printk.h> +#include <linux/msm_ion.h> +#include <soc/qcom/scm.h> +#include <soc/qcom/socinfo.h> + +#include <asm/smcmod.h> + +static DEFINE_MUTEX(ioctl_lock); + +#define SMCMOD_SVC_DEFAULT (0) +#define SMCMOD_SVC_CRYPTO (1) +#define SMCMOD_CRYPTO_CMD_CIPHER (1) +#define SMCMOD_CRYPTO_CMD_MSG_DIGEST_FIXED (2) +#define SMCMOD_CRYPTO_CMD_MSG_DIGEST (3) + +/** + * struct smcmod_cipher_scm_req - structure for sending the cipher cmd to + * scm_call. + * + * @algorithm - specifies cipher algorithm + * @operation - specifies encryption or decryption. + * @mode - specifies cipher mode. + * @key_phys_addr - physical address for key buffer. + * @key_size - key size in bytes. + * @plain_text_phys_addr - physical address for plain text buffer. + * @plain_text_size - size of plain text in bytes. + * @cipher_text_phys_addr - physical address for cipher text buffer. + * @cipher_text_size - cipher text size in bytes. + * @init_vector_phys_addr - physical address for init vector buffer. + * @init_vector_size - size of initialization vector in bytes. + */ +struct smcmod_cipher_scm_req { + uint32_t algorithm; + uint32_t operation; + uint32_t mode; + uint32_t key_phys_addr; + uint32_t key_size; + uint32_t plain_text_phys_addr; + uint32_t plain_text_size; + uint32_t cipher_text_phys_addr; + uint32_t cipher_text_size; + uint32_t init_vector_phys_addr; + uint32_t init_vector_size; +}; + +/** + * struct smcmod_msg_digest_scm_req - structure for sending message digest + * to scm_call. + * + * @algorithm - specifies the cipher algorithm. + * @key_phys_addr - physical address of key buffer. + * @key_size - hash key size in bytes. + * @input_phys_addr - physical address of input buffer. + * @input_size - input data size in bytes. + * @output_phys_addr - physical address of output buffer. + * @output_size - size of output buffer in bytes. + * @verify - indicates whether to verify the hash value. + */ +struct smcmod_msg_digest_scm_req { + uint32_t algorithm; + uint32_t key_phys_addr; + uint32_t key_size; + uint32_t input_phys_addr; + uint32_t input_size; + uint32_t output_phys_addr; + uint32_t output_size; + uint8_t verify; +} __packed; + +static int smcmod_ion_fd_to_phys(int32_t fd, struct ion_client *ion_clientp, + struct ion_handle **ion_handlep, uint32_t *phys_addrp, size_t *sizep) +{ + int ret = 0; + + /* sanity check args */ + if ((fd < 0) || IS_ERR_OR_NULL(ion_clientp) || + IS_ERR_OR_NULL(ion_handlep) || IS_ERR_OR_NULL(phys_addrp) || + IS_ERR_OR_NULL(sizep)) + return -EINVAL; + + /* import the buffer fd */ + *ion_handlep = ion_import_dma_buf(ion_clientp, fd); + + /* sanity check the handle */ + if (IS_ERR_OR_NULL(*ion_handlep)) + return -EINVAL; + + /* get the physical address */ + ret = ion_phys(ion_clientp, *ion_handlep, (ion_phys_addr_t *)phys_addrp, + sizep); + + return ret; +} + +static int smcmod_send_buf_cmd(struct smcmod_buf_req *reqp) +{ + int ret = 0; + struct ion_client *ion_clientp = NULL; + struct ion_handle *ion_cmd_handlep = NULL; + struct ion_handle *ion_resp_handlep = NULL; + void *cmd_vaddrp = NULL; + void *resp_vaddrp = NULL; + unsigned long cmd_buf_size = 0; + unsigned long resp_buf_size = 0; + + /* sanity check the argument */ + if (IS_ERR_OR_NULL(reqp)) + return -EINVAL; + + /* sanity check the fds */ + if (reqp->ion_cmd_fd < 0) + return -EINVAL; + + /* create an ion client */ + ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod"); + + /* check for errors */ + if (IS_ERR_OR_NULL(ion_clientp)) + return -EINVAL; + + /* import the command buffer fd */ + ion_cmd_handlep = ion_import_dma_buf(ion_clientp, reqp->ion_cmd_fd); + + /* sanity check the handle */ + if (IS_ERR_OR_NULL(ion_cmd_handlep)) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* retrieve the size of the buffer */ + if (ion_handle_get_size(ion_clientp, ion_cmd_handlep, + &cmd_buf_size) < 0) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* ensure that the command buffer size is not + * greater than the size of the buffer. + */ + if (reqp->cmd_len > cmd_buf_size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* map the area to get a virtual address */ + cmd_vaddrp = ion_map_kernel(ion_clientp, ion_cmd_handlep); + + /* sanity check the address */ + if (IS_ERR_OR_NULL(cmd_vaddrp)) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* check if there is a response buffer */ + if (reqp->ion_resp_fd >= 0) { + /* import the handle */ + ion_resp_handlep = + ion_import_dma_buf(ion_clientp, reqp->ion_resp_fd); + + /* sanity check the handle */ + if (IS_ERR_OR_NULL(ion_resp_handlep)) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* retrieve the size of the buffer */ + if (ion_handle_get_size(ion_clientp, ion_resp_handlep, + &resp_buf_size) < 0) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* ensure that the command buffer size is not + * greater than the size of the buffer. + */ + if (reqp->resp_len > resp_buf_size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* map the area to get a virtual address */ + resp_vaddrp = ion_map_kernel(ion_clientp, ion_resp_handlep); + + /* sanity check the address */ + if (IS_ERR_OR_NULL(resp_vaddrp)) { + ret = -EINVAL; + goto buf_cleanup; + } + } + + /* No need to flush the cache lines for the command buffer here, + * because the buffer will be flushed by scm_call. + */ + + /* call scm function to switch to secure world */ + reqp->return_val = scm_call(reqp->service_id, reqp->command_id, + cmd_vaddrp, reqp->cmd_len, resp_vaddrp, reqp->resp_len); + + /* The cache lines for the response buffer have already been + * invalidated by scm_call before returning. + */ + +buf_cleanup: + /* if the client and handle(s) are valid, free them */ + if (!IS_ERR_OR_NULL(ion_clientp)) { + if (!IS_ERR_OR_NULL(ion_cmd_handlep)) { + if (!IS_ERR_OR_NULL(cmd_vaddrp)) + ion_unmap_kernel(ion_clientp, ion_cmd_handlep); + ion_free(ion_clientp, ion_cmd_handlep); + } + + if (!IS_ERR_OR_NULL(ion_resp_handlep)) { + if (!IS_ERR_OR_NULL(resp_vaddrp)) + ion_unmap_kernel(ion_clientp, ion_resp_handlep); + ion_free(ion_clientp, ion_resp_handlep); + } + + ion_client_destroy(ion_clientp); + } + + return ret; +} + +static int smcmod_send_cipher_cmd(struct smcmod_cipher_req *reqp) +{ + int ret = 0; + struct smcmod_cipher_scm_req scm_req; + struct ion_client *ion_clientp = NULL; + struct ion_handle *ion_key_handlep = NULL; + struct ion_handle *ion_plain_handlep = NULL; + struct ion_handle *ion_cipher_handlep = NULL; + struct ion_handle *ion_iv_handlep = NULL; + size_t size = 0; + + if (IS_ERR_OR_NULL(reqp)) + return -EINVAL; + + /* sanity check the fds */ + if ((reqp->ion_plain_text_fd < 0) || + (reqp->ion_cipher_text_fd < 0) || + (reqp->ion_init_vector_fd < 0)) + return -EINVAL; + + /* create an ion client */ + ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod"); + + /* check for errors */ + if (IS_ERR_OR_NULL(ion_clientp)) + return -EINVAL; + + /* fill in the scm request structure */ + scm_req.algorithm = reqp->algorithm; + scm_req.operation = reqp->operation; + scm_req.mode = reqp->mode; + scm_req.key_phys_addr = 0; + scm_req.key_size = reqp->key_size; + scm_req.plain_text_size = reqp->plain_text_size; + scm_req.cipher_text_size = reqp->cipher_text_size; + scm_req.init_vector_size = reqp->init_vector_size; + + if (!reqp->key_is_null) { + /* import the key buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_key_fd, ion_clientp, + &ion_key_handlep, &scm_req.key_phys_addr, &size); + if (ret < 0) + goto buf_cleanup; + + /* ensure that the key size is not + * greater than the size of the buffer. + */ + if (reqp->key_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + } + + /* import the plain text buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_plain_text_fd, ion_clientp, + &ion_plain_handlep, &scm_req.plain_text_phys_addr, &size); + + if (ret < 0) + goto buf_cleanup; + + /* ensure that the plain text size is not + * greater than the size of the buffer. + */ + if (reqp->plain_text_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* import the cipher text buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_cipher_text_fd, ion_clientp, + &ion_cipher_handlep, &scm_req.cipher_text_phys_addr, &size); + if (ret < 0) + goto buf_cleanup; + + /* ensure that the cipher text size is not + * greater than the size of the buffer. + */ + if (reqp->cipher_text_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* import the init vector buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_init_vector_fd, ion_clientp, + &ion_iv_handlep, &scm_req.init_vector_phys_addr, &size); + if (ret < 0) + goto buf_cleanup; + + /* ensure that the init vector size is not + * greater than the size of the buffer. + */ + if (reqp->init_vector_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* Only the scm_req structure will be flushed by scm_call, + * so we must flush the cache for the input ion buffers here. + */ + msm_ion_do_cache_op(ion_clientp, ion_key_handlep, NULL, + scm_req.key_size, ION_IOC_CLEAN_CACHES); + msm_ion_do_cache_op(ion_clientp, ion_iv_handlep, NULL, + scm_req.init_vector_size, ION_IOC_CLEAN_CACHES); + + /* For decrypt, cipher text is input, otherwise it's plain text. */ + if (reqp->operation) + msm_ion_do_cache_op(ion_clientp, ion_cipher_handlep, NULL, + scm_req.cipher_text_size, ION_IOC_CLEAN_CACHES); + else + msm_ion_do_cache_op(ion_clientp, ion_plain_handlep, NULL, + scm_req.plain_text_size, ION_IOC_CLEAN_CACHES); + + /* call scm function to switch to secure world */ + reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO, + SMCMOD_CRYPTO_CMD_CIPHER, &scm_req, + sizeof(scm_req), NULL, 0); + + /* Invalidate the output buffer, since it's not done by scm_call */ + + /* for decrypt, plain text is the output, otherwise it's cipher text */ + if (reqp->operation) + msm_ion_do_cache_op(ion_clientp, ion_plain_handlep, NULL, + scm_req.plain_text_size, ION_IOC_INV_CACHES); + else + msm_ion_do_cache_op(ion_clientp, ion_cipher_handlep, NULL, + scm_req.cipher_text_size, ION_IOC_INV_CACHES); + +buf_cleanup: + /* if the client and handles are valid, free them */ + if (!IS_ERR_OR_NULL(ion_clientp)) { + if (!IS_ERR_OR_NULL(ion_key_handlep)) + ion_free(ion_clientp, ion_key_handlep); + + if (!IS_ERR_OR_NULL(ion_plain_handlep)) + ion_free(ion_clientp, ion_plain_handlep); + + if (!IS_ERR_OR_NULL(ion_cipher_handlep)) + ion_free(ion_clientp, ion_cipher_handlep); + + if (!IS_ERR_OR_NULL(ion_iv_handlep)) + ion_free(ion_clientp, ion_iv_handlep); + + ion_client_destroy(ion_clientp); + } + + return ret; +} +static int smcmod_send_msg_digest_cmd(struct smcmod_msg_digest_req *reqp) +{ + int ret = 0; + struct smcmod_msg_digest_scm_req scm_req; + struct ion_client *ion_clientp = NULL; + struct ion_handle *ion_key_handlep = NULL; + struct ion_handle *ion_input_handlep = NULL; + struct ion_handle *ion_output_handlep = NULL; + size_t size = 0; + + if (IS_ERR_OR_NULL(reqp)) + return -EINVAL; + + /* sanity check the fds */ + if ((reqp->ion_input_fd < 0) || (reqp->ion_output_fd < 0)) + return -EINVAL; + + /* create an ion client */ + ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod"); + + /* check for errors */ + if (IS_ERR_OR_NULL(ion_clientp)) + return -EINVAL; + + /* fill in the scm request structure */ + scm_req.algorithm = reqp->algorithm; + scm_req.key_phys_addr = 0; + scm_req.key_size = reqp->key_size; + scm_req.input_size = reqp->input_size; + scm_req.output_size = reqp->output_size; + scm_req.verify = 0; + + if (!reqp->key_is_null) { + /* import the key buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_key_fd, ion_clientp, + &ion_key_handlep, &scm_req.key_phys_addr, &size); + if (ret < 0) + goto buf_cleanup; + + /* ensure that the key size is not + * greater than the size of the buffer. + */ + if (reqp->key_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + } + + /* import the input buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_input_fd, ion_clientp, + &ion_input_handlep, &scm_req.input_phys_addr, &size); + if (ret < 0) + goto buf_cleanup; + + /* ensure that the input size is not + * greater than the size of the buffer. + */ + if (reqp->input_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* import the output buffer and get the physical address */ + ret = smcmod_ion_fd_to_phys(reqp->ion_output_fd, ion_clientp, + &ion_output_handlep, &scm_req.output_phys_addr, &size); + if (ret < 0) + goto buf_cleanup; + + /* ensure that the output size is not + * greater than the size of the buffer. + */ + if (reqp->output_size > size) { + ret = -EINVAL; + goto buf_cleanup; + } + + /* Only the scm_req structure will be flushed by scm_call, + * so we must flush the cache for the input ion buffers here. + */ + msm_ion_do_cache_op(ion_clientp, ion_key_handlep, NULL, + scm_req.key_size, ION_IOC_CLEAN_CACHES); + msm_ion_do_cache_op(ion_clientp, ion_input_handlep, NULL, + scm_req.input_size, ION_IOC_CLEAN_CACHES); + + /* call scm function to switch to secure world */ + if (reqp->fixed_block) + reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO, + SMCMOD_CRYPTO_CMD_MSG_DIGEST_FIXED, + &scm_req, + sizeof(scm_req), + NULL, 0); + else + reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO, + SMCMOD_CRYPTO_CMD_MSG_DIGEST, + &scm_req, + sizeof(scm_req), + NULL, 0); + + /* Invalidate the output buffer, since it's not done by scm_call */ + msm_ion_do_cache_op(ion_clientp, ion_output_handlep, NULL, + scm_req.output_size, ION_IOC_INV_CACHES); + +buf_cleanup: + /* if the client and handles are valid, free them */ + if (!IS_ERR_OR_NULL(ion_clientp)) { + if (!IS_ERR_OR_NULL(ion_key_handlep)) + ion_free(ion_clientp, ion_key_handlep); + + if (!IS_ERR_OR_NULL(ion_input_handlep)) + ion_free(ion_clientp, ion_input_handlep); + + if (!IS_ERR_OR_NULL(ion_output_handlep)) + ion_free(ion_clientp, ion_output_handlep); + + ion_client_destroy(ion_clientp); + } + + return ret; +} + +static int smcmod_send_dec_cmd(struct smcmod_decrypt_req *reqp) +{ + struct ion_client *ion_clientp; + struct ion_handle *ion_handlep = NULL; + int ion_fd; + int ret; + u32 pa; + size_t size; + struct { + u32 args[4]; + } req; + struct { + u32 args[3]; + } rsp; + + ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod"); + if (IS_ERR_OR_NULL(ion_clientp)) + return PTR_ERR(ion_clientp); + + switch (reqp->operation) { + case SMCMOD_DECRYPT_REQ_OP_METADATA: { + ion_fd = reqp->request.metadata.ion_fd; + ret = smcmod_ion_fd_to_phys(ion_fd, ion_clientp, + &ion_handlep, &pa, &size); + if (ret) + goto error; + + req.args[0] = reqp->request.metadata.len; + req.args[1] = pa; + break; + } + case SMCMOD_DECRYPT_REQ_OP_IMG_FRAG: { + ion_fd = reqp->request.img_frag.ion_fd; + ret = smcmod_ion_fd_to_phys(ion_fd, ion_clientp, + &ion_handlep, &pa, &size); + if (ret) + goto error; + + req.args[0] = reqp->request.img_frag.ctx_id; + req.args[1] = reqp->request.img_frag.last_frag; + req.args[2] = reqp->request.img_frag.frag_len; + req.args[3] = pa + reqp->request.img_frag.offset; + break; + } + default: + ret = -EINVAL; + goto error; + } + + /* + * scm_call does cache maintenance over request and response buffers. + * The userspace must flush/invalidate ion input/output buffers itself. + */ + + ret = scm_call(reqp->service_id, reqp->command_id, + &req, sizeof(req), &rsp, sizeof(rsp)); + if (ret) + goto error; + + switch (reqp->operation) { + case SMCMOD_DECRYPT_REQ_OP_METADATA: + reqp->response.metadata.status = rsp.args[0]; + reqp->response.metadata.ctx_id = rsp.args[1]; + reqp->response.metadata.end_offset = rsp.args[2] - pa; + break; + case SMCMOD_DECRYPT_REQ_OP_IMG_FRAG: { + reqp->response.img_frag.status = rsp.args[0]; + break; + } + default: + break; + } + +error: + if (!IS_ERR_OR_NULL(ion_clientp)) { + if (!IS_ERR_OR_NULL(ion_handlep)) + ion_free(ion_clientp, ion_handlep); + ion_client_destroy(ion_clientp); + } + return ret; +} + +static int smcmod_ioctl_check(unsigned cmd) +{ + switch (cmd) { + case SMCMOD_IOCTL_SEND_REG_CMD: + case SMCMOD_IOCTL_SEND_BUF_CMD: + case SMCMOD_IOCTL_SEND_CIPHER_CMD: + case SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD: + case SMCMOD_IOCTL_GET_VERSION: + if (!cpu_is_fsm9xxx()) + return -EINVAL; + break; + case SMCMOD_IOCTL_SEND_DECRYPT_CMD: + if (!cpu_is_msm8226()) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static long smcmod_ioctl(struct file *file, unsigned cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int ret = 0; + + /* sanity check */ + if (!argp) + return -EINVAL; + + /* + * The SMC instruction should only be initiated by one process + * at a time, hence the critical section here. Note that this + * does not prevent user space from modifying the + * allocated buffer contents. Extra steps are needed to + * prevent that from happening. + */ + mutex_lock(&ioctl_lock); + + ret = smcmod_ioctl_check(cmd); + if (ret) + goto cleanup; + + switch (cmd) { + case SMCMOD_IOCTL_SEND_REG_CMD: + { + struct smcmod_reg_req req; + + /* copy struct from user */ + if (copy_from_user((void *)&req, argp, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + + /* call the correct scm function to switch to secure + * world + */ + if (req.num_args == 1) { + req.return_val = + scm_call_atomic1(req.service_id, + req.command_id, req.args[0]); + } else if (req.num_args == 2) { + req.return_val = + scm_call_atomic2(req.service_id, + req.command_id, req.args[0], + req.args[1]); + } else { + ret = -EINVAL; + goto cleanup; + } + + /* copy result back to user */ + if (copy_to_user(argp, (void *)&req, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + } + break; + + /* This is an example of how to pass buffers to/from the secure + * side using the ion driver. + */ + case SMCMOD_IOCTL_SEND_BUF_CMD: + { + struct smcmod_buf_req req; + + /* copy struct from user */ + if (copy_from_user((void *)&req, argp, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + + /* send the command */ + ret = smcmod_send_buf_cmd(&req); + if (ret < 0) + goto cleanup; + + /* copy result back to user */ + if (copy_to_user(argp, (void *)&req, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + } + break; + + case SMCMOD_IOCTL_SEND_CIPHER_CMD: + { + struct smcmod_cipher_req req; + + /* copy struct from user */ + if (copy_from_user((void *)&req, argp, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + + ret = smcmod_send_cipher_cmd(&req); + if (ret < 0) + goto cleanup; + + /* copy result back to user */ + if (copy_to_user(argp, (void *)&req, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + } + break; + + case SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD: + { + struct smcmod_msg_digest_req req; + + /* copy struct from user */ + if (copy_from_user((void *)&req, argp, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + + ret = smcmod_send_msg_digest_cmd(&req); + if (ret < 0) + goto cleanup; + + /* copy result back to user */ + if (copy_to_user(argp, (void *)&req, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + } + break; + + case SMCMOD_IOCTL_GET_VERSION: + { + uint32_t req; + + /* call scm function to switch to secure world */ + req = scm_get_version(); + + /* copy result back to user */ + if (copy_to_user(argp, (void *)&req, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + } + break; + + case SMCMOD_IOCTL_SEND_DECRYPT_CMD: + { + struct smcmod_decrypt_req req; + + if (copy_from_user((void *)&req, argp, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + + ret = smcmod_send_dec_cmd(&req); + if (ret < 0) + goto cleanup; + + if (copy_to_user(argp, (void *)&req, sizeof(req))) { + ret = -EFAULT; + goto cleanup; + } + } + break; + + default: + ret = -EINVAL; + } + +cleanup: + mutex_unlock(&ioctl_lock); + return ret; +} + +static int smcmod_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int smcmod_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations smcmod_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = smcmod_ioctl, + .open = smcmod_open, + .release = smcmod_release, +}; + +static struct miscdevice smcmod_misc_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = SMCMOD_DEV, + .fops = &smcmod_fops +}; + +static int __init smcmod_init(void) +{ + return misc_register(&smcmod_misc_dev); +} + +static void __exit smcmod_exit(void) +{ + misc_deregister(&smcmod_misc_dev); +} + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SMC Module"); +MODULE_LICENSE("GPL v2"); + +module_init(smcmod_init); +module_exit(smcmod_exit); diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c new file mode 100644 index 000000000000..ac38ff1d0ee0 --- /dev/null +++ b/arch/arm/mach-msm/test-lpm.c @@ -0,0 +1,692 @@ +/* Copyright (c) 2012-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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/pm.h> +#include <linux/mutex.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/ctype.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> + +#if defined(CONFIG_MSM_RPM_SMD) +#include "lpm_resources.h" +#endif +#include "timer.h" +#include "test-lpm.h" + +#define LPM_STATS_RESET "reset" +#define LPM_TEST_ALL_LEVELS "lpm" +#define LPM_TEST_LATENCIES "latency" +#define LPM_TEST_CLEAR "clear" +#define BUF_SIZE 200 +#define STAT_BUF_EXTRA_SIZE 500 +#define WAIT_FOR_XO 1 +#define COMM_BUF_SIZE 15 +#define INPUT_COUNT_BUF 10 +#define LPM_DEFAULT_CPU 0 + +#define SNPRINTF(buf, size, format, ...) \ +{ \ + if (size > 0) { \ + int ret; \ + ret = snprintf(buf, size, format, ## __VA_ARGS__); \ + if (ret > size) { \ + buf += size; \ + size = 0; \ + } else { \ + buf += ret; \ + size -= ret; \ + } \ + } \ +} \ + +static DEFINE_MUTEX(lpm_stats_mutex); + +struct lpm_level_stat { + char level_name[BUF_SIZE]; + int64_t min_time; + int64_t max_time; + int64_t avg_time; + int64_t exit_early; + int64_t count; + unsigned long min_threshold; + uint32_t kernel_sleep_time; + bool entered; +}; + +static DEFINE_PER_CPU(struct lpm_level_stat *, lpm_levels); + +static struct dentry *lpm_stat; +static struct dentry *lpm_ext_comm; +static struct msm_rpmrs_level *lpm_supp_level; +static int lpm_level_count; +static int lpm_level_iter; +static bool msm_lpm_use_qtimer; +static unsigned long lpm_sleep_time; +static bool lpm_latency_test; + +static unsigned int timer_interval = 5000; +module_param_named(lpm_timer_interval_msec, timer_interval, uint, + S_IRUGO | S_IWUSR | S_IWGRP); + +static unsigned int latency_test_interval = 50; +module_param_named(lpm_latency_timer_interval_usec, latency_test_interval, uint, + S_IRUGO | S_IWUSR | S_IWGRP); + +static unsigned int cpu_to_debug = LPM_DEFAULT_CPU; +static int lpm_cpu_update(const char *val, const struct kernel_param *kp) +{ + int ret = 0; + unsigned int debug_val; + + ret = kstrtouint(val, 10, &debug_val); + if ((ret < 0) || (debug_val >= num_possible_cpus())) + return -EINVAL; + cpu_to_debug = debug_val; + return ret; +} + +static struct kernel_param_ops cpu_debug_events = { + .set = lpm_cpu_update, +}; + +module_param_cb(cpu_to_debug, &cpu_debug_events, &cpu_to_debug, + S_IRUGO | S_IWUSR | S_IWGRP); + +static void lpm_populate_name(struct lpm_level_stat *stat, + struct msm_rpmrs_level *supp) +{ + char nm[BUF_SIZE] = {0}; + char default_buf[20]; + + switch (supp->sleep_mode) { + case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT: + strlcat(nm, "WFI ", BUF_SIZE); + break; + case MSM_PM_SLEEP_MODE_RETENTION: + strlcat(nm, "Retention ", BUF_SIZE); + break; + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE: + strlcat(nm, "Standalone Power collapse ", BUF_SIZE); + break; + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: + strlcat(nm, "Idle Power collapse ", BUF_SIZE); + break; + case MSM_PM_MODE_POWER_COLLASE_SUSPEND: + strlcat(nm, "Suspend Power collapse", BUF_SIZE); + default: + strlcat(nm, "Invalid Mode ", BUF_SIZE); + break; + } + + switch (msm_pm_get_pxo(&(supp->rs_limits))) { + case MSM_PM(PXO_OFF): + strlcat(nm, "XO: OFF ", BUF_SIZE); + break; + case MSM_PM(PXO_ON): + strlcat(nm, "XO: ON ", BUF_SIZE); + break; + default: + snprintf(default_buf, sizeof(default_buf), + "XO : %d ", msm_pm_get_pxo(&(supp->rs_limits))); + strlcat(nm, default_buf , BUF_SIZE); + break; + } + + switch (msm_pm_get_l2_cache(&(supp->rs_limits))) { + case MSM_PM(L2_CACHE_HSFS_OPEN): + strlcat(nm, "L2: HSFS ", BUF_SIZE); + break; + case MSM_PM(L2_CACHE_GDHS): + strlcat(nm, "L2: GDHS ", BUF_SIZE); + break; + case MSM_PM(L2_CACHE_RETENTION): + strlcat(nm, "L2: Retention ", BUF_SIZE); + break; + case MSM_PM(L2_CACHE_ACTIVE): + strlcat(nm, "L2: Active ", BUF_SIZE); + break; + default: + snprintf(default_buf, sizeof(default_buf), + "L2 : %d ", msm_pm_get_l2_cache(&(supp->rs_limits))); + strlcat(nm, default_buf , BUF_SIZE); + break; + } + + snprintf(default_buf, sizeof(default_buf), + "Vdd_mem : %d ", msm_pm_get_vdd_mem(&(supp->rs_limits))); + strlcat(nm, default_buf , BUF_SIZE); + + snprintf(default_buf, sizeof(default_buf), + "Vdd_dig : %d ", msm_pm_get_vdd_dig(&(supp->rs_limits))); + strlcat(nm, default_buf , BUF_SIZE); + + strlcpy(stat->level_name, nm, strnlen(nm, BUF_SIZE)); +} + +static int64_t msm_lpm_get_time(void) +{ + if (msm_lpm_use_qtimer) + return ktime_to_ns(ktime_get()); + + return msm_timer_get_sclk_time(NULL); +} + +static bool lpm_get_level(void *v, unsigned int *ct) +{ + bool ret = false; + int it; + struct msm_rpmrs_level *level_enter; + + level_enter = container_of(((struct msm_lpm_sleep_data *)v)->limits, + struct msm_rpmrs_level, rs_limits); + if (level_enter) { + for (it = 0; it < lpm_level_count; it++) + if (!memcmp(level_enter , lpm_supp_level + it, + sizeof(struct msm_rpmrs_level))) { + *ct = it; + ret = true; + break; + } + } + return ret; +} + +static int lpm_callback(struct notifier_block *self, unsigned long cmd, + void *sleep_data) +{ + static int64_t time; + unsigned int ct; + struct lpm_level_stat *stats; + stats = per_cpu(lpm_levels, cpu_to_debug); + /* Update the stats and get the start/stop time */ + if (cmd == MSM_LPM_STATE_ENTER && !lpm_latency_test) { + time = msm_lpm_get_time(); + stats[lpm_level_iter].entered = true; + } else if ((cmd == MSM_LPM_STATE_EXIT) && (time) + && (!lpm_latency_test)) { + int64_t time1; + time1 = msm_lpm_get_time(); + time = time1 - time; + + if ((time < stats[lpm_level_iter].min_time) || + (!stats[lpm_level_iter].min_time)) + stats[lpm_level_iter].min_time = time; + + if (time > stats[lpm_level_iter].max_time) + stats[lpm_level_iter].max_time = time; + + time1 = stats[lpm_level_iter].avg_time * + stats[lpm_level_iter].count + time; + do_div(time1, ++(stats[lpm_level_iter].count)); + + stats[lpm_level_iter].avg_time = time1; + do_div(time, NSEC_PER_USEC); + if (time < lpm_supp_level[lpm_level_iter]. + time_overhead_us) + stats[lpm_level_iter].exit_early++; + time = 0; + } else if (cmd == MSM_LPM_STATE_ENTER && lpm_latency_test) { + + struct msm_lpm_sleep_data *data = sleep_data; + if ((lpm_get_level(sleep_data, &ct)) && + (stats[ct].min_threshold == 0) && + data->kernel_sleep <= lpm_sleep_time) { + + stats[ct].min_threshold = lpm_sleep_time; + stats[ct].kernel_sleep_time = + data->kernel_sleep; + } + } + return 0; +} + +static struct notifier_block lpm_idle_nb = { + .notifier_call = lpm_callback, +}; + +static void lpm_test_initiate(int lpm_level_test) +{ + int test_ret; + + /* This will communicate to 'stat' debugfs to skip latency printing*/ + lpm_sleep_time = 0; + lpm_latency_test = false; + /* Unregister any infinitely registered level*/ + msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb); + + /* Register/Unregister for Notification */ + while (lpm_level_iter < lpm_level_count) { + test_ret = msm_lpm_register_notifier(cpu_to_debug, + lpm_level_iter, &lpm_idle_nb, false); + if (test_ret < 0) { + pr_err("%s: Registering notifier failed\n", __func__); + return; + } + if (!timer_interval) + break; + msleep(timer_interval); + msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb); + if (lpm_level_test == lpm_level_count) + lpm_level_iter++; + else + break; + } +} + +static void lpm_latency_test_initiate(unsigned long max_time) +{ + int test_ret; + lpm_latency_test = true; + lpm_sleep_time = latency_test_interval; + + msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb); + if (max_time > lpm_sleep_time) { + + do { + test_ret = msm_lpm_register_notifier(cpu_to_debug, + lpm_level_count + 1, + &lpm_idle_nb, true); + if (test_ret) { + pr_err("%s: Registering notifier failed\n", + __func__); + return; + } + usleep(lpm_sleep_time); + /*Unregister to ensure that we dont update the latency + during the timer value transistion*/ + msm_lpm_unregister_notifier(cpu_to_debug, + &lpm_idle_nb); + lpm_sleep_time += latency_test_interval; + } while (lpm_sleep_time < max_time); + } else + pr_err("%s: Invalid time interval specified\n", __func__); + + lpm_latency_test = false; +} + +static ssize_t lpm_test_comm_read(struct file *fp, char __user *user_buffer, + size_t buffer_length, loff_t *position) +{ + int i = 0; + int count = buffer_length; + int alloc_size = 100 * lpm_level_count; + char *temp_buf; + char *comm_buf; + ssize_t ret; + + comm_buf = kzalloc(alloc_size, GFP_KERNEL); + if (!comm_buf) { + pr_err("%s:Memory alloc failed\n", __func__); + ret = 0; + goto com_read_failed; + } + temp_buf = comm_buf; + + SNPRINTF(temp_buf, count, "Low power modes available:\n"); + + for (i = 0; i < lpm_level_count; i++) + SNPRINTF(temp_buf, count, "%d. %s\n", i, + per_cpu(lpm_levels, cpu_to_debug)[i].level_name); + + SNPRINTF(temp_buf, count, "%d. MSM test all lpm\n", i++); + SNPRINTF(temp_buf, count, "%d. MSM determine latency\n", i); + + ret = simple_read_from_buffer(user_buffer, buffer_length - count, + position, comm_buf, alloc_size); + kfree(comm_buf); + +com_read_failed: + return ret; +} + +char *trimspaces(char *time_buf) +{ + int len; + char *tail; + + len = strnlen(time_buf, INPUT_COUNT_BUF); + tail = time_buf + len; + while (isspace(*time_buf) && (time_buf != tail)) + time_buf++; + if (time_buf == tail) { + time_buf = NULL; + goto exit_trim_spaces; + } + len = strnlen(time_buf, INPUT_COUNT_BUF); + tail = time_buf + len - 1; + while (isspace(*tail) && tail != time_buf) { + *tail = '\0'; + tail--; + } +exit_trim_spaces: + return time_buf; +} + +static ssize_t lpm_test_comm_write(struct file *fp, const char __user + *user_buffer, size_t count, loff_t *position) +{ + ssize_t ret; + int str_ret; + int lpm_level_test; + char *new_ptr; + char *comm_buf; + + comm_buf = kzalloc(COMM_BUF_SIZE, GFP_KERNEL); + if (!comm_buf) { + pr_err("\'%s\': kzalloc failed\n", __func__); + return -EINVAL; + } + + memset(comm_buf, '\0', COMM_BUF_SIZE); + + ret = simple_write_to_buffer(comm_buf, COMM_BUF_SIZE, position, + user_buffer, count); + new_ptr = trimspaces(comm_buf); + if (!new_ptr) { + pr_err("%s: Test case number input invalid\n", __func__); + goto write_com_failed; + } + + if (!memcmp(comm_buf, LPM_TEST_ALL_LEVELS, + sizeof(LPM_TEST_ALL_LEVELS) - 1)) { + lpm_level_test = lpm_level_count; + lpm_level_iter = 0; + lpm_test_initiate(lpm_level_test); + goto write_com_success; + } else if (!memcmp(comm_buf, LPM_TEST_LATENCIES, + sizeof(LPM_TEST_LATENCIES) - 1)) { + lpm_level_test = lpm_level_count + 1; + lpm_latency_test_initiate(timer_interval * USEC_PER_MSEC); + goto write_com_success; + } else if (!memcmp(comm_buf, LPM_TEST_CLEAR, + sizeof(LPM_TEST_CLEAR) - 1)) { + msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb); + goto write_com_success; + } + + str_ret = kstrtoint(new_ptr, 10, &lpm_level_test); + if ((str_ret) || (lpm_level_test > (lpm_level_count + 1)) || + (lpm_level_test < 0)) + goto write_com_failed; + + lpm_level_iter = lpm_level_test; + lpm_test_initiate(lpm_level_test); + goto write_com_success; + +write_com_failed: + ret = -EINVAL; +write_com_success: + kfree(comm_buf); + return ret; +} + +static ssize_t lpm_test_stat_read(struct file *fp, char __user *user_buffer, + size_t buffer_length, loff_t *position) +{ + int i = 0; + int j = 0; + int count = buffer_length; + char *stat_buf; + char *stat_buf_start; + size_t stat_buf_size; + ssize_t ret; + int64_t min_ns; + int64_t max_ns; + int64_t avg_ns; + uint32_t min_ms; + uint32_t max_ms; + uint32_t avg_ms; + + stat_buf_size = ((sizeof(struct lpm_level_stat) * lpm_level_count) + + STAT_BUF_EXTRA_SIZE); + stat_buf = kzalloc(stat_buf_size, GFP_KERNEL); + if (!stat_buf) { + pr_err("\'%s\': kzalloc failed\n", __func__); + return -EINVAL; + } + stat_buf_start = stat_buf; + mutex_lock(&lpm_stats_mutex); + memset(stat_buf, '\0', stat_buf_size); + SNPRINTF(stat_buf, count, "\n\nStats for CPU: %d\nTotal Levels: %d\n", + cpu_to_debug, lpm_level_count); + if (!lpm_sleep_time) { + SNPRINTF(stat_buf, count, "Level(s) failed: "); + for (i = 0 ; i < lpm_level_count; i++) { + if (per_cpu(lpm_levels, cpu_to_debug)[i].entered) + continue; + else { + SNPRINTF(stat_buf, count, + "\n%d. %s", ++j, per_cpu(lpm_levels, + cpu_to_debug)[i].level_name); + } + } + SNPRINTF(stat_buf, count, "\n\nSTATS:"); + for (i = 0; i < lpm_level_count; i++) { + min_ns = per_cpu(lpm_levels, cpu_to_debug)[i].min_time; + min_ms = do_div(min_ns, NSEC_PER_MSEC); + max_ns = per_cpu(lpm_levels, cpu_to_debug)[i].max_time; + max_ms = do_div(max_ns, NSEC_PER_MSEC); + avg_ns = per_cpu(lpm_levels, cpu_to_debug)[i].avg_time; + avg_ms = do_div(avg_ns, NSEC_PER_MSEC); + SNPRINTF(stat_buf, count, "\nLEVEL: %s\n" + "Entered : %lld\n" + "Early wakeup : %lld\n" + "Min Time (mSec): %lld.%06u\n" + "Max Time (mSec): %lld.%06u\n" + "Avg Time (mSec): %lld.%06u\n", + per_cpu(lpm_levels, cpu_to_debug)[i].level_name, + per_cpu(lpm_levels, cpu_to_debug)[i].count, + per_cpu(lpm_levels, cpu_to_debug)[i].exit_early, + min_ns, min_ms, + max_ns, max_ms, + avg_ns, avg_ms); + } + } else { + for (i = 0; i < lpm_level_count; i++) { + SNPRINTF(stat_buf, count, "\nLEVEL: %s\n" + "Min Timer value (uSec): %lu\n" + "Kernel sleep time (uSec): %u\n", + per_cpu(lpm_levels, cpu_to_debug)[i].level_name, + per_cpu(lpm_levels, cpu_to_debug)[i]. + min_threshold, + per_cpu(lpm_levels, + cpu_to_debug)[i].kernel_sleep_time); + } + } + + ret = simple_read_from_buffer(user_buffer, buffer_length - count, + position, stat_buf_start, stat_buf_size); + + mutex_unlock(&lpm_stats_mutex); + kfree(stat_buf_start); + return ret; +} + +static ssize_t lpm_test_stat_write(struct file *fp, const char __user + *user_buffer, size_t count, loff_t *position) +{ + char buf[sizeof(LPM_STATS_RESET)]; + int ret; + int i; + struct lpm_level_stat *stats; + + if (count > sizeof(LPM_STATS_RESET)) { + ret = -EINVAL; + goto write_debug_failed; + } + + simple_write_to_buffer(buf, sizeof(LPM_STATS_RESET), position, + user_buffer, count); + + if (memcmp(buf, LPM_STATS_RESET, sizeof(LPM_STATS_RESET) - 1)) { + ret = -EINVAL; + goto write_debug_failed; + } + + mutex_lock(&lpm_stats_mutex); + stats = per_cpu(lpm_levels, cpu_to_debug); + for (i = 0 ; i < lpm_level_count; i++) { + stats[i].entered = 0; + stats[i].min_time = 0; + stats[i].max_time = 0; + stats[i].avg_time = 0; + stats[i].count = 0; + stats[i].exit_early = 0; + stats[i].min_threshold = 0; + stats[i].kernel_sleep_time = 0; + } + mutex_unlock(&lpm_stats_mutex); + return count; +write_debug_failed: + return ret; +} + +static void lpm_init_rpm_levels(int test_lpm_level_count, + struct msm_rpmrs_level *test_levels) +{ + int i = 0; + unsigned int m_cpu = 0; + struct lpm_level_stat *stat_levels = NULL; + + if (test_lpm_level_count < 0) + return; + + lpm_level_count = test_lpm_level_count; + + lpm_supp_level = test_levels; + for_each_possible_cpu(m_cpu) { + stat_levels = kzalloc(sizeof(struct lpm_level_stat) * + lpm_level_count, GFP_KERNEL); + if (!stat_levels) { + for (i = m_cpu - 1; i >= 0; i--) + kfree(per_cpu(lpm_levels, i)); + return; + } + + for (i = 0; i < lpm_level_count; i++) + lpm_populate_name(&stat_levels[i], &lpm_supp_level[i]); + + per_cpu(lpm_levels, m_cpu) = stat_levels; + } +} + +static const struct file_operations fops_stat = { + .read = lpm_test_stat_read, + .write = lpm_test_stat_write, +}; + +static const struct file_operations fops_comm = { + .read = lpm_test_comm_read, + .write = lpm_test_comm_write, +}; + +static int lpm_test_init(int test_lpm_level_count, + struct msm_rpmrs_level *test_levels) +{ + int filevalue; + int lpm_comm; + int ret = -EINVAL; + struct dentry *parent_dir = NULL; + + parent_dir = debugfs_create_dir("msm_lpm_debug", NULL); + if (!parent_dir) { + pr_err("%s: debugfs directory creation failed\n", + __func__); + goto init_err; + } + + lpm_stat = debugfs_create_file("stat", + S_IRUGO | S_IWUSR | S_IWGRP, parent_dir, + &filevalue, &fops_stat); + if (!lpm_stat) { + pr_err("%s: lpm_stats debugfs creation failed\n", + __func__); + goto init_err; + } + + lpm_ext_comm = debugfs_create_file("comm", + S_IRUGO | S_IWUSR | S_IWGRP, parent_dir, &lpm_comm, + &fops_comm); + if (!lpm_ext_comm) { + pr_err("%s: lpm_comm debugfs creation failed\n", + __func__); + debugfs_remove(lpm_stat); + goto init_err; + } + + /*Query RPM resources and allocate the data sturctures*/ + lpm_init_rpm_levels(test_lpm_level_count, test_levels); + ret = 0; + +init_err: + return ret; +} + +static int lpm_test_exit(struct platform_device *pdev) +{ + unsigned int m_cpu = 0; + + kfree(lpm_supp_level); + for_each_possible_cpu(m_cpu) + kfree(per_cpu(lpm_levels, m_cpu)); + debugfs_remove(lpm_stat); + debugfs_remove(lpm_ext_comm); + return 0; +} + +static int lpm_test_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lpm_test_platform_data *pdata; + struct msm_rpmrs_level *test_levels; + int test_lpm_level_count; + + pdata = pdev->dev.platform_data; + + if (!pdata) { + dev_err(dev, "no platform data specified\n"); + return -EINVAL; + } + + test_levels = pdata->msm_lpm_test_levels; + test_lpm_level_count = pdata->msm_lpm_test_level_count; + + if (pdata->use_qtimer) + msm_lpm_use_qtimer = true; + + lpm_test_init(test_lpm_level_count, test_levels); + + return 0; +} + +static struct platform_driver lpm_test_driver = { + .probe = lpm_test_probe, + .remove = lpm_test_exit, + .driver = { + .name = "lpm_test", + .owner = THIS_MODULE, + }, +}; + +static int __init lpm_test_platform_driver_init(void) +{ + return platform_driver_register(&lpm_test_driver); +} + +late_initcall(lpm_test_platform_driver_init); diff --git a/arch/arm/mach-msm/test-lpm.h b/arch/arm/mach-msm/test-lpm.h new file mode 100644 index 000000000000..1486f88c386e --- /dev/null +++ b/arch/arm/mach-msm/test-lpm.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2012, 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_TEST_LPM_H +#define __ARCH_ARM_MACH_MSM_TEST_LPM_H + +struct lpm_test_platform_data { + struct msm_rpmrs_level *msm_lpm_test_levels; + int msm_lpm_test_level_count; + bool use_qtimer; +}; +#endif diff --git a/arch/arm/mach-msm/test_qmi_client.c b/arch/arm/mach-msm/test_qmi_client.c new file mode 100644 index 000000000000..8f77005e1e20 --- /dev/null +++ b/arch/arm/mach-msm/test_qmi_client.c @@ -0,0 +1,450 @@ +/* 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 <linux/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/qmi_encdec.h> + +#include <asm/uaccess.h> + +#include <soc/qcom/msm_qmi_interface.h> + +#include "kernel_test_service_v01.h" + +#define TEST_SERVICE_SVC_ID 0x0000000f +#define TEST_SERVICE_V1 1 +#define TEST_SERVICE_INS_ID 0 + +static int test_rep_cnt = 10; +module_param_named(rep_cnt, test_rep_cnt, int, S_IRUGO | S_IWUSR | S_IWGRP); + +static int test_data_sz = 50; +module_param_named(data_sz, test_data_sz, int, S_IRUGO | S_IWUSR | S_IWGRP); + +static int test_clnt_debug_mask; +module_param_named(debug_mask, test_clnt_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +#define D(x...) do { \ + if (test_clnt_debug_mask) \ + pr_debug(x); \ +} while (0) + +/* Variable to initiate the test through debugfs interface */ +static struct dentry *test_dent; + +/* Test client port for IPC Router */ +static struct qmi_handle *test_clnt; +static int test_clnt_reset; + +/* Reader thread to receive responses & indications */ +static void test_clnt_recv_msg(struct work_struct *work); +static DECLARE_DELAYED_WORK(work_recv_msg, test_clnt_recv_msg); +static void test_clnt_svc_arrive(struct work_struct *work); +static DECLARE_DELAYED_WORK(work_svc_arrive, test_clnt_svc_arrive); +static void test_clnt_svc_exit(struct work_struct *work); +static DECLARE_DELAYED_WORK(work_svc_exit, test_clnt_svc_exit); +static struct workqueue_struct *test_clnt_workqueue; + +/* Variable to hold the test result */ +static int test_res; + +static unsigned int callback_count; +static void test_async_resp_cb(struct qmi_handle *handle, + unsigned int msg_id, void *msg, + void *resp_cb_data, int stat) +{ + callback_count++; + if (stat == 0) + D("%s invoked %d time(s): [RESP_LEN] = %d, [RESP_VALID] = %d", + __func__, callback_count, + ((struct test_data_resp_msg_v01 *)msg)->data_len, + ((struct test_data_resp_msg_v01 *)msg)->data_valid); + else if (stat < 0) + pr_err("%s: Request Failed [MSG_ID]: %d, [ERR_ID]: %d, [Callback_count]: %d", + __func__, msg_id, stat, callback_count); + + kfree(msg); + kfree(resp_cb_data); +} + +static int test_qmi_ping_pong_send_sync_msg(void) +{ + struct test_ping_req_msg_v01 req; + struct test_ping_resp_msg_v01 resp; + struct msg_desc req_desc, resp_desc; + int rc; + + memcpy(req.ping, "ping", sizeof(req.ping)); + req.client_name_valid = 0; + + req_desc.max_msg_len = TEST_PING_REQ_MAX_MSG_LEN_V01; + req_desc.msg_id = TEST_PING_REQ_MSG_ID_V01; + req_desc.ei_array = test_ping_req_msg_v01_ei; + + resp_desc.max_msg_len = TEST_PING_REQ_MAX_MSG_LEN_V01; + resp_desc.msg_id = TEST_PING_REQ_MSG_ID_V01; + resp_desc.ei_array = test_ping_resp_msg_v01_ei; + + rc = qmi_send_req_wait(test_clnt, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), 0); + if (rc < 0) { + pr_err("%s: send req failed %d\n", __func__, rc); + return rc; + } + + D("%s: Received %s response\n", __func__, resp.pong); + return rc; +} + +static int test_qmi_data_send_sync_msg(unsigned int data_len) +{ + struct test_data_req_msg_v01 *req; + struct test_data_resp_msg_v01 *resp; + struct msg_desc req_desc, resp_desc; + int rc, i; + + req = kzalloc(sizeof(struct test_data_req_msg_v01), GFP_KERNEL); + if (!req) { + pr_err("%s: Data req msg alloc failed\n", __func__); + return -ENOMEM; + } + + resp = kzalloc(sizeof(struct test_data_resp_msg_v01), GFP_KERNEL); + if (!resp) { + pr_err("%s: Data resp msg alloc failed\n", __func__); + kfree(req); + return -ENOMEM; + } + + req->data_len = data_len; + for (i = 0; i < data_len; i = i + sizeof(int)) + memcpy(req->data + i, (uint8_t *)&i, sizeof(int)); + req->client_name_valid = 0; + + req_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01; + req_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01; + req_desc.ei_array = test_data_req_msg_v01_ei; + + resp_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01; + resp_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01; + resp_desc.ei_array = test_data_resp_msg_v01_ei; + + rc = qmi_send_req_wait(test_clnt, &req_desc, req, sizeof(*req), + &resp_desc, resp, sizeof(*resp), 0); + if (rc < 0) { + pr_err("%s: send req failed\n", __func__); + goto data_send_err; + } + + D("%s: data_valid %d\n", __func__, resp->data_valid); + D("%s: data_len %d\n", __func__, resp->data_len); +data_send_err: + kfree(resp); + kfree(req); + return rc; +} + +static int test_qmi_data_send_async_msg(unsigned int data_len) +{ + struct test_data_req_msg_v01 *req; + struct test_data_resp_msg_v01 *resp; + struct msg_desc req_desc, *resp_desc; + int rc, i; + + req = kzalloc(sizeof(struct test_data_req_msg_v01), GFP_KERNEL); + if (!req) { + pr_err("%s: Data req msg alloc failed\n", __func__); + return -ENOMEM; + } + + resp = kzalloc(sizeof(struct test_data_resp_msg_v01), GFP_KERNEL); + if (!resp) { + pr_err("%s: Data resp msg alloc failed\n", __func__); + kfree(req); + return -ENOMEM; + } + + resp_desc = kzalloc(sizeof(struct msg_desc), GFP_KERNEL); + if (!resp_desc) { + pr_err("%s: Resp_desc msg alloc failed\n", __func__); + kfree(req); + kfree(resp); + return -ENOMEM; + } + + req->data_len = data_len; + for (i = 0; i < data_len; i = i + sizeof(int)) + memcpy(req->data + i, (uint8_t *)&i, sizeof(int)); + req->client_name_valid = 0; + + req_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01; + req_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01; + req_desc.ei_array = test_data_req_msg_v01_ei; + + resp_desc->max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01; + resp_desc->msg_id = TEST_DATA_REQ_MSG_ID_V01; + resp_desc->ei_array = test_data_resp_msg_v01_ei; + + rc = qmi_send_req_nowait(test_clnt, &req_desc, req, sizeof(*req), + resp_desc, resp, sizeof(*resp), + test_async_resp_cb, (void *)resp_desc); + if (rc < 0) { + pr_err("%s: send req failed\n", __func__); + kfree(resp); + kfree(resp_desc); + } + kfree(req); + return rc; +} + +static void test_clnt_recv_msg(struct work_struct *work) +{ + int rc; + + do { + D("%s: Notified about a Receive Event", __func__); + } while ((rc = qmi_recv_msg(test_clnt)) == 0); + + if (rc != -ENOMSG) + pr_err("%s: Error receiving message\n", __func__); +} + +static void test_clnt_notify(struct qmi_handle *handle, + enum qmi_event_type event, void *notify_priv) +{ + switch (event) { + case QMI_RECV_MSG: + queue_delayed_work(test_clnt_workqueue, + &work_recv_msg, 0); + break; + default: + break; + } +} + +static void test_clnt_svc_arrive(struct work_struct *work) +{ + int rc; + + D("%s begins\n", __func__); + + /* Create a Local client port for QMI communication */ + test_clnt = qmi_handle_create(test_clnt_notify, NULL); + if (!test_clnt) { + pr_err("%s: QMI client handle alloc failed\n", __func__); + return; + } + + D("%s: Lookup server name\n", __func__); + rc = qmi_connect_to_service(test_clnt, TEST_SERVICE_SVC_ID, + TEST_SERVICE_V1, + TEST_SERVICE_INS_ID); + if (rc < 0) { + pr_err("%s: Server not found\n", __func__); + qmi_handle_destroy(test_clnt); + test_clnt = NULL; + return; + } + test_clnt_reset = 0; + D("%s complete\n", __func__); +} + +static void test_clnt_svc_exit(struct work_struct *work) +{ + D("%s begins\n", __func__); + + qmi_handle_destroy(test_clnt); + test_clnt_reset = 1; + test_clnt = NULL; + + D("%s complete\n", __func__); +} + +static int test_clnt_svc_event_notify(struct notifier_block *this, + unsigned long code, + void *_cmd) +{ + D("%s: event %ld\n", __func__, code); + switch (code) { + case QMI_SERVER_ARRIVE: + queue_delayed_work(test_clnt_workqueue, + &work_svc_arrive, 0); + break; + case QMI_SERVER_EXIT: + queue_delayed_work(test_clnt_workqueue, + &work_svc_exit, 0); + break; + default: + break; + } + return 0; +} + +static int test_qmi_open(struct inode *ip, struct file *fp) +{ + if (!test_clnt) { + pr_err("%s Test client is not initialized\n", __func__); + return -ENODEV; + } + return 0; +} + +static ssize_t test_qmi_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + char _buf[16]; + snprintf(_buf, sizeof(_buf), "%d\n", test_res); + test_res = 0; + return simple_read_from_buffer(buf, count, pos, + _buf, strnlen(_buf, 16)); +} + +static int test_qmi_release(struct inode *ip, struct file *fp) +{ + return 0; +} + +static ssize_t test_qmi_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + unsigned char cmd[64]; + int len; + int i; + + if (count < 1) + return 0; + + len = min(count, (sizeof(cmd) - 1)); + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "ping_pong", sizeof(cmd))) { + for (i = 0; i < test_rep_cnt; i++) { + test_res = test_qmi_ping_pong_send_sync_msg(); + if (test_res == -ENETRESET || test_clnt_reset) { + do { + msleep(50); + } while (test_clnt_reset); + } + } + } else if (!strncmp(cmd, "data", sizeof(cmd))) { + for (i = 0; i < test_rep_cnt; i++) { + test_res = test_qmi_data_send_sync_msg(test_data_sz); + if (test_res == -ENETRESET || test_clnt_reset) { + do { + msleep(50); + } while (test_clnt_reset); + } + } + } else if (!strncmp(cmd, "data_async", sizeof(cmd))) { + int i; + callback_count = 0; + for (i = 0; i < test_rep_cnt; i++) { + test_res = test_qmi_data_send_async_msg(test_data_sz); + if (test_res == -ENETRESET || test_clnt_reset) { + --i; + do { + msleep(50); + } while (test_clnt_reset); + } else if (test_res < 0) { + --i; + pr_err("%s: Error sending txn, aborting now", + __func__); + break; + } + } + while (callback_count < i) { + if (test_clnt_reset) { + pr_err("%s: Service Exited", __func__); + break; + } + msleep(50); + } + D("%s complete\n", __func__); + callback_count = 0; + } else { + test_res = -EINVAL; + } + return count; +} + +static struct notifier_block test_clnt_nb = { + .notifier_call = test_clnt_svc_event_notify, +}; + +static const struct file_operations debug_ops = { + .owner = THIS_MODULE, + .open = test_qmi_open, + .read = test_qmi_read, + .write = test_qmi_write, + .release = test_qmi_release, +}; + +static int __init test_qmi_init(void) +{ + int rc; + + test_clnt_workqueue = create_singlethread_workqueue("test_clnt"); + if (!test_clnt_workqueue) + return -EFAULT; + + rc = qmi_svc_event_notifier_register(TEST_SERVICE_SVC_ID, + TEST_SERVICE_V1, TEST_SERVICE_INS_ID, + &test_clnt_nb); + if (rc < 0) { + pr_err("%s: notifier register failed\n", __func__); + destroy_workqueue(test_clnt_workqueue); + return rc; + } + + test_dent = debugfs_create_file("test_qmi_client", 0444, 0, + NULL, &debug_ops); + if (IS_ERR(test_dent)) { + pr_err("%s: unable to create debugfs %ld\n", + __func__, IS_ERR(test_dent)); + test_dent = NULL; + qmi_svc_event_notifier_unregister(TEST_SERVICE_SVC_ID, + TEST_SERVICE_V1, TEST_SERVICE_INS_ID, + &test_clnt_nb); + destroy_workqueue(test_clnt_workqueue); + return -EFAULT; + } + + return 0; +} + +static void __exit test_qmi_exit(void) +{ + qmi_svc_event_notifier_unregister(TEST_SERVICE_SVC_ID, + TEST_SERVICE_V1, + TEST_SERVICE_INS_ID, &test_clnt_nb); + destroy_workqueue(test_clnt_workqueue); + debugfs_remove(test_dent); +} + +module_init(test_qmi_init); +module_exit(test_qmi_exit); + +MODULE_DESCRIPTION("TEST QMI Client Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h new file mode 100644 index 000000000000..ad67981c9067 --- /dev/null +++ b/arch/arm/mach-msm/timer.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2008-2009, 2011-2012 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. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_TIMER_H_ +#define _ARCH_ARM_MACH_MSM_TIMER_H_ + +void msm_timer_init(void); +uint32_t msm_timer_get_sclk_ticks(void); +int msm_timer_init_time_sync(void (*timeout)(void)); +#ifndef CONFIG_ARM_ARCH_TIMER +void __iomem *msm_timer_get_timer0_base(void); +int64_t msm_timer_enter_idle(void); +void msm_timer_exit_idle(int low_power); +int64_t msm_timer_get_sclk_time(int64_t *period); +#else +static inline int64_t msm_timer_enter_idle(void) { return 0; } +static inline void msm_timer_exit_idle(int low_power) { return; } +static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; } +static inline void __iomem *msm_timer_get_timer0_base(void) { return NULL; } +#endif +#endif diff --git a/arch/arm/mach-msm/tz_log.c b/arch/arm/mach-msm/tz_log.c new file mode 100644 index 000000000000..4b0dfe34fe52 --- /dev/null +++ b/arch/arm/mach-msm/tz_log.c @@ -0,0 +1,785 @@ +/* Copyright (c) 2011-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 <linux/debugfs.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/msm_ion.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <soc/qcom/scm.h> +#include <soc/qcom/qseecomi.h> + +#define DEBUG_MAX_RW_BUF 4096 + +/* QSEE_LOG_BUF_SIZE = 32K */ +#define QSEE_LOG_BUF_SIZE 0x8000 + + +/* TZ Diagnostic Area legacy version number */ +#define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2 +/* + * Preprocessor Definitions and Constants + */ +#define TZBSP_CPU_COUNT 0x02 +/* + * Number of VMID Tables + */ +#define TZBSP_DIAG_NUM_OF_VMID 16 +/* + * VMID Description length + */ +#define TZBSP_DIAG_VMID_DESC_LEN 7 +/* + * Number of Interrupts + */ +#define TZBSP_DIAG_INT_NUM 32 +/* + * Length of descriptive name associated with Interrupt + */ +#define TZBSP_MAX_INT_DESC 16 +/* + * VMID Table + */ +struct tzdbg_vmid_t { + uint8_t vmid; /* Virtual Machine Identifier */ + uint8_t desc[TZBSP_DIAG_VMID_DESC_LEN]; /* ASCII Text */ +}; +/* + * Boot Info Table + */ +struct tzdbg_boot_info_t { + uint32_t wb_entry_cnt; /* Warmboot entry CPU Counter */ + uint32_t wb_exit_cnt; /* Warmboot exit CPU Counter */ + uint32_t pc_entry_cnt; /* Power Collapse entry CPU Counter */ + uint32_t pc_exit_cnt; /* Power Collapse exit CPU counter */ + uint32_t warm_jmp_addr; /* Last Warmboot Jump Address */ + uint32_t spare; /* Reserved for future use. */ +}; +/* + * Reset Info Table + */ +struct tzdbg_reset_info_t { + uint32_t reset_type; /* Reset Reason */ + uint32_t reset_cnt; /* Number of resets occured/CPU */ +}; +/* + * Interrupt Info Table + */ +struct tzdbg_int_t { + /* + * Type of Interrupt/exception + */ + uint16_t int_info; + /* + * Availability of the slot + */ + uint8_t avail; + /* + * Reserved for future use + */ + uint8_t spare; + /* + * Interrupt # for IRQ and FIQ + */ + uint32_t int_num; + /* + * ASCII text describing type of interrupt e.g: + * Secure Timer, EBI XPU. This string is always null terminated, + * supporting at most TZBSP_MAX_INT_DESC characters. + * Any additional characters are truncated. + */ + uint8_t int_desc[TZBSP_MAX_INT_DESC]; + uint64_t int_count[TZBSP_CPU_COUNT]; /* # of times seen per CPU */ +}; + +/* + * Log ring buffer position + */ +struct tzdbg_log_pos_t { + uint16_t wrap; + uint16_t offset; +}; + + /* + * Log ring buffer + */ +struct tzdbg_log_t { + struct tzdbg_log_pos_t log_pos; + /* open ended array to the end of the 4K IMEM buffer */ + uint8_t log_buf[]; +}; + +/* + * Diagnostic Table + */ +struct tzdbg_t { + uint32_t magic_num; + uint32_t version; + /* + * Number of CPU's + */ + uint32_t cpu_count; + /* + * Offset of VMID Table + */ + uint32_t vmid_info_off; + /* + * Offset of Boot Table + */ + uint32_t boot_info_off; + /* + * Offset of Reset info Table + */ + uint32_t reset_info_off; + /* + * Offset of Interrupt info Table + */ + uint32_t int_info_off; + /* + * Ring Buffer Offset + */ + uint32_t ring_off; + /* + * Ring Buffer Length + */ + uint32_t ring_len; + /* + * VMID to EE Mapping + */ + struct tzdbg_vmid_t vmid_info[TZBSP_DIAG_NUM_OF_VMID]; + /* + * Boot Info + */ + struct tzdbg_boot_info_t boot_info[TZBSP_CPU_COUNT]; + /* + * Reset Info + */ + struct tzdbg_reset_info_t reset_info[TZBSP_CPU_COUNT]; + uint32_t num_interrupts; + struct tzdbg_int_t int_info[TZBSP_DIAG_INT_NUM]; + /* + * We need at least 2K for the ring buffer + */ + struct tzdbg_log_t ring_buffer; /* TZ Ring Buffer */ +}; + +/* + * Enumeration order for VMID's + */ +enum tzdbg_stats_type { + TZDBG_BOOT = 0, + TZDBG_RESET, + TZDBG_INTERRUPT, + TZDBG_VMID, + TZDBG_GENERAL, + TZDBG_LOG, + TZDBG_QSEE_LOG, + TZDBG_STATS_MAX +}; + +struct tzdbg_stat { + char *name; + char *data; +}; + +struct tzdbg { + void __iomem *virt_iobase; + struct tzdbg_t *diag_buf; + char *disp_buf; + int debug_tz[TZDBG_STATS_MAX]; + struct tzdbg_stat stat[TZDBG_STATS_MAX]; +}; + +static struct tzdbg tzdbg = { + + .stat[TZDBG_BOOT].name = "boot", + .stat[TZDBG_RESET].name = "reset", + .stat[TZDBG_INTERRUPT].name = "interrupt", + .stat[TZDBG_VMID].name = "vmid", + .stat[TZDBG_GENERAL].name = "general", + .stat[TZDBG_LOG].name = "log", + .stat[TZDBG_QSEE_LOG].name = "qsee_log", +}; + +static struct tzdbg_log_t *g_qsee_log; + +/* + * Debugfs data structure and functions + */ + +static int _disp_tz_general_stats(void) +{ + int len = 0; + + len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1, + " Version : 0x%x\n" + " Magic Number : 0x%x\n" + " Number of CPU : %d\n", + tzdbg.diag_buf->version, + tzdbg.diag_buf->magic_num, + tzdbg.diag_buf->cpu_count); + tzdbg.stat[TZDBG_GENERAL].data = tzdbg.disp_buf; + return len; +} + +static int _disp_tz_vmid_stats(void) +{ + int i, num_vmid; + int len = 0; + struct tzdbg_vmid_t *ptr; + + ptr = (struct tzdbg_vmid_t *)((unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->vmid_info_off); + num_vmid = ((tzdbg.diag_buf->boot_info_off - + tzdbg.diag_buf->vmid_info_off)/ + (sizeof(struct tzdbg_vmid_t))); + + for (i = 0; i < num_vmid; i++) { + if (ptr->vmid < 0xFF) { + len += snprintf(tzdbg.disp_buf + len, + (DEBUG_MAX_RW_BUF - 1) - len, + " 0x%x %s\n", + (uint32_t)ptr->vmid, (uint8_t *)ptr->desc); + } + if (len > (DEBUG_MAX_RW_BUF - 1)) { + pr_warn("%s: Cannot fit all info into the buffer\n", + __func__); + break; + } + ptr++; + } + + tzdbg.stat[TZDBG_VMID].data = tzdbg.disp_buf; + return len; +} + +static int _disp_tz_boot_stats(void) +{ + int i; + int len = 0; + struct tzdbg_boot_info_t *ptr; + + ptr = (struct tzdbg_boot_info_t *)((unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->boot_info_off); + + for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) { + len += snprintf(tzdbg.disp_buf + len, + (DEBUG_MAX_RW_BUF - 1) - len, + " CPU #: %d\n" + " Warmboot jump address : 0x%x\n" + " Warmboot entry CPU counter: 0x%x\n" + " Warmboot exit CPU counter : 0x%x\n" + " Power Collapse entry CPU counter: 0x%x\n" + " Power Collapse exit CPU counter : 0x%x\n", + i, ptr->warm_jmp_addr, ptr->wb_entry_cnt, + ptr->wb_exit_cnt, ptr->pc_entry_cnt, + ptr->pc_exit_cnt); + + if (len > (DEBUG_MAX_RW_BUF - 1)) { + pr_warn("%s: Cannot fit all info into the buffer\n", + __func__); + break; + } + ptr++; + } + tzdbg.stat[TZDBG_BOOT].data = tzdbg.disp_buf; + return len; +} + +static int _disp_tz_reset_stats(void) +{ + int i; + int len = 0; + struct tzdbg_reset_info_t *ptr; + + ptr = (struct tzdbg_reset_info_t *)((unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->reset_info_off); + + for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) { + len += snprintf(tzdbg.disp_buf + len, + (DEBUG_MAX_RW_BUF - 1) - len, + " CPU #: %d\n" + " Reset Type (reason) : 0x%x\n" + " Reset counter : 0x%x\n", + i, ptr->reset_type, ptr->reset_cnt); + + if (len > (DEBUG_MAX_RW_BUF - 1)) { + pr_warn("%s: Cannot fit all info into the buffer\n", + __func__); + break; + } + + ptr++; + } + tzdbg.stat[TZDBG_RESET].data = tzdbg.disp_buf; + return len; +} + +static int _disp_tz_interrupt_stats(void) +{ + int i, j, int_info_size; + int len = 0; + int *num_int; + unsigned char *ptr; + struct tzdbg_int_t *tzdbg_ptr; + + num_int = (uint32_t *)((unsigned char *)tzdbg.diag_buf + + (tzdbg.diag_buf->int_info_off - sizeof(uint32_t))); + ptr = ((unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->int_info_off); + int_info_size = ((tzdbg.diag_buf->ring_off - + tzdbg.diag_buf->int_info_off)/(*num_int)); + + for (i = 0; i < (*num_int); i++) { + tzdbg_ptr = (struct tzdbg_int_t *)ptr; + len += snprintf(tzdbg.disp_buf + len, + (DEBUG_MAX_RW_BUF - 1) - len, + " Interrupt Number : 0x%x\n" + " Type of Interrupt : 0x%x\n" + " Description of interrupt : %s\n", + tzdbg_ptr->int_num, + (uint32_t)tzdbg_ptr->int_info, + (uint8_t *)tzdbg_ptr->int_desc); + for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) { + len += snprintf(tzdbg.disp_buf + len, + (DEBUG_MAX_RW_BUF - 1) - len, + " int_count on CPU # %d : %u\n", + (uint32_t)j, + (uint32_t)tzdbg_ptr->int_count[j]); + } + len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1, + "\n"); + + if (len > (DEBUG_MAX_RW_BUF - 1)) { + pr_warn("%s: Cannot fit all info into the buffer\n", + __func__); + break; + } + + ptr += int_info_size; + } + tzdbg.stat[TZDBG_INTERRUPT].data = tzdbg.disp_buf; + return len; +} + +static int _disp_tz_log_stats_legacy(void) +{ + int len = 0; + unsigned char *ptr; + + ptr = (unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->ring_off; + len += snprintf(tzdbg.disp_buf, (DEBUG_MAX_RW_BUF - 1) - len, + "%s\n", ptr); + + tzdbg.stat[TZDBG_LOG].data = tzdbg.disp_buf; + return len; +} + +static int _disp_log_stats(struct tzdbg_log_t *log, + struct tzdbg_log_pos_t *log_start, uint32_t log_len, + size_t count, uint32_t buf_idx) +{ + uint32_t wrap_start; + uint32_t wrap_end; + uint32_t wrap_cnt; + int max_len; + int len = 0; + int i = 0; + + wrap_start = log_start->wrap; + wrap_end = log->log_pos.wrap; + + /* Calculate difference in # of buffer wrap-arounds */ + if (wrap_end >= wrap_start) { + wrap_cnt = wrap_end - wrap_start; + } else { + /* wrap counter has wrapped around, invalidate start position */ + wrap_cnt = 2; + } + + if (wrap_cnt > 1) { + /* end position has wrapped around more than once, */ + /* current start no longer valid */ + log_start->wrap = log->log_pos.wrap - 1; + log_start->offset = (log->log_pos.offset + 1) % log_len; + } else if ((wrap_cnt == 1) && + (log->log_pos.offset > log_start->offset)) { + /* end position has overwritten start */ + log_start->offset = (log->log_pos.offset + 1) % log_len; + } + + while (log_start->offset == log->log_pos.offset) { + /* + * No data in ring buffer, + * so we'll hang around until something happens + */ + unsigned long t = msleep_interruptible(50); + if (t != 0) { + /* Some event woke us up, so let's quit */ + return 0; + } + + if (buf_idx == TZDBG_LOG) + memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, + DEBUG_MAX_RW_BUF); + + } + + max_len = (count > DEBUG_MAX_RW_BUF) ? DEBUG_MAX_RW_BUF : count; + + /* + * Read from ring buff while there is data and space in return buff + */ + while ((log_start->offset != log->log_pos.offset) && (len < max_len)) { + tzdbg.disp_buf[i++] = log->log_buf[log_start->offset]; + log_start->offset = (log_start->offset + 1) % log_len; + if (0 == log_start->offset) + ++log_start->wrap; + ++len; + } + + /* + * return buffer to caller + */ + tzdbg.stat[buf_idx].data = tzdbg.disp_buf; + return len; +} + +static int _disp_tz_log_stats(size_t count) +{ + static struct tzdbg_log_pos_t log_start = {0}; + struct tzdbg_log_t *log_ptr; + log_ptr = (struct tzdbg_log_t *)((unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->ring_off - + offsetof(struct tzdbg_log_t, log_buf)); + + return _disp_log_stats(log_ptr, &log_start, + tzdbg.diag_buf->ring_len, count, TZDBG_LOG); +} + +static int _disp_qsee_log_stats(size_t count) +{ + static struct tzdbg_log_pos_t log_start = {0}; + + return _disp_log_stats(g_qsee_log, &log_start, + QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t), + count, TZDBG_QSEE_LOG); +} + +static ssize_t tzdbgfs_read(struct file *file, char __user *buf, + size_t count, loff_t *offp) +{ + int len = 0; + int *tz_id = file->private_data; + + memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, + DEBUG_MAX_RW_BUF); + switch (*tz_id) { + case TZDBG_BOOT: + len = _disp_tz_boot_stats(); + break; + case TZDBG_RESET: + len = _disp_tz_reset_stats(); + break; + case TZDBG_INTERRUPT: + len = _disp_tz_interrupt_stats(); + break; + case TZDBG_GENERAL: + len = _disp_tz_general_stats(); + break; + case TZDBG_VMID: + len = _disp_tz_vmid_stats(); + break; + case TZDBG_LOG: + if (TZBSP_DIAG_MAJOR_VERSION_LEGACY < + (tzdbg.diag_buf->version >> 16)) { + len = _disp_tz_log_stats(count); + *offp = 0; + } else { + len = _disp_tz_log_stats_legacy(); + } + break; + case TZDBG_QSEE_LOG: + len = _disp_qsee_log_stats(count); + *offp = 0; + break; + default: + break; + } + + if (len > count) + len = count; + + return simple_read_from_buffer(buf, len, offp, + tzdbg.stat[(*tz_id)].data, len); +} + +static int tzdbgfs_open(struct inode *inode, struct file *pfile) +{ + pfile->private_data = inode->i_private; + return 0; +} + +const struct file_operations tzdbg_fops = { + .owner = THIS_MODULE, + .read = tzdbgfs_read, + .open = tzdbgfs_open, +}; + +static struct ion_client *g_ion_clnt; +static struct ion_handle *g_ihandle; + +/* + * Allocates log buffer from ION, registers the buffer at TZ + */ +static void tzdbg_register_qsee_log_buf(void) +{ + /* register log buffer scm request */ + struct qseecom_reg_log_buf_ireq req; + + /* scm response */ + struct qseecom_command_scm_resp resp = {}; + ion_phys_addr_t pa = 0; + uint32_t len; + int ret = 0; + + /* Create ION msm client */ + g_ion_clnt = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK, "qsee_log"); + if (g_ion_clnt == NULL) { + pr_err("%s: Ion client cannot be created\n", __func__); + return; + } + + g_ihandle = ion_alloc(g_ion_clnt, QSEE_LOG_BUF_SIZE, + 4096, ION_HEAP(ION_QSECOM_HEAP_ID), 0); + if (IS_ERR_OR_NULL(g_ihandle)) { + pr_err("%s: Ion client could not retrieve the handle\n", + __func__); + goto err1; + } + + ret = ion_phys(g_ion_clnt, g_ihandle, &pa, &len); + if (ret) { + pr_err("%s: Ion conversion to physical address failed\n", + __func__); + goto err2; + } + + req.qsee_cmd_id = QSEOS_REGISTER_LOG_BUF_COMMAND; + req.phy_addr = pa; + req.len = len; + + /* SCM_CALL to register the log buffer */ + ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req), + &resp, sizeof(resp)); + if (ret) { + pr_err("%s: scm_call to register log buffer failed\n", + __func__); + goto err2; + } + + if (resp.result != QSEOS_RESULT_SUCCESS) { + pr_err( + "%s: scm_call to register log buf failed, resp result =%d\n", + __func__, resp.result); + goto err2; + } + + g_qsee_log = + (struct tzdbg_log_t *)ion_map_kernel(g_ion_clnt, g_ihandle); + g_qsee_log->log_pos.wrap = g_qsee_log->log_pos.offset = 0; + return; + +err2: + ion_free(g_ion_clnt, g_ihandle); + g_ihandle = NULL; +err1: + ion_client_destroy(g_ion_clnt); + g_ion_clnt = NULL; +} + +static int tzdbgfs_init(struct platform_device *pdev) +{ + int rc = 0; + int i; + struct dentry *dent_dir; + struct dentry *dent; + + dent_dir = debugfs_create_dir("tzdbg", NULL); + if (dent_dir == NULL) { + dev_err(&pdev->dev, "tzdbg debugfs_create_dir failed\n"); + return -ENOMEM; + } + + for (i = 0; i < TZDBG_STATS_MAX; i++) { + tzdbg.debug_tz[i] = i; + dent = debugfs_create_file(tzdbg.stat[i].name, + S_IRUGO, dent_dir, + &tzdbg.debug_tz[i], &tzdbg_fops); + if (dent == NULL) { + dev_err(&pdev->dev, "TZ debugfs_create_file failed\n"); + rc = -ENOMEM; + goto err; + } + } + tzdbg.disp_buf = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL); + if (tzdbg.disp_buf == NULL) { + pr_err("%s: Can't Allocate memory for tzdbg.disp_buf\n", + __func__); + + goto err; + } + platform_set_drvdata(pdev, dent_dir); + return 0; +err: + debugfs_remove_recursive(dent_dir); + + return rc; +} + +static void tzdbgfs_exit(struct platform_device *pdev) +{ + struct dentry *dent_dir; + + kzfree(tzdbg.disp_buf); + dent_dir = platform_get_drvdata(pdev); + debugfs_remove_recursive(dent_dir); + if (g_ion_clnt != NULL) { + if (!IS_ERR_OR_NULL(g_ihandle)) { + ion_unmap_kernel(g_ion_clnt, g_ihandle); + ion_free(g_ion_clnt, g_ihandle); + } + ion_client_destroy(g_ion_clnt); +} +} + +/* + * Driver functions + */ +static int tz_log_probe(struct platform_device *pdev) +{ + struct resource *resource; + void __iomem *virt_iobase; + phys_addr_t tzdiag_phy_iobase; + uint32_t *ptr = NULL; + + /* + * Get address that stores the physical location of 4KB + * diagnostic data + */ + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!resource) { + dev_err(&pdev->dev, + "%s: ERROR Missing MEM resource\n", __func__); + return -ENXIO; + }; + /* + * Map address that stores the physical location of 4KB + * diagnostic data + */ + virt_iobase = devm_ioremap_nocache(&pdev->dev, resource->start, + resource->end - resource->start + 1); + if (!virt_iobase) { + dev_err(&pdev->dev, + "%s: ERROR could not ioremap: start=%pr, len=%u\n", + __func__, &resource->start, + (unsigned int)(resource->end - resource->start + 1)); + return -ENXIO; + } + /* + * Retrieve the address of 4KB diagnostic data + */ + tzdiag_phy_iobase = readl_relaxed(virt_iobase); + + /* + * Map the 4KB diagnostic information area + */ + tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev, + tzdiag_phy_iobase, DEBUG_MAX_RW_BUF); + + if (!tzdbg.virt_iobase) { + dev_err(&pdev->dev, + "%s: ERROR could not ioremap: start=%pr, len=%u\n", + __func__, &tzdiag_phy_iobase, + DEBUG_MAX_RW_BUF); + return -ENXIO; + } + + ptr = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL); + if (ptr == NULL) { + pr_err("%s: Can't Allocate memory: ptr\n", + __func__); + return -ENXIO; + } + + tzdbg.diag_buf = (struct tzdbg_t *)ptr; + + if (tzdbgfs_init(pdev)) + goto err; + + tzdbg_register_qsee_log_buf(); + return 0; +err: + kfree(tzdbg.diag_buf); + return -ENXIO; +} + + +static int tz_log_remove(struct platform_device *pdev) +{ + kzfree(tzdbg.diag_buf); + tzdbgfs_exit(pdev); + + return 0; +} + +static struct of_device_id tzlog_match[] = { + { .compatible = "qcom,tz-log", + }, + {} +}; + +static struct platform_driver tz_log_driver = { + .probe = tz_log_probe, + .remove = tz_log_remove, + .driver = { + .name = "tz_log", + .owner = THIS_MODULE, + .of_match_table = tzlog_match, + }, +}; + +static int __init tz_log_init(void) +{ + return platform_driver_register(&tz_log_driver); +} + +static void __exit tz_log_exit(void) +{ + platform_driver_unregister(&tz_log_driver); +} + +module_init(tz_log_init); +module_exit(tz_log_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TZ Log driver"); +MODULE_VERSION("1.1"); +MODULE_ALIAS("platform:tz_log"); diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index ee5697ba05bc..dce1a43b9c3b 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -23,6 +23,37 @@ config ARCH_MSM8974 bool "Enable support for MSM8974" select HAVE_ARM_ARCH_TIMER +config ARCH_MSM8916 + bool "MSM8916" + select ARCH_MSM_CORTEXMP + select HAVE_GENERIC_HARDIRQS + select USE_GENERIC_CPU_HELPERS + select ARM_GIC + select MULTI_IRQ_HANDLER + select CPU_V7 + select HAVE_ARM_ARCH_TIMER + select MAY_HAVE_SPARSE_IRQ + select SPARSE_IRQ + select PINCTRL + select PINCTRL_MSM_TLMM_V4 + select USE_PINCTRL_IRQ + select MSM_PM if PM + select MSM_RPM_SMD + select MEMORY_HOLE_CARVEOUT + select DONT_MAP_HOLE_AFTER_MEMBANK0 + select QMI_ENCDEC + select MSM_IRQ + select MSM_CORTEX_A53 + select CPU_FREQ_MSM + select CPU_FREQ + select PM_DEVFREQ + select MSM_DEVFREQ_CPUBW + select MSM_RPM_SMD + select ARM_HAS_SG_CHAIN + select ARCH_WANT_KMAP_ATOMIC_FLUSH + select SOC_BUS + + config QCOM_SCM bool diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 7eb94e6fc376..c59ae579a30f 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -695,6 +695,21 @@ config SWP_EMULATE If unsure, say Y. +config FORCE_INSTRUCTION_ALIGNMENT + bool "Force instructions address alignment" + depends on CPU_V7 && ALIGNMENT_TRAP + help + Branching to an address in ARM state which is not word aligned, + where this is defined to be UNPREDICTABLE, can cause one of the + following two behaviours: 1. The unaligned location is forced to + be aligned. 2. Using the unaligned address generates a Prefetch + Abort on the first instruction using the unaligned PC value. + + To be consistant for the user space binaries, the unaligned location + is forced aligned with this config. + + If unsure, say Y. + config CPU_BIG_ENDIAN bool "Build big-endian kernel" depends on ARCH_SUPPORTS_BIG_ENDIAN diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 83792f4324ea..ab8da50a417e 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -747,6 +747,36 @@ do_alignment_t32_to_handler(unsigned long *pinstr, struct pt_regs *regs, return NULL; } +#ifdef CONFIG_FORCE_INSTRUCTION_ALIGNMENT +static int +do_ialignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + /* + * Branching to an address in ARM state which is not word aligned, + * where this is defined to be UNPREDICTABLE, + * can cause one of the following two behaviours: + * 1. The unaligned location is forced to be aligned. + * 2. Using the unaligned address generates a Prefetch Abort on + * the first instruction using the unaligned PC value. + */ + int isize = 4; + + if (user_mode(regs) && !thumb_mode(regs)) { + ai_sys += 1; + + /* + * Force align the instruction in software to be following + * a single behaviour for the unpredicatable cases. + */ + instruction_pointer(regs) &= ~(isize + (-1UL)); + return 0; + } + + ai_skipped += 1; + return 1; +} +#endif + static int do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { @@ -990,6 +1020,11 @@ static int __init alignment_init(void) hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN, "alignment exception"); +#ifdef CONFIG_FORCE_INSTRUCTION_ALIGNMENT + hook_ifault_code(FAULT_CODE_ALIGNMENT, do_ialignment, SIGBUS, + BUS_ADRALN, "alignment exception"); +#endif + /* * ARMv6K and ARMv7 use fault status 3 (0b00011) as Access Flag section * fault, not as alignment error. diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index b966656d2c2d..5154280c1ad7 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -371,7 +371,6 @@ v7_dma_inv_range: dsb st ret lr ENDPROC(v7_dma_inv_range) - /* * v7_dma_clean_range(start,end) * - start - virtual start address of region diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 9481f85c56e6..b68992f71f1d 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -46,6 +46,9 @@ unsigned long __init __clear_cr(unsigned long mask) #endif static phys_addr_t phys_initrd_start __initdata = 0; +int msm_krait_need_wfe_fixup; +EXPORT_SYMBOL(msm_krait_need_wfe_fixup); + static unsigned long phys_initrd_size __initdata = 0; static int __init early_initrd(char *p) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index a10297da122b..8c7bf7936ef5 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -467,6 +467,7 @@ msm7x27_surf MACH_MSM7X27_SURF MSM7X27_SURF 2705 msm7x27_ffa MACH_MSM7X27_FFA MSM7X27_FFA 2706 msm7x30_ffa MACH_MSM7X30_FFA MSM7X30_FFA 2707 qsd8x50_surf MACH_QSD8X50_SURF QSD8X50_SURF 2708 +qsd8x50_ffa MACH_QSD8X50_FFA QSD8X50_FFA 2710 mx53_evk MACH_MX53_EVK MX53_EVK 2716 igep0030 MACH_IGEP0030 IGEP0030 2717 sbc3530 MACH_SBC3530 SBC3530 2722 @@ -479,6 +480,8 @@ wbd222 MACH_WBD222 WBD222 2753 msm8x60_surf MACH_MSM8X60_SURF MSM8X60_SURF 2755 msm8x60_sim MACH_MSM8X60_SIM MSM8X60_SIM 2756 tcc8000_sdk MACH_TCC8000_SDK TCC8000_SDK 2758 +msm8x55_surf MACH_MSM8X55_SURF MSM8X55_SURF 2768 +msm8x55_ffa MACH_MSM8X55_FFA MSM8X55_FFA 2769 cns3420vb MACH_CNS3420VB CNS3420VB 2776 omap4_panda MACH_OMAP4_PANDA OMAP4_PANDA 2791 ti8168evm MACH_TI8168EVM TI8168EVM 2800 @@ -491,6 +494,8 @@ smdkc210 MACH_SMDKC210 SMDKC210 2838 t5325 MACH_T5325 T5325 2846 income MACH_INCOME INCOME 2849 goni MACH_GONI GONI 2862 +msm8x55_svlte_ffa MACH_MSM8X55_SVLTE_FFA MSM8X55_SVLTE_FFA 2863 +msm8x55_svlte_surf MACH_MSM8X55_SVLTE_SURF MSM8X55_SVLTE_SURF 2864 bv07 MACH_BV07 BV07 2882 openrd_ultimate MACH_OPENRD_ULTIMATE OPENRD_ULTIMATE 2884 devixp MACH_DEVIXP DEVIXP 2885 @@ -515,14 +520,19 @@ mx53_smd MACH_MX53_SMD MX53_SMD 3011 msm8x60_rumi3 MACH_MSM8X60_RUMI3 MSM8X60_RUMI3 3016 msm8x60_ffa MACH_MSM8X60_FFA MSM8X60_FFA 3017 cm_a510 MACH_CM_A510 CM_A510 3020 +fsm9xxx_surf MACH_FSM9XXX_SURF FSM9XXX_SURF 3028 +fsm9xxx_ffa MACH_FSM9XXX_FFA FSM9XXX_FFA 3029 tx28 MACH_TX28 TX28 3043 pcontrol_g20 MACH_PCONTROL_G20 PCONTROL_G20 3062 vpr200 MACH_VPR200 VPR200 3087 torbreck MACH_TORBRECK TORBRECK 3090 prima2_evb MACH_PRIMA2_EVB PRIMA2_EVB 3103 +msm8x60_fluid MACH_MSM8X60_FLUID MSM8X60_FLUID 3124 paz00 MACH_PAZ00 PAZ00 3128 acmenetusfoxg20 MACH_ACMENETUSFOXG20 ACMENETUSFOXG20 3129 +msm8x60_fusion MACH_MSM8X60_FUSION MSM8X60_FUSION 3181 ag5evm MACH_AG5EVM AG5EVM 3189 +msm8x60_fusn_ffa MACH_MSM8X60_FUSN_FFA MSM8X60_FUSN_FFA 3199 ics_if_voip MACH_ICS_IF_VOIP ICS_IF_VOIP 3206 wlf_cragg_6410 MACH_WLF_CRAGG_6410 WLF_CRAGG_6410 3207 trimslice MACH_TRIMSLICE TRIMSLICE 3209 @@ -540,17 +550,28 @@ armlex4210 MACH_ARMLEX4210 ARMLEX4210 3361 snowball MACH_SNOWBALL SNOWBALL 3363 xilinx_ep107 MACH_XILINX_EP107 XILINX_EP107 3378 nuri MACH_NURI NURI 3379 +msm8960_cdp MACH_MSM8960_CDP MSM8960_CDP 3396 +msm8960_mtp MACH_MSM8960_MTP MSM8960_MTP 3397 +msm8960_fluid MACH_MSM8960_FLUID MSM8960_FLUID 3398 +msm8960_apq MACH_MSM8960_APQ MSM8960_APQ 3399 origen MACH_ORIGEN ORIGEN 3455 nspire MACH_NSPIRE NSPIRE 3503 nokia_rm696 MACH_NOKIA_RM696 NOKIA_RM696 3522 mikrap_x168 MACH_MIKRAP_X168 MIKRAP_X168 3543 deto_macarm9 MACH_DETO_MACARM9 DETO_MACARM9 3568 +msm8x60_dragon MACH_MSM8X60_DRAGON MSM8X60_DRAGON 3586 m28evk MACH_M28EVK M28EVK 3613 kota2 MACH_KOTA2 KOTA2 3616 bonito MACH_BONITO BONITO 3623 omap3_egf MACH_OMAP3_EGF OMAP3_EGF 3637 smdk4212 MACH_SMDK4212 SMDK4212 3638 apx4devkit MACH_APX4DEVKIT APX4DEVKIT 3712 +msm9615_cdp MACH_MSM9615_CDP MSM9615_CDP 3675 +msm9615_mtp MACH_MSM9615_MTP MSM9615_MTP 3681 +msm8930_cdp MACH_MSM8930_CDP MSM8930_CDP 3727 +msm8930_mtp MACH_MSM8930_MTP MSM8930_MTP 3728 +msm8930_fluid MACH_MSM8930_FLUID MSM8930_FLUID 3729 +msm7627a_qrd1 MACH_MSM7627A_QRD1 MSM7627A_QRD1 3756 smdk4412 MACH_SMDK4412 SMDK4412 3765 marzen MACH_MARZEN MARZEN 3790 krome MACH_KROME KROME 3797 @@ -1007,3 +1028,19 @@ eco5_bx2 MACH_ECO5_BX2 ECO5_BX2 4572 eukrea_cpuimx28sd MACH_EUKREA_CPUIMX28SD EUKREA_CPUIMX28SD 4573 domotab MACH_DOMOTAB DOMOTAB 4574 pfla03 MACH_PFLA03 PFLA03 4575 +msm8625_rumi3 MACH_MSM8625_RUMI3 MSM8625_RUMI3 3871 +msm7627a_evb MACH_MSM7627A_EVB MSM7627A_EVB 3934 +apq8064_cdp MACH_APQ8064_CDP APQ8064_CDP 3948 +apq8064_mtp MACH_APQ8064_MTP APQ8064_MTP 3949 +apq8064_liquid MACH_APQ8064_LIQUID APQ8064_LIQUID 3951 +mpq8064_cdp MACH_MPQ8064_CDP MPQ8064_CDP 3993 +mpq8064_hrd MACH_MPQ8064_HRD MPQ8064_HRD 3994 +mpq8064_dtv MACH_MPQ8064_DTV MPQ8064_DTV 3995 +fsm8064_ep MACH_FSM8064_EP FSM8064_EP 3996 +msm7627a_qrd3 MACH_MSM7627A_QRD3 MSM7627A_QRD3 4005 +msm8625_surf MACH_MSM8625_SURF MSM8625_SURF 4037 +msm8625_evb MACH_MSM8625_EVB MSM8625_EVB 4042 +msm8625_qrd7 MACH_MSM8625_QRD7 MSM8625_QRD7 4095 +msm8625_ffa MACH_MSM8625_FFA MSM8625_FFA 4166 +msm8625_evt MACH_MSM8625_EVT MSM8625_EVT 4193 +qrd_skud_prime MACH_QRD_SKUD_PRIME QRD_SKUD_PRIME 4393 diff --git a/drivers/Makefile b/drivers/Makefile index ebee55537a05..fd1e9d72f81e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -7,6 +7,9 @@ obj-y += irqchip/ obj-y += bus/ +obj-y += soc/ + + obj-$(CONFIG_GENERIC_PHY) += phy/ diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 6922cd6850a2..508151a19485 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ attribute_container.o transport_class.o \ topology.o container.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o -obj-$(CONFIG_DMA_CMA) += dma-contiguous.o +obj-$(CONFIG_DMA_CMA) += dma-contiguous.o dma-removed.o obj-y += power/ obj-$(CONFIG_HAS_DMA) += dma-mapping.o obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 950fff9ce453..5d3c70d31aa1 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -9,6 +9,9 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License or (at your optional) any later version of the license. + * + * The Linux Foundation chooses to take subject only to the GPLv2 license + * terms, and distributes only under these terms. */ #define pr_fmt(fmt) "cma: " fmt @@ -24,9 +27,70 @@ #include <linux/memblock.h> #include <linux/err.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> +#include <linux/mm.h> +#include <linux/mutex.h> +#include <linux/page-isolation.h> #include <linux/sizes.h> #include <linux/dma-contiguous.h> #include <linux/cma.h> +#include <linux/dma-removed.h> +#include <trace/events/kmem.h> + +struct cma { + unsigned long base_pfn; + unsigned long count; + unsigned long *bitmap; + bool in_system; + struct mutex lock; +}; + +static DEFINE_MUTEX(cma_mutex); + +struct cma *dma_contiguous_def_area; +phys_addr_t dma_contiguous_def_base; + +static struct cma_area { + phys_addr_t base; + unsigned long size; + struct cma *cma; + const char *name; + bool to_system; +} cma_areas[MAX_CMA_AREAS]; +static unsigned cma_area_count; + + +static struct cma_map { + phys_addr_t base; + struct device *dev; +} cma_maps[MAX_CMA_AREAS] __initdata; +static unsigned cma_map_count __initdata; + +static struct cma *cma_get_area(phys_addr_t base) +{ + int i; + for (i = 0; i < cma_area_count; i++) + if (cma_areas[i].base == base) + return cma_areas[i].cma; + return NULL; +} + +static struct cma *cma_get_area_by_name(const char *name) +{ + int i; + if (!name) + return NULL; + + for (i = 0; i < cma_area_count; i++) + if (cma_areas[i].name && strcmp(cma_areas[i].name, name) == 0) + return cma_areas[i].cma; + return NULL; +} + + +>>>>>>> patched #ifdef CONFIG_CMA_SIZE_MBYTES #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES @@ -34,8 +98,16 @@ #define CMA_SIZE_MBYTES 0 #endif +<<<<<<< current struct cma *dma_contiguous_default_area; +======= +#ifdef CONFIG_CMA_RESERVE_DEFAULT_AREA +#define CMA_RESERVE_AREA 1 +#else +#define CMA_RESERVE_AREA 0 +#endif +>>>>>>> patched /* * Default global CMA area size can be defined in kernel's .config. * This is useful mainly for distro maintainers to create a kernel @@ -95,6 +167,7 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void) #endif +<<<<<<< current /** * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling * @limit: End address of the reserved memory (optional, 0 for any). @@ -146,6 +219,181 @@ void __init dma_contiguous_reserve(phys_addr_t limit) * dma_contiguous_reserve_area() - reserve custom contiguous area * @size: Size of the reserved area (in bytes), * @base: Base address of the reserved area optional, use 0 for any +======= +static __init int cma_activate_area(unsigned long base_pfn, unsigned long count) +{ + unsigned long pfn = base_pfn; + unsigned i = count >> pageblock_order; + struct zone *zone; + + WARN_ON_ONCE(!pfn_valid(pfn)); + zone = page_zone(pfn_to_page(pfn)); + + do { + unsigned j; + base_pfn = pfn; + for (j = pageblock_nr_pages; j; --j, pfn++) { + WARN_ON_ONCE(!pfn_valid(pfn)); + if (page_zone(pfn_to_page(pfn)) != zone) + return -EINVAL; + } + init_cma_reserved_pageblock(pfn_to_page(base_pfn)); + } while (--i); + return 0; +} + +static __init struct cma *cma_create_area(unsigned long base_pfn, + unsigned long count, bool system) +{ + int bitmap_size = BITS_TO_LONGS(count) * sizeof(long); + struct cma *cma; + int ret = -ENOMEM; + + pr_debug("%s(base %08lx, count %lx)\n", __func__, base_pfn, count); + + cma = kmalloc(sizeof *cma, GFP_KERNEL); + if (!cma) + return ERR_PTR(-ENOMEM); + + cma->base_pfn = base_pfn; + cma->count = count; + cma->in_system = system; + cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + + if (!cma->bitmap) + goto no_mem; + + if (cma->in_system) { + ret = cma_activate_area(base_pfn, count); + if (ret) + goto error; + } + mutex_init(&cma->lock); + + pr_debug("%s: returned %p\n", __func__, (void *)cma); + return cma; + +error: + kfree(cma->bitmap); +no_mem: + kfree(cma); + return ERR_PTR(ret); +} + +/*****************************************************************************/ + +#ifdef CONFIG_OF +int __init cma_fdt_scan(unsigned long node, const char *uname, + int depth, void *data) +{ + phys_addr_t base, size; + unsigned long len; + __be32 *prop; + char *name; + bool in_system; + bool remove; + unsigned long size_cells = dt_root_size_cells; + unsigned long addr_cells = dt_root_addr_cells; + phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE; + char *status; + + if (!of_get_flat_dt_prop(node, "linux,reserve-contiguous-region", NULL)) + return 0; + + status = of_get_flat_dt_prop(node, "status", NULL); + /* + * Yes, we actually want strncmp here to check for a prefix + * ok vs. okay + */ + if (status && (strncmp(status, "ok", 2) != 0)) + return 0; + + prop = of_get_flat_dt_prop(node, "#size-cells", NULL); + if (prop) + size_cells = be32_to_cpup(prop); + + prop = of_get_flat_dt_prop(node, "#address-cells", NULL); + if (prop) + addr_cells = be32_to_cpup(prop); + + prop = of_get_flat_dt_prop(node, "reg", &len); + if (!prop || depth != 2) + return 0; + + base = dt_mem_next_cell(addr_cells, &prop); + size = dt_mem_next_cell(size_cells, &prop); + + name = of_get_flat_dt_prop(node, "label", NULL); + in_system = + of_get_flat_dt_prop(node, "linux,reserve-region", NULL) ? 0 : 1; + + prop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); + if (prop) + limit = be32_to_cpu(prop[0]); + + remove = + of_get_flat_dt_prop(node, "linux,remove-completely", NULL) ? 1 : 0; + + pr_info("Found %s, memory base %pa, size %ld MiB, limit %pa\n", uname, + &base, (unsigned long)size / SZ_1M, &limit); + dma_contiguous_reserve_area(size, &base, limit, name, + in_system, remove); + + return 0; +} +#endif + +/** + * dma_contiguous_reserve() - reserve area for contiguous memory handling + * @limit: End address of the reserved memory (optional, 0 for any). + * + * This function reserves memory from early allocator. It should be + * called by arch specific code once the early allocator (memblock or bootmem) + * has been activated and all other subsystems have already allocated/reserved + * memory. It reserves contiguous areas for global, device independent + * allocations and (optionally) all areas defined in device tree structures. + */ +void __init dma_contiguous_reserve(phys_addr_t limit) +{ + phys_addr_t sel_size = 0; + + pr_debug("%s(limit %pa)\n", __func__, &limit); + + if (size_cmdline != -1) { + sel_size = size_cmdline; + } else { +#ifdef CONFIG_CMA_SIZE_SEL_MBYTES + sel_size = size_bytes; +#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE) + sel_size = cma_early_percent_memory(); +#elif defined(CONFIG_CMA_SIZE_SEL_MIN) + sel_size = min(size_bytes, cma_early_percent_memory()); +#elif defined(CONFIG_CMA_SIZE_SEL_MAX) + sel_size = max(size_bytes, cma_early_percent_memory()); +#endif + } + + if (sel_size) { + phys_addr_t base = 0; + pr_debug("%s: reserving %ld MiB for global area\n", __func__, + (unsigned long)sel_size / SZ_1M); + + if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL, + CMA_RESERVE_AREA ? 0 : 1, false) == 0) + dma_contiguous_def_base = base; + } +#ifdef CONFIG_OF + of_scan_flat_dt(cma_fdt_scan, NULL); +#endif +}; + +/** + * dma_contiguous_reserve_area() - reserve custom contiguous area + * @size: Size of the reserved area (in bytes), + * @base: Pointer to the base address of the reserved area, also used to return + * base address of the actually reserved area, optional, use pointer to + * 0 for any +>>>>>>> patched * @limit: End address of the reserved memory (optional, 0 for any). * @res_cma: Pointer to store the created cma region. * @fixed: hint about where to place the reserved area @@ -156,6 +404,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit) * memory. This function allows to create custom reserved areas for specific * devices. * +<<<<<<< current * If @fixed is true, reserve contiguous area at exactly @base. If false, * reserve in range from @base to @limit. */ @@ -174,6 +423,200 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, cma_get_size(*res_cma)); return 0; +======= + * This function reserves memory from early allocator. It should be + * called by arch specific code once the early allocator (memblock or bootmem) + * has been activated and all other subsystems have already allocated/reserved + * memory. This function allows to create custom reserved areas for specific + * devices. + */ +int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, + phys_addr_t limit, const char *name, + bool to_system, bool remove) +{ + phys_addr_t base = *res_base; + phys_addr_t alignment = PAGE_SIZE; + int ret = 0; + + pr_debug("%s(size %lx, base %pa, limit %pa)\n", __func__, + (unsigned long)size, &base, + &limit); + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err("Not enough slots for CMA reserved regions!\n"); + return -ENOSPC; + } + + if (!size) + return -EINVAL; + + /* Sanitise input arguments */ + if (!remove) + alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); + base = ALIGN(base, alignment); + size = ALIGN(size, alignment); + limit &= ~(alignment - 1); + + /* Reserve memory */ + if (base) { + if (memblock_is_region_reserved(base, size) || + memblock_reserve(base, size) < 0) { + ret = -EBUSY; + goto err; + } + } else { + /* + * Use __memblock_alloc_base() since + * memblock_alloc_base() panic()s. + */ + phys_addr_t addr = __memblock_alloc_base(size, alignment, limit); + if (!addr) { + ret = -ENOMEM; + goto err; + } else { + base = addr; + } + } + + if (remove) { + if (!to_system) { + memblock_free(base, size); + memblock_remove(base, size); + } else { + WARN(1, "Removing is incompatible with staying in the system\n"); + } + } + + /* + * Each reserved area must be initialised later, when more kernel + * subsystems (like slab allocator) are available. + */ + cma_areas[cma_area_count].base = base; + cma_areas[cma_area_count].size = size; + cma_areas[cma_area_count].name = name; + cma_areas[cma_area_count].to_system = to_system; + cma_area_count++; + *res_base = base; + + pr_info("CMA: reserved %ld MiB at %pa\n", (unsigned long)size / SZ_1M, + &base); + + /* Architecture specific contiguous memory fixup. */ + if (!remove) + dma_contiguous_early_fixup(base, size); + return 0; +err: + pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); + return ret; +} + +/** + * dma_contiguous_add_device() - add device to custom contiguous reserved area + * @dev: Pointer to device structure. + * @base: Pointer to the base address of the reserved area returned by + * dma_contiguous_reserve_area() function, also used to return + * + * This function assigns the given device to the contiguous memory area + * reserved earlier by dma_contiguous_reserve_area() function. + */ +int __init dma_contiguous_add_device(struct device *dev, phys_addr_t base) +{ + if (cma_map_count == ARRAY_SIZE(cma_maps)) { + pr_err("Not enough slots for CMA reserved regions!\n"); + return -ENOSPC; + } + cma_maps[cma_map_count].dev = dev; + cma_maps[cma_map_count].base = base; + cma_map_count++; + return 0; +} + +#ifdef CONFIG_OF +static void cma_assign_device_from_dt(struct device *dev) +{ + struct device_node *node; + struct cma *cma; + const char *name; + u32 value; + + node = of_parse_phandle(dev->of_node, "linux,contiguous-region", 0); + if (!node) + return; + if (of_property_read_u32(node, "reg", &value) && !value) + return; + + if (of_property_read_string(node, "label", &name)) + return; + + cma = cma_get_area_by_name(name); + if (!cma) + return; + + dev_set_cma_area(dev, cma); + + if (of_property_read_bool(node, "linux,remove-completely")) + set_dma_ops(dev, &removed_dma_ops); + + pr_info("Assigned CMA region at %lx to %s device\n", (unsigned long)value, dev_name(dev)); +} + +static int cma_device_init_notifier_call(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct device *dev = data; + if (event == BUS_NOTIFY_ADD_DEVICE && dev->of_node) + cma_assign_device_from_dt(dev); + return NOTIFY_DONE; +} + +static struct notifier_block cma_dev_init_nb = { + .notifier_call = cma_device_init_notifier_call, +}; +#endif + +static int __init cma_init_reserved_areas(void) +{ + struct cma *cma; + int i; + + for (i = 0; i < cma_area_count; i++) { + phys_addr_t base = PFN_DOWN(cma_areas[i].base); + unsigned int count = cma_areas[i].size >> PAGE_SHIFT; + bool system = cma_areas[i].to_system; + + cma = cma_create_area(base, count, system); + if (!IS_ERR(cma)) + cma_areas[i].cma = cma; + } + + dma_contiguous_def_area = cma_get_area(dma_contiguous_def_base); + + for (i = 0; i < cma_map_count; i++) { + cma = cma_get_area(cma_maps[i].base); + dev_set_cma_area(cma_maps[i].dev, cma); + } + +#ifdef CONFIG_OF + bus_register_notifier(&platform_bus_type, &cma_dev_init_nb); +#endif + return 0; +} +core_initcall(cma_init_reserved_areas); + +phys_addr_t cma_get_base(struct device *dev) +{ + struct cma *cma = dev_get_cma_area(dev); + + return cma->base_pfn << PAGE_SHIFT; +} + +static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count) +{ + mutex_lock(&cma->lock); + bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count); + mutex_unlock(&cma->lock); +>>>>>>> patched } /** @@ -187,13 +630,77 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, * global one. Requires architecture specific dev_get_cma_area() helper * function. */ -struct page *dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, int count, unsigned int align) { +<<<<<<< current if (align > CONFIG_CMA_ALIGNMENT) align = CONFIG_CMA_ALIGNMENT; return cma_alloc(dev_get_cma_area(dev), count, align); +======= + unsigned long mask, pfn = 0, pageno, start = 0; + struct cma *cma = dev_get_cma_area(dev); + int ret = 0; + int tries = 0; + + if (!cma || !cma->count) + return 0; + + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + + pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma, + count, align); + + if (!count) + return 0; + + mask = (1 << align) - 1; + + + for (;;) { + mutex_lock(&cma->lock); + pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count, + start, count, mask); + if (pageno >= cma->count) { + pfn = 0; + mutex_unlock(&cma->lock); + break; + } + bitmap_set(cma->bitmap, pageno, count); + /* + * It's safe to drop the lock here. We've marked this region for + * our exclusive use. If the migration fails we will take the + * lock again and unmark it. + */ + mutex_unlock(&cma->lock); + + pfn = cma->base_pfn + pageno; + if (cma->in_system) { + mutex_lock(&cma_mutex); + ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA); + mutex_unlock(&cma_mutex); + } + if (ret == 0) { + break; + } else if (ret != -EBUSY) { + pfn = 0; + clear_cma_bitmap(cma, pfn, count); + break; + } + clear_cma_bitmap(cma, pfn, count); + tries++; + + pr_debug("%s(): memory range at %p is busy, retrying\n", + __func__, pfn_to_page(pfn)); + /* try again with a bit different memory target */ + start = pageno + mask + 1; + } + + pr_debug("%s(): returned %lx\n", __func__, pfn); + return pfn; +>>>>>>> patched } /** @@ -206,9 +713,10 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count, * It returns false when provided pages do not belong to contiguous area and * true otherwise. */ -bool dma_release_from_contiguous(struct device *dev, struct page *pages, +bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, int count) { +<<<<<<< current return cma_release(dev_get_cma_area(dev), pages, count); } @@ -228,6 +736,14 @@ static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev) dev_set_cma_area(dev, rmem->priv); return 0; } +======= + struct cma *cma = dev_get_cma_area(dev); + + if (!cma || !pfn) + return false; + + pr_debug("%s(pfn %lx)\n", __func__, pfn); +>>>>>>> patched static void rmem_cma_device_release(struct reserved_mem *rmem, struct device *dev) @@ -248,9 +764,15 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) struct cma *cma; int err; +<<<<<<< current if (!of_get_flat_dt_prop(node, "reusable", NULL) || of_get_flat_dt_prop(node, "no-map", NULL)) return -EINVAL; +======= + if (cma->in_system) + free_contig_range(pfn, count); + clear_cma_bitmap(cma, pfn, count); +>>>>>>> patched if ((rmem->base & mask) || (rmem->size & mask)) { pr_err("Reserved memory: incorrect alignment of CMA region\n"); diff --git a/drivers/base/dma-removed.c b/drivers/base/dma-removed.c new file mode 100644 index 000000000000..45c0bf0c05e5 --- /dev/null +++ b/drivers/base/dma-removed.c @@ -0,0 +1,162 @@ +/* + * + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (C) 2000-2004 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/gfp.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> +#include <linux/highmem.h> +#include <linux/memblock.h> +#include <linux/slab.h> +#include <linux/iommu.h> +#include <linux/io.h> +#include <linux/vmalloc.h> +#include <linux/sizes.h> + +#define NO_KERNEL_MAPPING_DUMMY 0x2222 + +void *removed_alloc(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp, struct dma_attrs *attrs) +{ + bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, + attrs); + bool skip_zeroing = dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs); + unsigned long pfn; + unsigned long order = get_order(size); + void *addr = NULL; + + size = PAGE_ALIGN(size); + + if (!(gfp & __GFP_WAIT)) + return NULL; + + pfn = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, order); + + if (pfn) { + if (no_kernel_mapping && skip_zeroing) { + *handle = __pfn_to_phys(pfn); + return (void *)NO_KERNEL_MAPPING_DUMMY; + } + + addr = ioremap(__pfn_to_phys(pfn), size); + if (WARN_ON(!addr)) { + dma_release_from_contiguous(dev, pfn, order); + } else { + if (!skip_zeroing) + memset(addr, 0, size); + if (no_kernel_mapping) { + iounmap(addr); + addr = (void *)NO_KERNEL_MAPPING_DUMMY; + } + *handle = __pfn_to_phys(pfn); + } + } + + return addr; +} + + +int removed_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) +{ + return -ENXIO; +} + +void removed_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, struct dma_attrs *attrs) +{ + bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, + attrs); + + if (!no_kernel_mapping) + iounmap(cpu_addr); + dma_release_from_contiguous(dev, __phys_to_pfn(handle), + size >> PAGE_SHIFT); +} + +static dma_addr_t removed_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return ~(dma_addr_t)0; +} + +static void removed_unmap_page(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return; +} + +static int removed_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return 0; +} + +static void removed_unmap_sg(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return; +} + +static void removed_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir) +{ + return; +} + +void removed_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir) +{ + return; +} + +void removed_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + return; +} + +void removed_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + return; +} + +struct dma_map_ops removed_dma_ops = { + .alloc = removed_alloc, + .free = removed_free, + .mmap = removed_mmap, + .map_page = removed_map_page, + .unmap_page = removed_unmap_page, + .map_sg = removed_map_sg, + .unmap_sg = removed_unmap_sg, + .sync_single_for_cpu = removed_sync_single_for_cpu, + .sync_single_for_device = removed_sync_single_for_device, + .sync_sg_for_cpu = removed_sync_sg_for_cpu, + .sync_sg_for_device = removed_sync_sg_for_device, +}; +EXPORT_SYMBOL(removed_dma_ops); + + diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index 098c542e5c53..86e70efc9bb7 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -1,5 +1,4 @@ /* - * * Copyright (C) 2007 Google, Inc. * Copyright (c) 2009-2012,2014, The Linux Foundation. All rights reserved. * @@ -14,36 +13,196 @@ * */ +#include <linux/module.h> #include <linux/clocksource.h> #include <linux/clockchips.h> #include <linux/cpu.h> #include <linux/init.h> +#include <linux/time.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/delay.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/sched_clock.h> #include <asm/delay.h> +#include <linux/percpu.h> +#include <linux/mm.h> +#include <linux/sched_clock.h> + +#include <asm/localtimer.h> +#include <asm/mach/time.h> +#include <asm/smp_plat.h> +#include <asm/user_accessible_timer.h> +#include <mach/msm_iomap.h> +#include <mach/irqs.h> +#include <soc/qcom/socinfo.h> + +#include <soc/qcom/smem.h> +#if defined(CONFIG_MSM_SMD) +#include <soc/qcom/smsm.h> +#endif +#include "timer.h" + +enum { + MSM_TIMER_DEBUG_SYNC = 1U << 0, +}; +static int msm_timer_debug_mask; +module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); + +#ifdef CONFIG_MSM7X00A_USE_GP_TIMER + #define DG_TIMER_RATING 100 +#else + #define DG_TIMER_RATING 300 +#endif + +#ifndef MSM_TMR0_BASE +#define MSM_TMR0_BASE MSM_TMR_BASE +#endif + +#define MSM_DGT_SHIFT (5) + +#define TIMER_MATCH_VAL 0x0000 +#define TIMER_COUNT_VAL 0x0004 +#define TIMER_ENABLE 0x0008 +#define TIMER_CLEAR 0x000C +#define DGT_CLK_CTL 0x0034 +enum { + DGT_CLK_CTL_DIV_1 = 0, + DGT_CLK_CTL_DIV_2 = 1, + DGT_CLK_CTL_DIV_3 = 2, + DGT_CLK_CTL_DIV_4 = 3, +}; +#define TIMER_STATUS 0x0088 +#define TIMER_ENABLE_EN 1 +#define TIMER_ENABLE_CLR_ON_MATCH_EN 2 + +#define LOCAL_TIMER 0 +#define GLOBAL_TIMER 1 -#define TIMER_MATCH_VAL 0x0000 -#define TIMER_COUNT_VAL 0x0004 -#define TIMER_ENABLE 0x0008 -#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) -#define TIMER_ENABLE_EN BIT(0) -#define TIMER_CLEAR 0x000C -#define DGT_CLK_CTL 0x10 -#define DGT_CLK_CTL_DIV_4 0x3 -#define TIMER_STS_GPT0_CLR_PEND BIT(10) +/* + * global_timer_offset is added to the regbase of a timer to force the memory + * access to come from the CPU0 region. + */ +static int global_timer_offset; +static int msm_global_timer; + +#define NR_TIMERS ARRAY_SIZE(msm_clocks) -#define GPT_HZ 32768 +unsigned int gpt_hz = 32768; +unsigned int sclk_hz = 32768; -#define MSM_DGT_SHIFT 5 +static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt); +static irqreturn_t msm_timer_interrupt(int irq, void *dev_id); +static cycle_t msm_gpt_read(struct clocksource *cs); +static cycle_t msm_dgt_read(struct clocksource *cs); +static void msm_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt); +static int msm_timer_set_next_event(unsigned long cycles, + struct clock_event_device *evt); + +enum { + MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0, + MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1, + MSM_CLOCK_FLAGS_DELAYED_WRITE_POST = 1U << 2, +}; + +struct msm_clock { + struct clock_event_device clockevent; + struct clocksource clocksource; + unsigned int irq; + void __iomem *regbase; + uint32_t freq; + uint32_t shift; + uint32_t flags; + uint32_t write_delay; + uint32_t rollover_offset; + uint32_t index; + void __iomem *global_counter; + void __iomem *local_counter; + uint32_t status_mask; + union { + struct clock_event_device *evt; + struct clock_event_device __percpu **percpu_evt; + }; +}; -static void __iomem *event_base; -static void __iomem *sts_base; +enum { + MSM_CLOCK_GPT, + MSM_CLOCK_DGT, +}; + +struct msm_clock_percpu_data { + uint32_t last_set; + uint32_t sleep_offset; + uint32_t alarm_vtime; + uint32_t alarm; + uint32_t non_sleep_offset; + uint32_t in_sync; + cycle_t stopped_tick; + int stopped; + uint32_t last_sync_gpt; + u64 last_sync_jiffies; +}; + +struct msm_timer_sync_data_t { + struct msm_clock *clock; + uint32_t timeout; + int exit_sleep; +}; + +static struct msm_clock msm_clocks[] = { + [MSM_CLOCK_GPT] = { + .clockevent = { + .name = "gp_timer", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .rating = 200, + .set_next_event = msm_timer_set_next_event, + .set_mode = msm_timer_set_mode, + }, + .clocksource = { + .name = "gp_timer", + .rating = 200, + .read = msm_gpt_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, + .irq = INT_GP_TIMER_EXP, + .regbase = MSM_TMR_BASE + 0x4, + .freq = 32768, + .index = MSM_CLOCK_GPT, + .write_delay = 9, + }, + [MSM_CLOCK_DGT] = { + .clockevent = { + .name = "dg_timer", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .rating = DG_TIMER_RATING, + .set_next_event = msm_timer_set_next_event, + .set_mode = msm_timer_set_mode, + }, + .clocksource = { + .name = "dg_timer", + .rating = DG_TIMER_RATING, + .read = msm_dgt_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, + .irq = INT_DEBUG_TIMER_EXP, + .regbase = MSM_TMR_BASE + 0x24, + .index = MSM_CLOCK_DGT, + .write_delay = 9, + } +}; + +static DEFINE_PER_CPU(struct msm_clock_percpu_data[NR_TIMERS], + msm_clocks_percpu); + +static DEFINE_PER_CPU(struct msm_clock *, msm_active_clock); static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { @@ -58,45 +217,182 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static uint32_t msm_read_timer_count(struct msm_clock *clock, int global) +{ + uint32_t t1, t2, t3; + int loop_count = 0; + void __iomem *addr = clock->regbase + TIMER_COUNT_VAL + + global*global_timer_offset; + + if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT)) + return __raw_readl_no_log(addr); + + t1 = __raw_readl_no_log(addr); + t2 = __raw_readl_no_log(addr); + if ((t2-t1) <= 1) + return t2; + while (1) { + t1 = __raw_readl_no_log(addr); + t2 = __raw_readl_no_log(addr); + t3 = __raw_readl_no_log(addr); + cpu_relax(); + if ((t3-t2) <= 1) + return t3; + if ((t2-t1) <= 1) + return t2; + if ((t2 >= t1) && (t3 >= t2)) + return t2; + if (++loop_count == 5) { + pr_err("msm_read_timer_count timer %s did not " + "stabilize: %u -> %u -> %u\n", + clock->clockevent.name, t1, t2, t3); + return t3; + } + } +} + +static cycle_t msm_gpt_read(struct clocksource *cs) +{ + struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT]; + struct msm_clock_percpu_data *clock_state = + &per_cpu(msm_clocks_percpu, 0)[MSM_CLOCK_GPT]; + + if (clock_state->stopped) + return clock_state->stopped_tick; + + return msm_read_timer_count(clock, GLOBAL_TIMER) + + clock_state->sleep_offset; +} + +static cycle_t msm_dgt_read(struct clocksource *cs) +{ + struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT]; + struct msm_clock_percpu_data *clock_state = + &per_cpu(msm_clocks_percpu, 0)[MSM_CLOCK_DGT]; + + if (clock_state->stopped) + return clock_state->stopped_tick >> clock->shift; + + return (msm_read_timer_count(clock, GLOBAL_TIMER) + + clock_state->sleep_offset) >> clock->shift; +} + +static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt) +{ + int i; + + if (!is_smp()) + return container_of(evt, struct msm_clock, clockevent); + + for (i = 0; i < NR_TIMERS; i++) + if (evt == &(msm_clocks[i].clockevent)) + return &msm_clocks[i]; + return &msm_clocks[msm_global_timer]; +} + static int msm_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); + int i; + struct msm_clock *clock; + struct msm_clock_percpu_data *clock_state; + uint32_t now; + uint32_t alarm; + int late; - ctrl &= ~TIMER_ENABLE_EN; - writel_relaxed(ctrl, event_base + TIMER_ENABLE); + clock = clockevent_to_clock(evt); + clock_state = &__get_cpu_var(msm_clocks_percpu)[clock->index]; + now = msm_read_timer_count(clock, LOCAL_TIMER); + alarm = now + (cycles << clock->shift); + if (clock->flags & MSM_CLOCK_FLAGS_ODD_MATCH_WRITE) + while (now == clock_state->last_set) + now = msm_read_timer_count(clock, LOCAL_TIMER); - writel_relaxed(ctrl, event_base + TIMER_CLEAR); - writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); + clock_state->alarm = alarm; + __raw_writel(alarm, clock->regbase + TIMER_MATCH_VAL); - if (sts_base) - while (readl_relaxed(sts_base) & TIMER_STS_GPT0_CLR_PEND) - cpu_relax(); + if (clock->flags & MSM_CLOCK_FLAGS_DELAYED_WRITE_POST) { + /* read the counter four extra times to make sure write posts + before reading the time */ + for (i = 0; i < 4; i++) + __raw_readl_no_log(clock->regbase + TIMER_COUNT_VAL); + } + now = msm_read_timer_count(clock, LOCAL_TIMER); + clock_state->last_set = now; + clock_state->alarm_vtime = alarm + clock_state->sleep_offset; + late = now - alarm; + if (late >= (int)(-clock->write_delay << clock->shift) && + late < clock->freq*5) + return -ETIME; - writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); return 0; } static void msm_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) + struct clock_event_device *evt) { - u32 ctrl; + struct msm_clock *clock; + struct msm_clock **cur_clock; + struct msm_clock_percpu_data *clock_state, *gpt_state; + unsigned long irq_flags; + struct irq_chip *chip; - ctrl = readl_relaxed(event_base + TIMER_ENABLE); - ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); + clock = clockevent_to_clock(evt); + clock_state = &__get_cpu_var(msm_clocks_percpu)[clock->index]; + gpt_state = &__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT]; + + local_irq_save(irq_flags); switch (mode) { case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_PERIODIC: break; case CLOCK_EVT_MODE_ONESHOT: - /* Timer is enabled in set_next_event */ + clock_state->stopped = 0; + clock_state->sleep_offset = + -msm_read_timer_count(clock, LOCAL_TIMER) + + clock_state->stopped_tick; + get_cpu_var(msm_active_clock) = clock; + put_cpu_var(msm_active_clock); + __raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + chip = irq_get_chip(clock->irq); + if (chip && chip->irq_unmask) + chip->irq_unmask(irq_get_irq_data(clock->irq)); + if (clock != &msm_clocks[MSM_CLOCK_GPT]) + __raw_writel(TIMER_ENABLE_EN, + msm_clocks[MSM_CLOCK_GPT].regbase + + TIMER_ENABLE); break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: + cur_clock = &get_cpu_var(msm_active_clock); + if (*cur_clock == clock) + *cur_clock = NULL; + put_cpu_var(msm_active_clock); + clock_state->in_sync = 0; + clock_state->stopped = 1; + clock_state->stopped_tick = + msm_read_timer_count(clock, LOCAL_TIMER) + + clock_state->sleep_offset; + __raw_writel(0, clock->regbase + TIMER_MATCH_VAL); + chip = irq_get_chip(clock->irq); + if (chip && chip->irq_mask) + chip->irq_mask(irq_get_irq_data(clock->irq)); + + if (!is_smp() || clock != &msm_clocks[MSM_CLOCK_DGT] + || smp_processor_id()) + __raw_writel(0, clock->regbase + TIMER_ENABLE); + + if (msm_global_timer == MSM_CLOCK_DGT && + clock != &msm_clocks[MSM_CLOCK_GPT]) { + gpt_state->in_sync = 0; + __raw_writel(0, msm_clocks[MSM_CLOCK_GPT].regbase + + TIMER_ENABLE); + } break; } - writel_relaxed(ctrl, event_base + TIMER_ENABLE); + wmb(); + local_irq_restore(irq_flags); } static struct clock_event_device __percpu *msm_evt; @@ -104,8 +400,10 @@ static struct clock_event_device __percpu *msm_evt; static void __iomem *source_base; static notrace cycle_t msm_read_timer_count(struct clocksource *cs) + +void __iomem *msm_timer_get_timer0_base(void) { - return readl_relaxed(source_base + TIMER_COUNT_VAL); + return MSM_TMR_BASE + global_timer_offset; } static struct clocksource msm_clocksource = { @@ -147,12 +445,77 @@ static int msm_local_timer_setup(struct clock_event_device *evt) return 0; } -static void msm_local_timer_stop(struct clock_event_device *evt) +#define MPM_SCLK_COUNT_VAL 0x0024 + +#ifdef CONFIG_PM +/* + * Retrieve the cycle count from sclk and optionally synchronize local clock + * with the sclk value. + * + * time_start and time_expired are callbacks that must be specified. The + * protocol uses them to detect timeout. The update callback is optional. + * If not NULL, update will be called so that it can update local clock. + * + * The function does not use the argument data directly; it passes data to + * the callbacks. + * + * Return value: + * 0: the operation failed + * >0: the slow clock value after time-sync + */ +static void (*msm_timer_sync_timeout)(void); +#if defined(CONFIG_MSM_DIRECT_SCLK_ACCESS) +uint32_t msm_timer_get_sclk_ticks(void) { - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); - disable_percpu_irq(evt->irq); + uint32_t t1, t2; + int loop_count = 10; + int loop_zero_count = 3; + int tmp = USEC_PER_SEC; + do_div(tmp, sclk_hz); + tmp /= (loop_zero_count-1); + + while (loop_zero_count--) { + t1 = __raw_readl_no_log(MSM_RPM_MPM_BASE + MPM_SCLK_COUNT_VAL); + do { + udelay(1); + t2 = t1; + t1 = __raw_readl_no_log( + MSM_RPM_MPM_BASE + MPM_SCLK_COUNT_VAL); + } while ((t2 != t1) && --loop_count); + + if (!loop_count) { + printk(KERN_EMERG "SCLK did not stabilize\n"); + return 0; + } + + if (t1) + break; + + udelay(tmp); + } + + if (!loop_zero_count) { + printk(KERN_EMERG "SCLK reads zero\n"); + return 0; + } + + return t1; } +static uint32_t msm_timer_do_sync_to_sclk( + void (*time_start)(struct msm_timer_sync_data_t *data), + bool (*time_expired)(struct msm_timer_sync_data_t *data), + void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t), + struct msm_timer_sync_data_t *data) +{ + unsigned t1 = msm_timer_get_sclk_ticks(); + + if (t1 && update != NULL) + update(data, t1, sclk_hz); + return t1; +} +#else + static int msm_timer_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { @@ -230,8 +593,97 @@ err: sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); msm_delay_timer.freq = dgt_hz; register_current_timer_delay(&msm_delay_timer); + +} + +/* Time Master State Bits */ +#define MASTER_BITS_PER_CPU 1 +#define MASTER_TIME_PENDING \ + (0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) + +/* Time Slave State Bits */ +#define SLAVE_TIME_REQUEST 0x0400 +#define SLAVE_TIME_POLL 0x0800 +#define SLAVE_TIME_INIT 0x1000 + +static uint32_t msm_timer_do_sync_to_sclk( + void (*time_start)(struct msm_timer_sync_data_t *data), + bool (*time_expired)(struct msm_timer_sync_data_t *data), + void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t), + struct msm_timer_sync_data_t *data) +{ + uint32_t *smem_clock; + uint32_t smem_clock_val; + uint32_t state; + + smem_clock = smem_find(SMEM_SMEM_SLOW_CLOCK_VALUE, + sizeof(uint32_t), 0, SMEM_ANY_HOST_FLAG); + if (smem_clock == NULL) { + printk(KERN_ERR "no smem clock\n"); + return 0; + } + + state = smsm_get_state(SMSM_MODEM_STATE); + if ((state & SMSM_INIT) == 0) { + printk(KERN_ERR "smsm not initialized\n"); + return 0; + } + + time_start(data); + while ((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & + MASTER_TIME_PENDING) { + if (time_expired(data)) { + printk(KERN_EMERG "get_smem_clock: timeout 1 still " + "invalid state %x\n", state); + msm_timer_sync_timeout(); + } + } + + smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_POLL | SLAVE_TIME_INIT, + SLAVE_TIME_REQUEST); + + time_start(data); + while (!((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & + MASTER_TIME_PENDING)) { + if (time_expired(data)) { + printk(KERN_EMERG "get_smem_clock: timeout 2 still " + "invalid state %x\n", state); + msm_timer_sync_timeout(); + } + } + + smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST, SLAVE_TIME_POLL); + + time_start(data); + do { + smem_clock_val = *smem_clock; + } while (smem_clock_val == 0 && !time_expired(data)); + + state = smsm_get_state(SMSM_TIME_MASTER_DEM); + + if (smem_clock_val) { + if (update != NULL) + update(data, smem_clock_val, sclk_hz); + + if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) + printk(KERN_INFO + "get_smem_clock: state %x clock %u\n", + state, smem_clock_val); + } else { + printk(KERN_EMERG + "get_smem_clock: timeout state %x clock %u\n", + state, smem_clock_val); + msm_timer_sync_timeout(); + } + + smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, + SLAVE_TIME_INIT); + return smem_clock_val; +>>>>>>> patched:arch/arm/mach-msm/timer.c } +#endif /* CONFIG_MSM_DIRECT_SCLK_ACCESS */ +<<<<<<< current:drivers/clocksource/qcom-timer.c #ifdef CONFIG_ARCH_QCOM static void __init msm_dt_timer_init(struct device_node *np) { @@ -246,65 +698,394 @@ static void __init msm_dt_timer_init(struct device_node *np) if (!base) { pr_err("Failed to map event base\n"); return; +======= +/* + * Callback function that initializes the timeout value. + */ +static void msm_timer_sync_to_sclk_time_start( + struct msm_timer_sync_data_t *data) +{ + /* approx 2 seconds */ + uint32_t delta = data->clock->freq << data->clock->shift << 1; + data->timeout = msm_read_timer_count(data->clock, LOCAL_TIMER) + delta; +} + +/* + * Callback function that checks the timeout. + */ +static bool msm_timer_sync_to_sclk_time_expired( + struct msm_timer_sync_data_t *data) +{ + uint32_t delta = msm_read_timer_count(data->clock, LOCAL_TIMER) - + data->timeout; + return ((int32_t) delta) > 0; +} + +/* + * Callback function that updates local clock from the specified source clock + * value and frequency. + */ +static void msm_timer_sync_update(struct msm_timer_sync_data_t *data, + uint32_t src_clk_val, uint32_t src_clk_freq) +{ + struct msm_clock *dst_clk = data->clock; + struct msm_clock_percpu_data *dst_clk_state = + &__get_cpu_var(msm_clocks_percpu)[dst_clk->index]; + uint32_t dst_clk_val = msm_read_timer_count(dst_clk, LOCAL_TIMER); + uint32_t new_offset; + + if ((dst_clk->freq << dst_clk->shift) == src_clk_freq) { + new_offset = src_clk_val - dst_clk_val; + } else { + uint64_t temp; + + /* separate multiplication and division steps to reduce + rounding error */ + temp = src_clk_val; + temp *= dst_clk->freq << dst_clk->shift; + do_div(temp, src_clk_freq); + + new_offset = (uint32_t)(temp) - dst_clk_val; } - /* We use GPT0 for the clockevent */ - irq = irq_of_parse_and_map(np, 1); - if (irq <= 0) { - pr_err("Can't get irq\n"); - return; + if (dst_clk_state->sleep_offset + dst_clk_state->non_sleep_offset != + new_offset) { + if (data->exit_sleep) + dst_clk_state->sleep_offset = + new_offset - dst_clk_state->non_sleep_offset; + else + dst_clk_state->non_sleep_offset = + new_offset - dst_clk_state->sleep_offset; + + if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) + printk(KERN_INFO "sync clock %s: " + "src %u, new offset %u + %u\n", + dst_clk->clocksource.name, src_clk_val, + dst_clk_state->sleep_offset, + dst_clk_state->non_sleep_offset); +>>>>>>> patched:arch/arm/mach-msm/timer.c } +} - /* We use CPU0's DGT for the clocksource */ - if (of_property_read_u32(np, "cpu-offset", &percpu_offset)) - percpu_offset = 0; +/* + * Synchronize GPT clock with sclk. + */ +static void msm_timer_sync_gpt_to_sclk(int exit_sleep) +{ + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; + struct msm_clock_percpu_data *gpt_clk_state = + &__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT]; + struct msm_timer_sync_data_t data; + uint32_t ret; - if (of_address_to_resource(np, 0, &res)) { - pr_err("Failed to parse DGT resource\n"); + if (gpt_clk_state->in_sync) return; - } - cpu0_base = ioremap(res.start + percpu_offset, resource_size(&res)); - if (!cpu0_base) { - pr_err("Failed to map source base\n"); + data.clock = gpt_clk; + data.timeout = 0; + data.exit_sleep = exit_sleep; + + ret = msm_timer_do_sync_to_sclk( + msm_timer_sync_to_sclk_time_start, + msm_timer_sync_to_sclk_time_expired, + msm_timer_sync_update, + &data); + + if (ret) + gpt_clk_state->in_sync = 1; +} + +/* + * Synchronize clock with GPT clock. + */ +static void msm_timer_sync_to_gpt(struct msm_clock *clock, int exit_sleep) +{ + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; + struct msm_clock_percpu_data *gpt_clk_state = + &__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT]; + struct msm_clock_percpu_data *clock_state = + &__get_cpu_var(msm_clocks_percpu)[clock->index]; + struct msm_timer_sync_data_t data; + uint32_t gpt_clk_val; + u64 gpt_period = (1ULL << 32) * HZ; + u64 now = get_jiffies_64(); + + do_div(gpt_period, gpt_hz); + + BUG_ON(clock == gpt_clk); + + if (clock_state->in_sync && + (now - clock_state->last_sync_jiffies < (gpt_period >> 1))) return; + + gpt_clk_val = msm_read_timer_count(gpt_clk, LOCAL_TIMER) + + gpt_clk_state->sleep_offset + gpt_clk_state->non_sleep_offset; + + if (exit_sleep && gpt_clk_val < clock_state->last_sync_gpt) + clock_state->non_sleep_offset -= clock->rollover_offset; + + data.clock = clock; + data.timeout = 0; + data.exit_sleep = exit_sleep; + + msm_timer_sync_update(&data, gpt_clk_val, gpt_hz); + + clock_state->in_sync = 1; + clock_state->last_sync_gpt = gpt_clk_val; + clock_state->last_sync_jiffies = now; +} + +static void msm_timer_reactivate_alarm(struct msm_clock *clock) +{ + struct msm_clock_percpu_data *clock_state = + &__get_cpu_var(msm_clocks_percpu)[clock->index]; + long alarm_delta = clock_state->alarm_vtime - + clock_state->sleep_offset - + msm_read_timer_count(clock, LOCAL_TIMER); + alarm_delta >>= clock->shift; + if (alarm_delta < (long)clock->write_delay + 4) + alarm_delta = clock->write_delay + 4; + while (msm_timer_set_next_event(alarm_delta, &clock->clockevent)) + ; +} + +int64_t msm_timer_enter_idle(void) +{ + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; + struct msm_clock *clock = __get_cpu_var(msm_active_clock); + struct msm_clock_percpu_data *clock_state = + &__get_cpu_var(msm_clocks_percpu)[clock->index]; + uint32_t alarm; + uint32_t count; + int32_t delta; + + BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] && + clock != &msm_clocks[MSM_CLOCK_DGT]); + + msm_timer_sync_gpt_to_sclk(0); + if (clock != gpt_clk) + msm_timer_sync_to_gpt(clock, 0); + + count = msm_read_timer_count(clock, LOCAL_TIMER); + if (clock_state->stopped++ == 0) + clock_state->stopped_tick = count + clock_state->sleep_offset; + alarm = clock_state->alarm; + delta = alarm - count; + if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) { + /* timer should have triggered 1ms ago */ + printk(KERN_ERR "msm_timer_enter_idle: timer late %d, " + "reprogram it\n", delta); + msm_timer_reactivate_alarm(clock); } + if (delta <= 0) + return 0; + return clocksource_cyc2ns((alarm - count) >> clock->shift, + clock->clocksource.mult, + clock->clocksource.shift); +} - if (of_property_read_u32(np, "clock-frequency", &freq)) { - pr_err("Unknown frequency\n"); - return; +void msm_timer_exit_idle(int low_power) +{ + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; + struct msm_clock *clock = __get_cpu_var(msm_active_clock); + struct msm_clock_percpu_data *gpt_clk_state = + &__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT]; + struct msm_clock_percpu_data *clock_state = + &__get_cpu_var(msm_clocks_percpu)[clock->index]; + uint32_t enabled; + + BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] && + clock != &msm_clocks[MSM_CLOCK_DGT]); + + if (!low_power) + goto exit_idle_exit; + + enabled = __raw_readl(gpt_clk->regbase + TIMER_ENABLE) & + TIMER_ENABLE_EN; + if (!enabled) + __raw_writel(TIMER_ENABLE_EN, gpt_clk->regbase + TIMER_ENABLE); + +#if defined(CONFIG_ARCH_MSM_SCORPION) || defined(CONFIG_ARCH_MSM_KRAIT) + gpt_clk_state->in_sync = 0; +#else + gpt_clk_state->in_sync = gpt_clk_state->in_sync && enabled; +#endif + /* Make sure timer is actually enabled before we sync it */ + wmb(); + msm_timer_sync_gpt_to_sclk(1); + + if (clock == gpt_clk) + goto exit_idle_alarm; + + enabled = __raw_readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN; + if (!enabled) + __raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + +#if defined(CONFIG_ARCH_MSM_SCORPION) || defined(CONFIG_ARCH_MSM_KRAIT) + clock_state->in_sync = 0; +#else + clock_state->in_sync = clock_state->in_sync && enabled; +#endif + /* Make sure timer is actually enabled before we sync it */ + wmb(); + msm_timer_sync_to_gpt(clock, 1); + +exit_idle_alarm: + msm_timer_reactivate_alarm(clock); + +exit_idle_exit: + clock_state->stopped--; +} + +/* + * Callback function that initializes the timeout value. + */ +static void msm_timer_get_sclk_time_start( + struct msm_timer_sync_data_t *data) +{ + data->timeout = 200000; +} + +/* + * Callback function that checks the timeout. + */ +static bool msm_timer_get_sclk_time_expired( + struct msm_timer_sync_data_t *data) +{ + udelay(10); + return --data->timeout <= 0; +} + +/* + * Retrieve the cycle count from the sclk and convert it into + * nanoseconds. + * + * On exit, if period is not NULL, it contains the period of the + * sclk in nanoseconds, i.e. how long the cycle count wraps around. + * + * Return value: + * 0: the operation failed; period is not set either + * >0: time in nanoseconds + */ +int64_t msm_timer_get_sclk_time(int64_t *period) +{ + struct msm_timer_sync_data_t data; + uint32_t clock_value; + int64_t tmp; + + memset(&data, 0, sizeof(data)); + clock_value = msm_timer_do_sync_to_sclk( + msm_timer_get_sclk_time_start, + msm_timer_get_sclk_time_expired, + NULL, + &data); + + if (!clock_value) + return 0; + + if (period) { + tmp = 1LL << 32; + tmp *= NSEC_PER_SEC; + do_div(tmp, sclk_hz); + *period = tmp; + } + + tmp = (int64_t)clock_value; + tmp *= NSEC_PER_SEC; + do_div(tmp, sclk_hz); + return tmp; +} + +int __init msm_timer_init_time_sync(void (*timeout)(void)) +{ +#if !defined(CONFIG_MSM_DIRECT_SCLK_ACCESS) + int ret = smsm_change_intr_mask(SMSM_TIME_MASTER_DEM, 0xFFFFFFFF, 0); + + if (ret) { + printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n", + __func__, ret); + return ret; } - event_base = base + 0x4; - sts_base = base + 0x88; - source_base = cpu0_base + 0x24; - freq /= 4; - writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); + smsm_change_state(SMSM_APPS_DEM, + SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, SLAVE_TIME_INIT); +#endif - msm_timer_init(freq, 32, irq, !!percpu_offset); + BUG_ON(timeout == NULL); + msm_timer_sync_timeout = timeout; + + return 0; } +<<<<<<< current:drivers/clocksource/qcom-timer.c CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); #else +======= -static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, - u32 sts) +#endif +>>>>>>> patched:arch/arm/mach-msm/timer.c + +static u32 notrace msm_read_sched_clock(void) { - void __iomem *base; + struct msm_clock *clock = &msm_clocks[msm_global_timer]; + struct clocksource *cs = &clock->clocksource; + return cs->read(NULL); +} - base = ioremap(addr, SZ_256); - if (!base) { - pr_err("Failed to map timer base\n"); - return -ENOMEM; +static struct delay_timer msm_delay_timer; + +static unsigned long msm_read_current_timer(void) +{ + struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT]; + return msm_read_timer_count(dgt, GLOBAL_TIMER); +} + +static void __init msm_sched_clock_init(void) +{ + struct msm_clock *clock = &msm_clocks[msm_global_timer]; + + setup_sched_clock(msm_read_sched_clock, 32 - clock->shift, clock->freq); +} + +#ifdef CONFIG_LOCAL_TIMERS +int __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + static DEFINE_PER_CPU(bool, first_boot) = true; + struct msm_clock *clock = &msm_clocks[msm_global_timer]; + + /* Use existing clock_event for cpu 0 */ + if (!smp_processor_id()) + return 0; + + if (cpu_is_msm8x60() || soc_class_is_msm8960() || + soc_class_is_apq8064() || soc_class_is_msm8930()) + __raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); + + if (__get_cpu_var(first_boot)) { + __raw_writel(0, clock->regbase + TIMER_ENABLE); + __raw_writel(0, clock->regbase + TIMER_CLEAR); + __raw_writel(~0, clock->regbase + TIMER_MATCH_VAL); + __get_cpu_var(first_boot) = false; + if (clock->status_mask) + while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) & + clock->status_mask) + ; } - event_base = base + event; - source_base = base + source; - if (sts) - sts_base = base + sts; + evt->irq = clock->irq; + evt->name = "local_timer"; + evt->features = CLOCK_EVT_FEAT_ONESHOT; + evt->rating = clock->clockevent.rating; + evt->set_mode = msm_timer_set_mode; + evt->set_next_event = msm_timer_set_next_event; + + *__this_cpu_ptr(clock->percpu_evt) = evt; + clockevents_config_and_register(evt, gpt_hz, 4, 0xf0000000); + enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); return 0; } +<<<<<<< current:drivers/clocksource/qcom-timer.c static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) { /* @@ -315,29 +1096,204 @@ static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) } void __init msm7x01_timer_init(void) +======= +void local_timer_stop(struct clock_event_device *evt) +>>>>>>> patched:arch/arm/mach-msm/timer.c { - struct clocksource *cs = &msm_clocksource; - - if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0)) - return; - cs->read = msm_read_timer_count_shift; - cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); - /* 600 KHz */ - msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7, - false); + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + disable_percpu_irq(evt->irq); } -void __init msm7x30_timer_init(void) +static struct local_timer_ops msm_lt_ops = { + local_timer_setup, + local_timer_stop, +}; +#endif /* CONFIG_LOCAL_TIMERS */ + +#ifdef CONFIG_ARCH_MSM8625 +static void fixup_msm8625_timer(void) { - if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80)) - return; - msm_timer_init(24576000 / 4, 32, 1, false); + struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT]; + struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT]; + dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP; + gpt->irq = MSM8625_INT_GP_TIMER_EXP; + global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE; } +#else +static inline void fixup_msm8625_timer(void) { }; +#endif -void __init qsd8x50_timer_init(void) +void __init msm_timer_init(void) { - if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34)) - return; - msm_timer_init(19200000 / 4, 32, 7, false); + int i; + int res; + struct irq_chip *chip; + struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT]; + struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT]; + + if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() || + cpu_is_msm7x25a() || cpu_is_msm7x27a() || cpu_is_msm7x25aa() || + cpu_is_msm7x27aa() || cpu_is_msm8625() || cpu_is_msm7x25ab() || + cpu_is_msm8625q()) { + dgt->shift = MSM_DGT_SHIFT; + dgt->freq = 19200000 >> MSM_DGT_SHIFT; + dgt->clockevent.shift = 32 + MSM_DGT_SHIFT; + dgt->clocksource.mask = CLOCKSOURCE_MASK(32 - MSM_DGT_SHIFT); + gpt->regbase = MSM_TMR_BASE; + dgt->regbase = MSM_TMR_BASE + 0x10; + gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT + | MSM_CLOCK_FLAGS_ODD_MATCH_WRITE + | MSM_CLOCK_FLAGS_DELAYED_WRITE_POST; + if (cpu_is_msm8625() || cpu_is_msm8625q()) + fixup_msm8625_timer(); + } else if (cpu_is_qsd8x50()) { + dgt->freq = 4800000; + gpt->regbase = MSM_TMR_BASE; + dgt->regbase = MSM_TMR_BASE + 0x10; + } else if (cpu_is_fsm9xxx()) + dgt->freq = 4800000; + else if (cpu_is_msm7x30() || cpu_is_msm8x55()) { + gpt->status_mask = BIT(10); + dgt->status_mask = BIT(2); + dgt->freq = 6144000; + } else if (cpu_is_msm8x60()) { + global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE; + gpt->status_mask = BIT(10); + dgt->status_mask = BIT(2); + dgt->freq = 6750000; + __raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); + } else if (cpu_is_msm9615()) { + dgt->freq = 6750000; + __raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); + gpt->status_mask = BIT(10); + dgt->status_mask = BIT(2); + gpt->freq = 32765; + gpt_hz = 32765; + sclk_hz = 32765; + gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT; + dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT; + } else if (soc_class_is_msm8960() || soc_class_is_apq8064() || + soc_class_is_msm8930()) { + global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE; + dgt->freq = 6750000; + __raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); + gpt->status_mask = BIT(10); + dgt->status_mask = BIT(2); + if (!soc_class_is_apq8064()) { + gpt->freq = 32765; + gpt_hz = 32765; + sclk_hz = 32765; + } + if (!soc_class_is_msm8930() && !cpu_is_msm8960ab()) { + gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT; + dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT; + } + } else { + WARN(1, "Timer running on unknown hardware. Configure this! " + "Assuming default configuration.\n"); + dgt->freq = 6750000; + } + + if (msm_clocks[MSM_CLOCK_GPT].clocksource.rating > DG_TIMER_RATING) + msm_global_timer = MSM_CLOCK_GPT; + else + msm_global_timer = MSM_CLOCK_DGT; + + for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) { + struct msm_clock *clock = &msm_clocks[i]; + struct clock_event_device *ce = &clock->clockevent; + struct clocksource *cs = &clock->clocksource; + __raw_writel(0, clock->regbase + TIMER_ENABLE); + __raw_writel(0, clock->regbase + TIMER_CLEAR); + __raw_writel(~0, clock->regbase + TIMER_MATCH_VAL); + + if ((clock->freq << clock->shift) == gpt_hz) { + clock->rollover_offset = 0; + } else { + uint64_t temp; + + temp = clock->freq << clock->shift; + temp <<= 32; + do_div(temp, gpt_hz); + + clock->rollover_offset = (uint32_t) temp; + } + + ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); + /* allow at least 10 seconds to notice that the timer wrapped */ + ce->max_delta_ns = + clockevent_delta2ns(0xf0000000 >> clock->shift, ce); + /* ticks gets rounded down by one */ + ce->min_delta_ns = + clockevent_delta2ns(clock->write_delay + 4, ce); + ce->cpumask = cpumask_of(0); + + res = clocksource_register_hz(cs, clock->freq); + if (res) + printk(KERN_ERR "msm_timer_init: clocksource_register " + "failed for %s\n", cs->name); + + ce->irq = clock->irq; + if (cpu_is_msm8x60() || cpu_is_msm9615() || cpu_is_msm8625() || + cpu_is_msm8625q() || soc_class_is_msm8960() || + soc_class_is_apq8064() || soc_class_is_msm8930()) { + clock->percpu_evt = alloc_percpu(struct clock_event_device *); + if (!clock->percpu_evt) { + pr_err("msm_timer_init: memory allocation " + "failed for %s\n", ce->name); + continue; + } + + *__this_cpu_ptr(clock->percpu_evt) = ce; + res = request_percpu_irq(ce->irq, msm_timer_interrupt, + ce->name, clock->percpu_evt); + if (!res) + enable_percpu_irq(ce->irq, + IRQ_TYPE_EDGE_RISING); + } else { + clock->evt = ce; + res = request_irq(ce->irq, msm_timer_interrupt, + IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, + ce->name, &clock->evt); + } + + if (res) + pr_err("msm_timer_init: request_irq failed for %s\n", + ce->name); + + chip = irq_get_chip(clock->irq); + if (chip && chip->irq_mask) + chip->irq_mask(irq_get_irq_data(clock->irq)); + + if (clock->status_mask) + while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) & + clock->status_mask) + ; + + clockevents_register_device(ce); + } + msm_sched_clock_init(); + + if (use_user_accessible_timers()) { + if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) { + struct msm_clock *gtclock = &msm_clocks[MSM_CLOCK_GPT]; + void __iomem *addr = gtclock->regbase + + TIMER_COUNT_VAL + global_timer_offset; + setup_user_timer_offset(virt_to_phys(addr)&0xfff); + set_user_accessible_timer_flag(true); + } + } + + if (is_smp()) { + __raw_writel(1, + msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE); + msm_delay_timer.freq = dgt->freq; + msm_delay_timer.read_current_timer = &msm_read_current_timer; + register_current_timer_delay(&msm_delay_timer); + } + +#ifdef CONFIG_LOCAL_TIMERS + local_timer_register(&msm_lt_ops); +#endif } #endif diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 438901257ac1..cb69e7cbf5d5 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1 +1,55 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o +# When adding new entries keep the list in alphabetical order +CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) + +obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o +#obj-$(CONFIG_DEBUG_FS) += nohlt.o +obj-$(CONFIG_ARM64) += idle-v8.o cpu_ops.o +obj-$(CONFIG_CPU_V7) += idle-v7.o +obj-$(CONFIG_MAXIMUM_CURRENT_THROTTLING) += mct.o +obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o +obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o +obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o +obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o +obj-$(CONFIG_MSM_MEMORY_DUMP) += memory_dump.o +obj-$(CONFIG_MSM_MEMORY_DUMP_V2) += memory_dump_v2.o +obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o +obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o +ifdef CONFIG_DEBUG_FS +obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd-debug.o +endif +obj-$(CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG) += rpm_rbcpr_stats_v2.o +obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o +obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o +obj-$(CONFIG_MSM_JTAG) += jtag-fuse.o jtag.o +obj-$(CONFIG_MSM_JTAG_MM) += jtag-fuse.o jtag-mm.o +obj-$(CONFIG_MSM_JTAGV8) += jtag-fuse.o jtagv8.o jtagv8-mm.o +obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o + +obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o + +obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o smd_private.o smd_init_dt.o smsm_debug.o +obj-$(CONFIG_MSM_SMEM) += smem.o smem_debug.o +obj-$(CONFIG_MSM_SMEM_LOGGING) += smem_log.o +obj-$(CONFIG_MSM_COMMON_LOG) += common_log.o +obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o +obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_spinlock_test.o +obj-$(CONFIG_MSM_WATCHDOG_V2) += watchdog_v2.o +#obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/ +obj-$(CONFIG_MSM_SPM_V2) += spm-v2.o spm_devices.o +obj-y += socinfo.o + +obj-$(CONFIG_MSM_PIL) += peripheral-loader.o +obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o +obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o +obj-$(CONFIG_MSM_PIL_FEMTO) += pil-q6v5.o pil-msa.o pil-femto-modem.o + +obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o +obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o ocmem_core.o + +ifdef CONFIG_MSM_SUBSYSTEM_RESTART + obj-y += subsystem_notif.o + obj-y += subsystem_restart.o + obj-y += ramdump.o +endif +obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o diff --git a/drivers/soc/qcom/idle-v7.S b/drivers/soc/qcom/idle-v7.S new file mode 100644 index 000000000000..575f5a933582 --- /dev/null +++ b/drivers/soc/qcom/idle-v7.S @@ -0,0 +1,64 @@ +/* + * Idle processing for ARMv7-based Qualcomm SoCs. + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2009, 2011-2014 The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/linkage.h> +#include <linux/threads.h> +#include <asm/assembler.h> + + .arm +ENTRY(msm_pm_boot_entry) +THUMB( adr r9, BSYM(2f) ) /* Kernel is always entered in ARM. */ +THUMB( bx r9 ) /* If this is a Thumb-2 kernel, */ +THUMB( .thumb ) /* switch to Thumb now. */ +THUMB(2: ) + mrc p15, 0, r0, c0, c0, 5 /* MPIDR */ + bic r0, #0xff000000 /* what CPU am I */ + + adr r3, 3f + ldr r1, [r3] + sub r3, r1, r3 + ldr r1, =msm_pc_debug_counters_phys /*phys addr for IMEM reg */ + sub r1, r1, r3 /* translate virt to phys */ + ldr r1,[r1] + + cmp r1, #0 + beq skip_pc_debug3 + add r1, r1, r0, LSL #4 /* debug location for this CPU */ + add r1, #4 /* warmboot entry counter*/ + ldr r2, [r1] + add r2, #1 + str r2, [r1] + +skip_pc_debug3: + ldr r1, =msm_pm_boot_vector + sub r1, r1, r3 /* translate virt to phys */ + + add r1, r1, r0, LSL #2 /* locate boot vector for our cpu */ + ldr pc, [r1] /* jump */ +ENDPROC(msm_pm_boot_entry) + +3: .long . + + .data + + .globl msm_pm_boot_vector +msm_pm_boot_vector: + .space 4 * NR_CPUS + + .globl msm_pc_debug_counters_phys +msm_pc_debug_counters_phys: + .long 0x0 diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c new file mode 100644 index 000000000000..d482225183b2 --- /dev/null +++ b/drivers/soc/qcom/socinfo.c @@ -0,0 +1,1355 @@ +/* Copyright (c) 2009-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 Info Routines + * + */ + +#include <linux/export.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/sys_soc.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <asm/system_misc.h> + +#include <soc/qcom/socinfo.h> +#include <soc/qcom/smem.h> +#include <soc/qcom/boot_stats.h> + +#define BUILD_ID_LENGTH 32 +#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32 +#define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128 +#define SMEM_IMAGE_VERSION_SIZE 4096 +#define SMEM_IMAGE_VERSION_NAME_SIZE 75 +#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20 +#define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75 +#define SMEM_IMAGE_VERSION_OEM_SIZE 32 +#define SMEM_IMAGE_VERSION_OEM_OFFSET 96 +#define SMEM_IMAGE_VERSION_PARTITION_APPS 10 + +enum { + HW_PLATFORM_UNKNOWN = 0, + HW_PLATFORM_SURF = 1, + HW_PLATFORM_FFA = 2, + HW_PLATFORM_FLUID = 3, + HW_PLATFORM_SVLTE_FFA = 4, + HW_PLATFORM_SVLTE_SURF = 5, + HW_PLATFORM_MTP = 8, + HW_PLATFORM_LIQUID = 9, + /* Dragonboard platform id is assigned as 10 in CDT */ + HW_PLATFORM_DRAGON = 10, + HW_PLATFORM_QRD = 11, + HW_PLATFORM_HRD = 13, + HW_PLATFORM_DTV = 14, + HW_PLATFORM_STP = 23, + HW_PLATFORM_SBC = 24, + HW_PLATFORM_INVALID +}; + +const char *hw_platform[] = { + [HW_PLATFORM_UNKNOWN] = "Unknown", + [HW_PLATFORM_SURF] = "Surf", + [HW_PLATFORM_FFA] = "FFA", + [HW_PLATFORM_FLUID] = "Fluid", + [HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA", + [HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF", + [HW_PLATFORM_MTP] = "MTP", + [HW_PLATFORM_LIQUID] = "Liquid", + [HW_PLATFORM_DRAGON] = "Dragon", + [HW_PLATFORM_QRD] = "QRD", + [HW_PLATFORM_HRD] = "HRD", + [HW_PLATFORM_DTV] = "DTV", + [HW_PLATFORM_STP] = "STP", + [HW_PLATFORM_SBC] = "SBC", +}; + +enum { + ACCESSORY_CHIP_UNKNOWN = 0, + ACCESSORY_CHIP_CHARM = 58, +}; + +enum { + PLATFORM_SUBTYPE_QRD = 0x0, + PLATFORM_SUBTYPE_SKUAA = 0x1, + PLATFORM_SUBTYPE_SKUF = 0x2, + PLATFORM_SUBTYPE_SKUAB = 0x3, + PLATFORM_SUBTYPE_SKUG = 0x5, + PLATFORM_SUBTYPE_QRD_INVALID, +}; + +const char *qrd_hw_platform_subtype[] = { + [PLATFORM_SUBTYPE_QRD] = "QRD", + [PLATFORM_SUBTYPE_SKUAA] = "SKUAA", + [PLATFORM_SUBTYPE_SKUF] = "SKUF", + [PLATFORM_SUBTYPE_SKUAB] = "SKUAB", + [PLATFORM_SUBTYPE_SKUG] = "SKUG", + [PLATFORM_SUBTYPE_QRD_INVALID] = "INVALID", +}; + +enum { + PLATFORM_SUBTYPE_UNKNOWN = 0x0, + PLATFORM_SUBTYPE_CHARM = 0x1, + PLATFORM_SUBTYPE_STRANGE = 0x2, + PLATFORM_SUBTYPE_STRANGE_2A = 0x3, + PLATFORM_SUBTYPE_INVALID, +}; + +const char *hw_platform_subtype[] = { + [PLATFORM_SUBTYPE_UNKNOWN] = "Unknown", + [PLATFORM_SUBTYPE_CHARM] = "charm", + [PLATFORM_SUBTYPE_STRANGE] = "strange", + [PLATFORM_SUBTYPE_STRANGE_2A] = "strange_2a," +}; + +/* Used to parse shared memory. Must match the modem. */ +struct socinfo_v1 { + uint32_t format; + uint32_t id; + uint32_t version; + char build_id[BUILD_ID_LENGTH]; +}; + +struct socinfo_v2 { + struct socinfo_v1 v1; + + /* only valid when format==2 */ + uint32_t raw_id; + uint32_t raw_version; +}; + +struct socinfo_v3 { + struct socinfo_v2 v2; + + /* only valid when format==3 */ + uint32_t hw_platform; +}; + +struct socinfo_v4 { + struct socinfo_v3 v3; + + /* only valid when format==4 */ + uint32_t platform_version; +}; + +struct socinfo_v5 { + struct socinfo_v4 v4; + + /* only valid when format==5 */ + uint32_t accessory_chip; +}; + +struct socinfo_v6 { + struct socinfo_v5 v5; + + /* only valid when format==6 */ + uint32_t hw_platform_subtype; +}; + +struct socinfo_v7 { + struct socinfo_v6 v6; + + /* only valid when format==7 */ + uint32_t pmic_model; + uint32_t pmic_die_revision; +}; + +struct socinfo_v8 { + struct socinfo_v7 v7; + + /* only valid when format==8*/ + uint32_t pmic_model_1; + uint32_t pmic_die_revision_1; + uint32_t pmic_model_2; + uint32_t pmic_die_revision_2; +}; + +struct socinfo_v9 { + struct socinfo_v8 v8; + + /* only valid when format==9*/ + uint32_t foundry_id; +}; + +static union { + struct socinfo_v1 v1; + struct socinfo_v2 v2; + struct socinfo_v3 v3; + struct socinfo_v4 v4; + struct socinfo_v5 v5; + struct socinfo_v6 v6; + struct socinfo_v7 v7; + struct socinfo_v8 v8; + struct socinfo_v9 v9; +} *socinfo; + +static struct msm_soc_info cpu_of_id[] = { + + /* 7x01 IDs */ + [0] = {MSM_CPU_UNKNOWN, "Unknown CPU"}, + [1] = {MSM_CPU_7X01, "MSM7X01"}, + [16] = {MSM_CPU_7X01, "MSM7X01"}, + [17] = {MSM_CPU_7X01, "MSM7X01"}, + [18] = {MSM_CPU_7X01, "MSM7X01"}, + [19] = {MSM_CPU_7X01, "MSM7X01"}, + [23] = {MSM_CPU_7X01, "MSM7X01"}, + [25] = {MSM_CPU_7X01, "MSM7X01"}, + [26] = {MSM_CPU_7X01, "MSM7X01"}, + [32] = {MSM_CPU_7X01, "MSM7X01"}, + [33] = {MSM_CPU_7X01, "MSM7X01"}, + [34] = {MSM_CPU_7X01, "MSM7X01"}, + [35] = {MSM_CPU_7X01, "MSM7X01"}, + + /* 7x25 IDs */ + [20] = {MSM_CPU_7X25, "MSM7X25"}, + [21] = {MSM_CPU_7X25, "MSM7X25"}, + [24] = {MSM_CPU_7X25, "MSM7X25"}, + [27] = {MSM_CPU_7X25, "MSM7X25"}, + [39] = {MSM_CPU_7X25, "MSM7X25"}, + [40] = {MSM_CPU_7X25, "MSM7X25"}, + [41] = {MSM_CPU_7X25, "MSM7X25"}, + [42] = {MSM_CPU_7X25, "MSM7X25"}, + [62] = {MSM_CPU_7X25, "MSM7X25"}, + [63] = {MSM_CPU_7X25, "MSM7X25"}, + [66] = {MSM_CPU_7X25, "MSM7X25"}, + + + /* 7x27 IDs */ + [43] = {MSM_CPU_7X27, "MSM7X27"}, + [44] = {MSM_CPU_7X27, "MSM7X27"}, + [61] = {MSM_CPU_7X27, "MSM7X27"}, + [67] = {MSM_CPU_7X27, "MSM7X27"}, + [68] = {MSM_CPU_7X27, "MSM7X27"}, + [69] = {MSM_CPU_7X27, "MSM7X27"}, + + + /* 8x50 IDs */ + [30] = {MSM_CPU_8X50, "MSM8X50"}, + [36] = {MSM_CPU_8X50, "MSM8X50"}, + [37] = {MSM_CPU_8X50, "MSM8X50"}, + [38] = {MSM_CPU_8X50, "MSM8X50"}, + + /* 7x30 IDs */ + [59] = {MSM_CPU_7X30, "MSM7X30"}, + [60] = {MSM_CPU_7X30, "MSM7X30"}, + + /* 8x55 IDs */ + [74] = {MSM_CPU_8X55, "MSM8X55"}, + [75] = {MSM_CPU_8X55, "MSM8X55"}, + [85] = {MSM_CPU_8X55, "MSM8X55"}, + + /* 8x60 IDs */ + [70] = {MSM_CPU_8X60, "MSM8X60"}, + [71] = {MSM_CPU_8X60, "MSM8X60"}, + [86] = {MSM_CPU_8X60, "MSM8X60"}, + + /* 8960 IDs */ + [87] = {MSM_CPU_8960, "MSM8960"}, + + /* 7x25A IDs */ + [88] = {MSM_CPU_7X25A, "MSM7X25A"}, + [89] = {MSM_CPU_7X25A, "MSM7X25A"}, + [96] = {MSM_CPU_7X25A, "MSM7X25A"}, + + /* 7x27A IDs */ + [90] = {MSM_CPU_7X27A, "MSM7X27A"}, + [91] = {MSM_CPU_7X27A, "MSM7X27A"}, + [92] = {MSM_CPU_7X27A, "MSM7X27A"}, + [97] = {MSM_CPU_7X27A, "MSM7X27A"}, + + /* FSM9xxx ID */ + [94] = {FSM_CPU_9XXX, "FSM9XXX"}, + [95] = {FSM_CPU_9XXX, "FSM9XXX"}, + + /* 7x25AA ID */ + [98] = {MSM_CPU_7X25AA, "MSM7X25AA"}, + [99] = {MSM_CPU_7X25AA, "MSM7X25AA"}, + [100] = {MSM_CPU_7X25AA, "MSM7X25AA"}, + + /* 7x27AA ID */ + [101] = {MSM_CPU_7X27AA, "MSM7X27AA"}, + [102] = {MSM_CPU_7X27AA, "MSM7X27AA"}, + [103] = {MSM_CPU_7X27AA, "MSM7X27AA"}, + [136] = {MSM_CPU_7X27AA, "MSM7X27AA"}, + + /* 9x15 ID */ + [104] = {MSM_CPU_9615, "MSM9615"}, + [105] = {MSM_CPU_9615, "MSM9615"}, + [106] = {MSM_CPU_9615, "MSM9615"}, + [107] = {MSM_CPU_9615, "MSM9615"}, + [171] = {MSM_CPU_9615, "MSM9615"}, + + /* 8064 IDs */ + [109] = {MSM_CPU_8064, "APQ8064"}, + + /* 8930 IDs */ + [116] = {MSM_CPU_8930, "MSM8930"}, + [117] = {MSM_CPU_8930, "MSM8930"}, + [118] = {MSM_CPU_8930, "MSM8930"}, + [119] = {MSM_CPU_8930, "MSM8930"}, + [179] = {MSM_CPU_8930, "MSM8930"}, + + /* 8627 IDs */ + [120] = {MSM_CPU_8627, "MSM8627"}, + [121] = {MSM_CPU_8627, "MSM8627"}, + + /* 8660A ID */ + [122] = {MSM_CPU_8960, "MSM8960"}, + + /* 8260A ID */ + [123] = {MSM_CPU_8960, "MSM8960"}, + + /* 8060A ID */ + [124] = {MSM_CPU_8960, "MSM8960"}, + + /* 8974 IDs */ + [126] = {MSM_CPU_8974, "MSM8974"}, + [184] = {MSM_CPU_8974, "MSM8974"}, + [185] = {MSM_CPU_8974, "MSM8974"}, + [186] = {MSM_CPU_8974, "MSM8974"}, + + /* 8974AA IDs */ + [208] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"}, + [211] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"}, + [214] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"}, + [217] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"}, + + /* 8974AB IDs */ + [209] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"}, + [212] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"}, + [215] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"}, + [218] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"}, + + /* 8974AC IDs */ + [194] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"}, + [210] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"}, + [213] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"}, + [216] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"}, + + /* 8625 IDs */ + [127] = {MSM_CPU_8625, "MSM8625"}, + [128] = {MSM_CPU_8625, "MSM8625"}, + [129] = {MSM_CPU_8625, "MSM8625"}, + [137] = {MSM_CPU_8625, "MSM8625"}, + [167] = {MSM_CPU_8625, "MSM8625"}, + + /* 8064 MPQ ID */ + [130] = {MSM_CPU_8064, "APQ8064"}, + + /* 7x25AB IDs */ + [131] = {MSM_CPU_7X25AB, "MSM7X25AB"}, + [132] = {MSM_CPU_7X25AB, "MSM7X25AB"}, + [133] = {MSM_CPU_7X25AB, "MSM7X25AB"}, + [135] = {MSM_CPU_7X25AB, "MSM7X25AB"}, + + /* 9625 IDs */ + [134] = {MSM_CPU_9625, "MSM9625"}, + [148] = {MSM_CPU_9625, "MSM9625"}, + [149] = {MSM_CPU_9625, "MSM9625"}, + [150] = {MSM_CPU_9625, "MSM9625"}, + [151] = {MSM_CPU_9625, "MSM9625"}, + [152] = {MSM_CPU_9625, "MSM9625"}, + [173] = {MSM_CPU_9625, "MSM9625"}, + [174] = {MSM_CPU_9625, "MSM9625"}, + [175] = {MSM_CPU_9625, "MSM9625"}, + + /* 8960AB IDs */ + [138] = {MSM_CPU_8960AB, "MSM8960AB"}, + [139] = {MSM_CPU_8960AB, "MSM8960AB"}, + [140] = {MSM_CPU_8960AB, "MSM8960AB"}, + [141] = {MSM_CPU_8960AB, "MSM8960AB"}, + + /* 8930AA IDs */ + [142] = {MSM_CPU_8930AA, "MSM8930AA"}, + [143] = {MSM_CPU_8930AA, "MSM8930AA"}, + [144] = {MSM_CPU_8930AA, "MSM8930AA"}, + [160] = {MSM_CPU_8930AA, "MSM8930AA"}, + [180] = {MSM_CPU_8930AA, "MSM8930AA"}, + + /* 8226 IDs */ + [145] = {MSM_CPU_8226, "MSM8626"}, + [158] = {MSM_CPU_8226, "MSM8226"}, + [159] = {MSM_CPU_8226, "MSM8526"}, + [198] = {MSM_CPU_8226, "MSM8126"}, + [199] = {MSM_CPU_8226, "APQ8026"}, + [200] = {MSM_CPU_8226, "MSM8926"}, + [205] = {MSM_CPU_8226, "MSM8326"}, + [219] = {MSM_CPU_8226, "APQ8028"}, + [220] = {MSM_CPU_8226, "MSM8128"}, + [221] = {MSM_CPU_8226, "MSM8228"}, + [222] = {MSM_CPU_8226, "MSM8528"}, + [223] = {MSM_CPU_8226, "MSM8628"}, + [224] = {MSM_CPU_8226, "MSM8928"}, + + /* 8092 IDs */ + [146] = {MSM_CPU_8092, "MPQ8092"}, + + /* 8610 IDs */ + [147] = {MSM_CPU_8610, "MSM8610"}, + [161] = {MSM_CPU_8610, "MSM8110"}, + [162] = {MSM_CPU_8610, "MSM8210"}, + [163] = {MSM_CPU_8610, "MSM8810"}, + [164] = {MSM_CPU_8610, "MSM8212"}, + [165] = {MSM_CPU_8610, "MSM8612"}, + [166] = {MSM_CPU_8610, "MSM8112"}, + [225] = {MSM_CPU_8610, "MSM8510"}, + [226] = {MSM_CPU_8610, "MSM8512"}, + + /* 8064AB IDs */ + [153] = {MSM_CPU_8064AB, "APQ8064AB"}, + + /* 8930AB IDs */ + [154] = {MSM_CPU_8930AB, "MSM8930AB"}, + [155] = {MSM_CPU_8930AB, "MSM8930AB"}, + [156] = {MSM_CPU_8930AB, "MSM8930AB"}, + [157] = {MSM_CPU_8930AB, "MSM8930AB"}, + [181] = {MSM_CPU_8930AB, "MSM8930AB"}, + + /* 8625Q IDs */ + [168] = {MSM_CPU_8625Q, "MSM8225Q"}, + [169] = {MSM_CPU_8625Q, "MSM8625Q"}, + [170] = {MSM_CPU_8625Q, "MSM8125Q"}, + + /* 8064AA IDs */ + [172] = {MSM_CPU_8064AA, "APQ8064AA"}, + + /* 8084 IDs */ + [178] = {MSM_CPU_8084, "APQ8084"}, + + /* 9630 IDs */ + [187] = {MSM_CPU_9630, "MDM9630"}, + [227] = {MSM_CPU_9630, "MDM9630"}, + [228] = {MSM_CPU_9630, "MDM9630"}, + [229] = {MSM_CPU_9630, "MDM9630"}, + [230] = {MSM_CPU_9630, "MDM9630"}, + [231] = {MSM_CPU_9630, "MDM9630"}, + + /* FSM9900 ID */ + [188] = {FSM_CPU_9900, "FSM9900"}, + [189] = {FSM_CPU_9900, "FSM9900"}, + [190] = {FSM_CPU_9900, "FSM9900"}, + [191] = {FSM_CPU_9900, "FSM9900"}, + [192] = {FSM_CPU_9900, "FSM9900"}, + [193] = {FSM_CPU_9900, "FSM9900"}, + + /* 8916 IDs */ + [206] = {MSM_CPU_8916, "MSM8916"}, + [247] = {MSM_CPU_8916, "APQ8016"}, + [248] = {MSM_CPU_8916, "MSM8216"}, + [249] = {MSM_CPU_8916, "MSM8116"}, + [250] = {MSM_CPU_8916, "MSM8616"}, + + /* 8936 IDs */ + [233] = {MSM_CPU_8936, "MSM8936"}, + + /* 8939 IDs */ + [239] = {MSM_CPU_8939, "MSM8939"}, + + /* ZIRC IDs */ + [234] = {MSM_CPU_ZIRC, "MSMZIRC"}, + [235] = {MSM_CPU_ZIRC, "MSMZIRC"}, + [236] = {MSM_CPU_ZIRC, "MSMZIRC"}, + [237] = {MSM_CPU_ZIRC, "MSMZIRC"}, + [238] = {MSM_CPU_ZIRC, "MSMZIRC"}, + + /* Uninitialized IDs are not known to run Linux. + MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are + considered as unknown CPU. */ +}; + +static enum msm_cpu cur_cpu; +static int current_image; + +static struct socinfo_v1 dummy_socinfo = { + .format = 1, + .version = 1, +}; + +uint32_t socinfo_get_id(void) +{ + return (socinfo) ? socinfo->v1.id : 0; +} +EXPORT_SYMBOL_GPL(socinfo_get_id); + +uint32_t socinfo_get_version(void) +{ + return (socinfo) ? socinfo->v1.version : 0; +} + +char *socinfo_get_build_id(void) +{ + return (socinfo) ? socinfo->v1.build_id : NULL; +} + +static char *msm_read_hardware_id(void) +{ + static char msm_soc_str[256] = "Qualcomm Technologies, Inc "; + static bool string_generated; + int ret = 0; + + if (string_generated) + return msm_soc_str; + if (!socinfo) + goto err_path; + if (!cpu_of_id[socinfo->v1.id].soc_id_string) + goto err_path; + + ret = strlcat(msm_soc_str, cpu_of_id[socinfo->v1.id].soc_id_string, + sizeof(msm_soc_str)); + if (ret > sizeof(msm_soc_str)) + goto err_path; + + string_generated = true; + return msm_soc_str; +err_path: + return "UNKNOWN SOC TYPE"; +} + +uint32_t socinfo_get_raw_id(void) +{ + return socinfo ? + (socinfo->v1.format >= 2 ? socinfo->v2.raw_id : 0) + : 0; +} + +uint32_t socinfo_get_raw_version(void) +{ + return socinfo ? + (socinfo->v1.format >= 2 ? socinfo->v2.raw_version : 0) + : 0; +} + +uint32_t socinfo_get_platform_type(void) +{ + return socinfo ? + (socinfo->v1.format >= 3 ? socinfo->v3.hw_platform : 0) + : 0; +} + + +uint32_t socinfo_get_platform_version(void) +{ + return socinfo ? + (socinfo->v1.format >= 4 ? socinfo->v4.platform_version : 0) + : 0; +} + +/* This information is directly encoded by the machine id */ +/* Thus no external callers rely on this information at the moment */ +static uint32_t socinfo_get_accessory_chip(void) +{ + return socinfo ? + (socinfo->v1.format >= 5 ? socinfo->v5.accessory_chip : 0) + : 0; +} + +uint32_t socinfo_get_platform_subtype(void) +{ + return socinfo ? + (socinfo->v1.format >= 6 ? socinfo->v6.hw_platform_subtype : 0) + : 0; +} + +static uint32_t socinfo_get_foundry_id(void) +{ + return socinfo ? + (socinfo->v1.format >= 9 ? socinfo->v9.foundry_id : 0) + : 0; +} + +enum pmic_model socinfo_get_pmic_model(void) +{ + return socinfo ? + (socinfo->v1.format >= 7 ? socinfo->v7.pmic_model + : PMIC_MODEL_UNKNOWN) + : PMIC_MODEL_UNKNOWN; +} + +uint32_t socinfo_get_pmic_die_revision(void) +{ + return socinfo ? + (socinfo->v1.format >= 7 ? socinfo->v7.pmic_die_revision : 0) + : 0; +} + +static char *socinfo_get_image_version_base_address(void) +{ + return smem_find(SMEM_IMAGE_VERSION_TABLE, + SMEM_IMAGE_VERSION_SIZE, 0, SMEM_ANY_HOST_FLAG); +} + +static uint32_t socinfo_get_format(void) +{ + return socinfo ? socinfo->v1.format : 0; +} + +enum msm_cpu socinfo_get_msm_cpu(void) +{ + return cur_cpu; +} +EXPORT_SYMBOL_GPL(socinfo_get_msm_cpu); + +static ssize_t +msm_get_vendor(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Qualcomm\n"); +} + +static ssize_t +msm_get_raw_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_raw_id()); +} + +static ssize_t +msm_get_raw_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_raw_version()); +} + +static ssize_t +msm_get_build_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%-.32s\n", + socinfo_get_build_id()); +} + +static ssize_t +msm_get_hw_platform(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + uint32_t hw_type; + hw_type = socinfo_get_platform_type(); + + return snprintf(buf, PAGE_SIZE, "%-.32s\n", + hw_platform[hw_type]); +} + +static ssize_t +msm_get_platform_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_platform_version()); +} + +static ssize_t +msm_get_accessory_chip(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_accessory_chip()); +} + +static ssize_t +msm_get_platform_subtype(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + uint32_t hw_subtype; + hw_subtype = socinfo_get_platform_subtype(); + if (HW_PLATFORM_QRD == socinfo_get_platform_type()) { + if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) { + pr_err("%s: Invalid hardware platform sub type for qrd found\n", + __func__); + hw_subtype = PLATFORM_SUBTYPE_QRD_INVALID; + } + return snprintf(buf, PAGE_SIZE, "%-.32s\n", + qrd_hw_platform_subtype[hw_subtype]); + } + + return snprintf(buf, PAGE_SIZE, "%-.32s\n", + hw_platform_subtype[hw_subtype]); +} + +static ssize_t +msm_get_platform_subtype_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + uint32_t hw_subtype; + hw_subtype = socinfo_get_platform_subtype(); + return snprintf(buf, PAGE_SIZE, "%u\n", + hw_subtype); +} + +static ssize_t +msm_get_foundry_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_foundry_id()); +} + +static ssize_t +msm_get_pmic_model(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_pmic_model()); +} + +static ssize_t +msm_get_pmic_die_revision(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", + socinfo_get_pmic_die_revision()); +} + +static ssize_t +msm_get_image_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char *string_address; + + string_address = socinfo_get_image_version_base_address(); + if (IS_ERR_OR_NULL(string_address)) { + pr_err("%s : Failed to get image version base address", + __func__); + return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown"); + } + string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n", + string_address); +} + +static ssize_t +msm_set_image_version(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + char *store_address; + + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) + return count; + store_address = socinfo_get_image_version_base_address(); + if (IS_ERR_OR_NULL(store_address)) { + pr_err("%s : Failed to get image version base address", + __func__); + return count; + } + store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf); + return count; +} + +static ssize_t +msm_get_image_variant(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char *string_address; + + string_address = socinfo_get_image_version_base_address(); + if (IS_ERR_OR_NULL(string_address)) { + pr_err("%s : Failed to get image version base address", + __func__); + return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, + "Unknown"); + } + string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET; + return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n", + string_address); +} + +static ssize_t +msm_set_image_variant(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + char *store_address; + + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) + return count; + store_address = socinfo_get_image_version_base_address(); + if (IS_ERR_OR_NULL(store_address)) { + pr_err("%s : Failed to get image version base address", + __func__); + return count; + } + store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET; + snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf); + return count; +} + +static ssize_t +msm_get_image_crm_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char *string_address; + + string_address = socinfo_get_image_version_base_address(); + if (IS_ERR_OR_NULL(string_address)) { + pr_err("%s : Failed to get image version base address", + __func__); + return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown"); + } + string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + string_address += SMEM_IMAGE_VERSION_OEM_OFFSET; + return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n", + string_address); +} + +static ssize_t +msm_set_image_crm_version(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + char *store_address; + + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) + return count; + store_address = socinfo_get_image_version_base_address(); + if (IS_ERR_OR_NULL(store_address)) { + pr_err("%s : Failed to get image version base address", + __func__); + return count; + } + store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + store_address += SMEM_IMAGE_VERSION_OEM_OFFSET; + snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf); + return count; +} + +static ssize_t +msm_get_image_number(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + current_image); +} + +static ssize_t +msm_select_image(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret, digit; + + ret = kstrtoint(buf, 10, &digit); + if (ret) + return ret; + if (0 <= digit && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT) + current_image = digit; + else + current_image = 0; + return count; +} + + +static struct device_attribute msm_soc_attr_raw_version = + __ATTR(raw_version, S_IRUGO, msm_get_raw_version, NULL); + +static struct device_attribute msm_soc_attr_raw_id = + __ATTR(raw_id, S_IRUGO, msm_get_raw_id, NULL); + +static struct device_attribute msm_soc_attr_vendor = + __ATTR(vendor, S_IRUGO, msm_get_vendor, NULL); + +static struct device_attribute msm_soc_attr_build_id = + __ATTR(build_id, S_IRUGO, msm_get_build_id, NULL); + +static struct device_attribute msm_soc_attr_hw_platform = + __ATTR(hw_platform, S_IRUGO, msm_get_hw_platform, NULL); + + +static struct device_attribute msm_soc_attr_platform_version = + __ATTR(platform_version, S_IRUGO, + msm_get_platform_version, NULL); + +static struct device_attribute msm_soc_attr_accessory_chip = + __ATTR(accessory_chip, S_IRUGO, + msm_get_accessory_chip, NULL); + +static struct device_attribute msm_soc_attr_platform_subtype = + __ATTR(platform_subtype, S_IRUGO, + msm_get_platform_subtype, NULL); + +/* Platform Subtype String is being deprecated. Use Platform + * Subtype ID instead. + */ +static struct device_attribute msm_soc_attr_platform_subtype_id = + __ATTR(platform_subtype_id, S_IRUGO, + msm_get_platform_subtype_id, NULL); + +static struct device_attribute msm_soc_attr_foundry_id = + __ATTR(foundry_id, S_IRUGO, + msm_get_foundry_id, NULL); + +static struct device_attribute msm_soc_attr_pmic_model = + __ATTR(pmic_model, S_IRUGO, + msm_get_pmic_model, NULL); + +static struct device_attribute msm_soc_attr_pmic_die_revision = + __ATTR(pmic_die_revision, S_IRUGO, + msm_get_pmic_die_revision, NULL); + +static struct device_attribute image_version = + __ATTR(image_version, S_IRUGO | S_IWUSR, + msm_get_image_version, msm_set_image_version); + +static struct device_attribute image_variant = + __ATTR(image_variant, S_IRUGO | S_IWUSR, + msm_get_image_variant, msm_set_image_variant); + +static struct device_attribute image_crm_version = + __ATTR(image_crm_version, S_IRUGO | S_IWUSR, + msm_get_image_crm_version, msm_set_image_crm_version); + +static struct device_attribute select_image = + __ATTR(select_image, S_IRUGO | S_IWUSR, + msm_get_image_number, msm_select_image); + +static void * __init setup_dummy_socinfo(void) +{ + if (early_machine_is_mpq8092()) { + dummy_socinfo.id = 146; + strlcpy(dummy_socinfo.build_id, "mpq8092 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_apq8084()) { + dummy_socinfo.id = 178; + strlcpy(dummy_socinfo.build_id, "apq8084 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_mdm9630()) { + dummy_socinfo.id = 187; + strlcpy(dummy_socinfo.build_id, "mdm9630 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msmsamarium()) { + dummy_socinfo.id = 195; + strlcpy(dummy_socinfo.build_id, "msmsamarium - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msm8916()) { + dummy_socinfo.id = 206; + strlcpy(dummy_socinfo.build_id, "msm8916 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msm8939()) { + dummy_socinfo.id = 239; + strlcpy(dummy_socinfo.build_id, "msm8939 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msm8936()) { + dummy_socinfo.id = 233; + strlcpy(dummy_socinfo.build_id, "msm8936 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msmzirc()) { + dummy_socinfo.id = 238; + strlcpy(dummy_socinfo.build_id, "msmzirc - ", + sizeof(dummy_socinfo.build_id)); + } + + strlcat(dummy_socinfo.build_id, "Dummy socinfo", + sizeof(dummy_socinfo.build_id)); + return (void *) &dummy_socinfo; +} + +static void __init populate_soc_sysfs_files(struct device *msm_soc_device) +{ + uint32_t legacy_format = socinfo_get_format(); + + device_create_file(msm_soc_device, &msm_soc_attr_vendor); + device_create_file(msm_soc_device, &image_version); + device_create_file(msm_soc_device, &image_variant); + device_create_file(msm_soc_device, &image_crm_version); + device_create_file(msm_soc_device, &select_image); + + switch (legacy_format) { + case 9: + device_create_file(msm_soc_device, + &msm_soc_attr_foundry_id); + case 8: + case 7: + device_create_file(msm_soc_device, + &msm_soc_attr_pmic_model); + device_create_file(msm_soc_device, + &msm_soc_attr_pmic_die_revision); + case 6: + device_create_file(msm_soc_device, + &msm_soc_attr_platform_subtype); + device_create_file(msm_soc_device, + &msm_soc_attr_platform_subtype_id); + case 5: + device_create_file(msm_soc_device, + &msm_soc_attr_accessory_chip); + case 4: + device_create_file(msm_soc_device, + &msm_soc_attr_platform_version); + case 3: + device_create_file(msm_soc_device, + &msm_soc_attr_hw_platform); + case 2: + device_create_file(msm_soc_device, + &msm_soc_attr_raw_id); + device_create_file(msm_soc_device, + &msm_soc_attr_raw_version); + case 1: + device_create_file(msm_soc_device, + &msm_soc_attr_build_id); + break; + default: + pr_err("%s:Unknown socinfo format:%u\n", __func__, + legacy_format); + break; + } + + return; +} + +static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr) +{ + uint32_t soc_version = socinfo_get_version(); + + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", socinfo_get_id()); + soc_dev_attr->machine = "Snapdragon"; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u", + SOCINFO_VERSION_MAJOR(soc_version), + SOCINFO_VERSION_MINOR(soc_version)); + return; + +} + +static int __init socinfo_init_sysfs(void) +{ + struct device *msm_soc_device; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + if (!socinfo) { + pr_err("%s: No socinfo found!\n", __func__); + return -ENODEV; + } + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) { + pr_err("%s: Soc Device alloc failed!\n", __func__); + return -ENOMEM; + } + + soc_info_populate(soc_dev_attr); + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR_OR_NULL(soc_dev)) { + kfree(soc_dev_attr); + pr_err("%s: Soc device register failed\n", __func__); + return -EIO; + } + + msm_soc_device = soc_device_to_device(soc_dev); + populate_soc_sysfs_files(msm_soc_device); + return 0; +} + +late_initcall(socinfo_init_sysfs); + +static void socinfo_print(void) +{ + switch (socinfo->v1.format) { + case 1: + pr_info("%s: v%u, id=%u, ver=%u.%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version)); + break; + case 2: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version); + break; + case 3: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u, hw_plat=%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform); + break; + case 4: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform, socinfo->v4.platform_version); + break; + case 5: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n" + " accessory_chip=%u\n", __func__, socinfo->v1.format, + socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform, socinfo->v4.platform_version, + socinfo->v5.accessory_chip); + break; + case 6: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n" + " accessory_chip=%u hw_plat_subtype=%u\n", __func__, + socinfo->v1.format, + socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform, socinfo->v4.platform_version, + socinfo->v5.accessory_chip, + socinfo->v6.hw_platform_subtype); + break; + case 8: + case 7: + pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n", + __func__, + socinfo->v1.format, + socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform, socinfo->v4.platform_version, + socinfo->v5.accessory_chip, + socinfo->v6.hw_platform_subtype, + socinfo->v7.pmic_model, + socinfo->v7.pmic_die_revision); + break; + case 9: + pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u\n", + __func__, + socinfo->v1.format, + socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform, socinfo->v4.platform_version, + socinfo->v5.accessory_chip, + socinfo->v6.hw_platform_subtype, + socinfo->v7.pmic_model, + socinfo->v7.pmic_die_revision, + socinfo->v9.foundry_id); + break; + + default: + pr_err("%s: Unknown format found\n", __func__); + break; + } +} + +int __init socinfo_init(void) +{ + static bool socinfo_init_done; + + if (socinfo_init_done) + return 0; + + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v9), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v8), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v7), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v6), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v5), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v4), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v3), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v2), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) + socinfo = smem_find(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v1), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(socinfo)) { + pr_warn("%s: Can't find SMEM_HW_SW_BUILD_ID; falling back on dummy values.\n", + __func__); + socinfo = setup_dummy_socinfo(); + } + + WARN(!socinfo_get_id(), "Unknown SOC ID!\n"); + + if (socinfo_get_id() >= ARRAY_SIZE(cpu_of_id)) + BUG_ON("New IDs added! ID => CPU mapping needs an update.\n"); + else + cur_cpu = cpu_of_id[socinfo->v1.id].generic_soc_type; + + boot_stats_init(); + socinfo_print(); + arch_read_hardware_id = msm_read_hardware_id; + socinfo_init_done = true; + + return 0; +} +subsys_initcall(socinfo_init); + +const int get_core_count(void) +{ + if (!(read_cpuid_mpidr() & BIT(31))) + return 1; + + if (read_cpuid_mpidr() & BIT(30)) + return 1; + + /* 1 + the PART[1:0] field of MIDR */ + return ((read_cpuid_id() >> 4) & 3) + 1; +} + +const int read_msm_cpu_type(void) +{ + if (socinfo_get_msm_cpu() != MSM_CPU_UNKNOWN) + return socinfo_get_msm_cpu(); + + switch (read_cpuid_id()) { + case 0x510F02D0: + case 0x510F02D2: + case 0x510F02D4: + return MSM_CPU_8X60; + + case 0x510F04D0: + case 0x510F04D1: + case 0x510F04D2: + case 0x511F04D0: + case 0x512F04D0: + return MSM_CPU_8960; + + case 0x51404D11: /* We can't get here unless we are in bringup */ + return MSM_CPU_8930; + + case 0x510F06F0: + return MSM_CPU_8064; + + case 0x511F06F1: + case 0x511F06F2: + case 0x512F06F0: + return MSM_CPU_8974; + + default: + return MSM_CPU_UNKNOWN; + }; +} + +const int cpu_is_krait(void) +{ + return ((read_cpuid_id() & 0xFF00FC00) == 0x51000400); +} + +const int cpu_is_krait_v1(void) +{ + switch (read_cpuid_id()) { + case 0x510F04D0: + case 0x510F04D1: + case 0x510F04D2: + return 1; + + default: + return 0; + }; +} + +const int cpu_is_krait_v2(void) +{ + switch (read_cpuid_id()) { + case 0x511F04D0: + case 0x511F04D1: + case 0x511F04D2: + case 0x511F04D3: + case 0x511F04D4: + + case 0x510F06F0: + case 0x510F06F1: + case 0x510F06F2: + return 1; + + default: + return 0; + }; +} + +const int cpu_is_krait_v3(void) +{ + switch (read_cpuid_id()) { + case 0x512F04D0: + case 0x511F06F0: + case 0x511F06F1: + case 0x511F06F2: + case 0x510F05D0: + case 0x510F07F0: + return 1; + + default: + return 0; + }; +} diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h index 292c571750f0..f7aae4d28bf6 100644 --- a/include/asm-generic/dma-contiguous.h +++ b/include/asm-generic/dma-contiguous.h @@ -1,9 +1,25 @@ #ifndef _ASM_GENERIC_DMA_CONTIGUOUS_H #define _ASM_GENERIC_DMA_CONTIGUOUS_H +#include <linux/device.h> +#include <linux/dma-contiguous.h> + #include <linux/types.h> static inline void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { } +static inline struct cma *dev_get_cma_area(struct device *dev) +{ + if (dev && dev->cma_area) + return dev->cma_area; + return dma_contiguous_def_area; +} + +static inline void dev_set_cma_area(struct device *dev, struct cma *cma) +{ + if (dev) + dev->cma_area = cma; +} + #endif diff --git a/include/asm-generic/percpu-defs.h b/include/asm-generic/percpu-defs.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/include/asm-generic/percpu-defs.h diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index aa70cbda327c..a0a37cfc16ea 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -165,9 +165,18 @@ #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) -#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) +/* #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) */ #define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) +#ifdef CONFIG_OF +#define CPU_METHOD_OF_TABLES() . = ALIGN(8); \ + VMLINUX_SYMBOL(__cpu_method_of_table) = .; \ + *(__cpu_method_of_table) \ + VMLINUX_SYMBOL(__cpu_method_of_table_end) = .; +#else +#define CPU_METHOD_OF_TABLES() +#endif + #define KERNEL_DTB() \ STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__dtb_start) = .; \ @@ -496,6 +505,7 @@ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ + CPU_METHOD_OF_TABLES() \ CLKSRC_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ KERNEL_DTB() \ @@ -653,6 +663,11 @@ *(.security_initcall.init) \ VMLINUX_SYMBOL(__security_initcall_end) = .; +#define COMPAT_EXPORTS \ + VMLINUX_SYMBOL(__compat_exports_start) = .; \ + *(.exportcompat.init) \ + VMLINUX_SYMBOL(__compat_exports_end) = .; + #ifdef CONFIG_BLK_DEV_INITRD #define INIT_RAM_FS \ . = ALIGN(4); \ diff --git a/include/dt-bindings/clock/msm-clocks-8916.h b/include/dt-bindings/clock/msm-clocks-8916.h new file mode 100644 index 000000000000..c609f3e2969e --- /dev/null +++ b/include/dt-bindings/clock/msm-clocks-8916.h @@ -0,0 +1,222 @@ +/* Copyright (c) 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. + */ + +#ifndef __MSM_CLOCKS_8916_H +#define __MSM_CLOCKS_8916_H + +/* GPLLs */ +#define clk_gpll0_clk_src 0x5933b69f +#define clk_gpll0_ao_clk_src 0x6b2fb034 +#define clk_gpll1_clk_src 0x916f8847 +#define clk_gpll2_clk_src 0x7c34503b + +/* SR2PLL */ +#define clk_a53sspll 0xf761da94 + +/* SRCs */ +#define clk_apss_ahb_clk_src 0x36f8495f +#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e +#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa +#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79 +#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a +#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902 +#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f +#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68 +#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb +#define clk_blsp1_qup5_i2c_apps_clk_src 0x71ea7804 +#define clk_blsp1_qup5_spi_apps_clk_src 0x9752f35f +#define clk_blsp1_qup6_i2c_apps_clk_src 0x28806803 +#define clk_blsp1_qup6_spi_apps_clk_src 0x44a1edc4 +#define clk_blsp1_uart1_apps_clk_src 0xf8146114 +#define clk_blsp1_uart2_apps_clk_src 0xfc9c2f73 +#define clk_byte0_clk_src 0x75cc885b +#define clk_cci_clk_src 0x822f3d97 +#define clk_cpp_clk_src 0x8382f56d +#define clk_camss_ahb_clk_src 0xa68afe9c +#define clk_camss_gp0_clk_src 0x43b063e9 +#define clk_camss_gp1_clk_src 0xa3315f1b +#define clk_crypto_clk_src 0x37a21414 +#define clk_csi0_clk_src 0x227e65bc +#define clk_csi1_clk_src 0x6a2a6c36 +#define clk_csi0phytimer_clk_src 0xc8a309be +#define clk_csi1phytimer_clk_src 0x7c0fe23a +#define clk_esc0_clk_src 0xb41d7c38 +#define clk_gfx3d_clk_src 0x917f76ef +#define clk_gp1_clk_src 0xad85b97a +#define clk_gp2_clk_src 0xfb1f0065 +#define clk_gp3_clk_src 0x63b693d6 +#define clk_jpeg0_clk_src 0x9a0a0ac3 +#define clk_mdp_clk_src 0x6dc1f8f1 +#define clk_mclk0_clk_src 0x266b3853 +#define clk_mclk1_clk_src 0xa73cad0c +#define clk_pclk0_clk_src 0xccac1f35 +#define clk_pdm2_clk_src 0x31e494fd +#define clk_sdcc1_apps_clk_src 0xd4975db2 +#define clk_sdcc2_apps_clk_src 0xfc46c821 +#define clk_usb_hs_system_clk_src 0x28385546 +#define clk_vsync_clk_src 0xecb43940 +#define clk_vfe0_clk_src 0xa0c2bd8f +#define clk_vcodec0_clk_src 0xbc193019 + +/* BRANCHEs*/ +#define clk_gcc_blsp1_ahb_clk 0x8caa5b4f +#define clk_gcc_boot_rom_ahb_clk 0xde2adeb1 +#define clk_gcc_crypto_ahb_clk 0x94de4919 +#define clk_gcc_crypto_axi_clk 0xd4415c9b +#define clk_gcc_crypto_clk 0x00d390d2 +#define clk_gcc_prng_ahb_clk 0x397e7eaa +#define clk_gcc_apss_tcu_clk 0xaf56a329 +#define clk_gcc_gfx_tbu_clk 0x18bb9a90 +#define clk_gcc_gtcu_ahb_clk 0xb432168e +#define clk_gcc_jpeg_tbu_clk 0xcf8fd944 +#define clk_gcc_mdp_tbu_clk 0x82287f76 +#define clk_gcc_smmu_cfg_clk 0x75eaefa5 +#define clk_gcc_venus_tbu_clk 0x7e0b97ce +#define clk_gcc_vfe_tbu_clk 0x061f2f95 +#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9 +#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0 +#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220 +#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f +#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82 +#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880 +#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f +#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f +#define clk_gcc_blsp1_qup5_i2c_apps_clk 0xacae5604 +#define clk_gcc_blsp1_qup5_spi_apps_clk 0xbf3e15d7 +#define clk_gcc_blsp1_qup6_i2c_apps_clk 0x5c6ad820 +#define clk_gcc_blsp1_qup6_spi_apps_clk 0x780d9f85 +#define clk_gcc_blsp1_uart1_apps_clk 0xc7c62f90 +#define clk_gcc_blsp1_uart2_apps_clk 0xf8a61c96 +#define clk_gcc_camss_cci_ahb_clk 0xa81c11ba +#define clk_gcc_camss_cci_clk 0xb7dd8824 +#define clk_gcc_camss_csi0_ahb_clk 0x175d672a +#define clk_gcc_camss_csi0_clk 0x6b01b3e1 +#define clk_gcc_camss_csi0phy_clk 0x06a41ff7 +#define clk_gcc_camss_csi0pix_clk 0x61a8a930 +#define clk_gcc_camss_csi0rdi_clk 0x7053c7ae +#define clk_gcc_camss_csi1_ahb_clk 0x2c2dc261 +#define clk_gcc_camss_csi1_clk 0x1aba4a8c +#define clk_gcc_camss_csi1phy_clk 0x0fd1d1fa +#define clk_gcc_camss_csi1pix_clk 0x87fc98d8 +#define clk_gcc_camss_csi1rdi_clk 0x6ac996fe +#define clk_gcc_camss_csi_vfe0_clk 0xcc73453c +#define clk_gcc_camss_gp0_clk 0xd2bc3892 +#define clk_gcc_camss_gp1_clk 0xe4c013e1 +#define clk_gcc_camss_ispif_ahb_clk 0x3c0a858f +#define clk_gcc_camss_jpeg0_clk 0x1ed3f032 +#define clk_gcc_camss_jpeg_ahb_clk 0x3bfa7603 +#define clk_gcc_camss_jpeg_axi_clk 0x3e278896 +#define clk_gcc_camss_mclk0_clk 0x80902deb +#define clk_gcc_camss_mclk1_clk 0x5002d85f +#define clk_gcc_camss_micro_ahb_clk 0xfbbee8cf +#define clk_gcc_camss_csi0phytimer_clk 0xf8897589 +#define clk_gcc_camss_csi1phytimer_clk 0x4d26438f +#define clk_gcc_camss_ahb_clk 0x9894b414 +#define clk_gcc_camss_top_ahb_clk 0x4e814a78 +#define clk_gcc_camss_cpp_ahb_clk 0x4ac95e14 +#define clk_gcc_camss_cpp_clk 0x7118a0de +#define clk_gcc_camss_vfe0_clk 0xaaa3cd97 +#define clk_gcc_camss_vfe_ahb_clk 0x4050f47a +#define clk_gcc_camss_vfe_axi_clk 0x77fe2384 +#define clk_gcc_oxili_gmem_clk 0x5620913a +#define clk_gcc_gp1_clk 0x057f7b69 +#define clk_gcc_gp2_clk 0x9bf83ffd +#define clk_gcc_gp3_clk 0xec6539ee +#define clk_gcc_mdss_ahb_clk 0xbfb92ed3 +#define clk_gcc_mdss_axi_clk 0x668f51de +#define clk_gcc_mdss_byte0_clk 0x35da7862 +#define clk_gcc_mdss_esc0_clk 0xaec5cb25 +#define clk_gcc_mdss_mdp_clk 0x22f3521f +#define clk_gcc_mdss_pclk0_clk 0xcc5c5c77 +#define clk_gcc_mdss_vsync_clk 0x32a09f1f +#define clk_gcc_mss_cfg_ahb_clk 0x111cde81 +#define clk_gcc_mss_q6_bimc_axi_clk 0x67544d62 +#define clk_gcc_oxili_ahb_clk 0xd15c8a00 +#define clk_gcc_oxili_gfx3d_clk 0x49a51fd9 +#define clk_gcc_pdm2_clk 0x99d55711 +#define clk_gcc_pdm_ahb_clk 0x365664f6 +#define clk_gcc_sdcc1_ahb_clk 0x691e0caa +#define clk_gcc_sdcc1_apps_clk 0x9ad6fb96 +#define clk_gcc_sdcc2_ahb_clk 0x23d5727f +#define clk_gcc_sdcc2_apps_clk 0x861b20ac +#define clk_gcc_usb2a_phy_sleep_clk 0x6caa736f +#define clk_gcc_usb_hs_ahb_clk 0x72ce8032 +#define clk_gcc_usb_hs_system_clk 0xa11972e5 +#define clk_gcc_venus0_ahb_clk 0x08d778c6 +#define clk_gcc_venus0_axi_clk 0xcdf4c8f6 +#define clk_gcc_venus0_vcodec0_clk 0xf76a02bb +#define clk_gcc_gfx_tcu_clk 0x59505e55 +#define clk_gcc_gtcu_ahb_bridge_clk 0x19d2c5fe +#define clk_gcc_bimc_gpu_clk 0x19922503 +#define clk_gcc_bimc_gfx_clk 0x3edd69ad + +#define clk_pixel_clk_src 0x8b6f83d8 +#define clk_byte_clk_src 0x3a911c53 + +/* RPM */ +#define clk_pcnoc_clk 0xc1296d0f +#define clk_pcnoc_a_clk 0x9bcffee4 +#define clk_pcnoc_msmbus_clk 0x2b53b688 +#define clk_pcnoc_msmbus_a_clk 0x9753a54f +#define clk_pcnoc_keepalive_a_clk 0x9464f720 +#define clk_pcnoc_sps_clk 0x23d3f584 +#define clk_pcnoc_usb_a_clk 0x11d6a74e +#define clk_snoc_clk 0x2c341aa0 +#define clk_snoc_a_clk 0x8fcef2af +#define clk_snoc_msmbus_clk 0xe6900bb6 +#define clk_snoc_msmbus_a_clk 0x5d4683bd +#define clk_snoc_mmnoc_axi_clk 0xfedd4bd5 +#define clk_snoc_mmnoc_ahb_clk 0xd2149dbb +#define clk_snoc_usb_a_clk 0x34b7821b +#define clk_bimc_clk 0x4b80bf00 +#define clk_bimc_a_clk 0x4b25668a +#define clk_bimc_acpu_a_clk 0x4446311b +#define clk_bimc_msmbus_clk 0xd212feea +#define clk_bimc_msmbus_a_clk 0x71d1a499 +#define clk_bimc_usb_a_clk 0xea410834 +#define clk_qdss_clk 0x1492202a +#define clk_qdss_a_clk 0xdd121669 +#define clk_xo_clk_src 0x23f5649f +#define clk_xo_a_clk_src 0x2fdd2c7c +#define clk_xo_otg_clk 0x79bca5cc +#define clk_xo_a2 0xeba5a83d +#define clk_xo_dwc3_clk 0xfad488ce +#define clk_xo_ehci_host_clk 0xc7c340b1 +#define clk_xo_lpm_clk 0x2be48257 +#define clk_xo_pil_mss_clk 0xe97a8354 +#define clk_xo_pil_pronto_clk 0x89dae6d0 +#define clk_xo_wlan_clk 0x0116b76f + +#define clk_bb_clk1 0xf5304268 +#define clk_bb_clk1_pin 0x6dd0a779 +#define clk_bb_clk2 0xfe15cb87 +#define clk_bb_clk2_pin 0x498938e5 +#define clk_rf_clk1 0xaabeea5a +#define clk_rf_clk1_pin 0x8f463562 +#define clk_rf_clk2 0x24a30992 +#define clk_rf_clk2_pin 0xa7c5602a + +/* DEBUG */ +#define clk_gcc_debug_mux 0x8121ac15 +#define clk_rpm_debug_mux 0x25cd1f3a +#define clk_wcnss_m_clk 0x709f430b +#define clk_apss_debug_pri_mux 0xc691ff55 +#define clk_apss_debug_sec_mux 0xc0b680f9 +#define clk_apss_debug_ter_mux 0x32041c48 +#define clk_apc0_m_clk 0xce1e9473 +#define clk_apc1_m_clk 0x990fbaf7 +#define clk_apc2_m_clk 0x252cd4ae +#define clk_apc3_m_clk 0x78c64486 +#define clk_l2_m_clk 0x4bedf4d0 + + +#endif diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h index c8e1831d7572..eb1b9d727f39 100644 --- a/include/linux/dma-attrs.h +++ b/include/linux/dma-attrs.h @@ -18,6 +18,8 @@ enum dma_attr { DMA_ATTR_NO_KERNEL_MAPPING, DMA_ATTR_SKIP_CPU_SYNC, DMA_ATTR_FORCE_CONTIGUOUS, + DMA_ATTR_STRONGLY_ORDERED, + DMA_ATTR_SKIP_ZEROING, DMA_ATTR_MAX, }; diff --git a/include/linux/dma-removed.h b/include/linux/dma-removed.h new file mode 100644 index 000000000000..3a0f1a4b45e7 --- /dev/null +++ b/include/linux/dma-removed.h @@ -0,0 +1,16 @@ +/* + * 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 <linux/dma-mapping.h> + +extern struct dma_map_ops removed_dma_ops; diff --git a/include/linux/msm_rtb.h b/include/linux/msm_rtb.h new file mode 100644 index 000000000000..f8033c02feb2 --- /dev/null +++ b/include/linux/msm_rtb.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012-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. + */ +#ifndef __MSM_RTB_H__ +#define __MSM_RTB_H__ + +/* + * These numbers are used from the kernel command line and sysfs + * to control filtering. Remove items from here with extreme caution. + */ +enum logk_event_type { + LOGK_NONE = 0, + LOGK_READL = 1, + LOGK_WRITEL = 2, + LOGK_LOGBUF = 3, + LOGK_HOTPLUG = 4, + LOGK_CTXID = 5, + LOGK_TIMESTAMP = 6, + LOGK_L2CPREAD = 7, + LOGK_L2CPWRITE = 8, +}; + +#define LOGTYPE_NOPC 0x80 + +struct msm_rtb_platform_data { + unsigned int size; +}; + +#if defined(CONFIG_MSM_RTB) +/* + * returns 1 if data was logged, 0 otherwise + */ +int uncached_logk_pc(enum logk_event_type log_type, void *caller, + void *data); + +/* + * returns 1 if data was logged, 0 otherwise + */ +int uncached_logk(enum logk_event_type log_type, void *data); + +#define ETB_WAYPOINT do { \ + BRANCH_TO_NEXT_ISTR; \ + nop(); \ + BRANCH_TO_NEXT_ISTR; \ + nop(); \ + } while (0) + +#define BRANCH_TO_NEXT_ISTR asm volatile("b .+4\n" : : : "memory") +/* + * both the mb and the isb are needed to ensure enough waypoints for + * etb tracing + */ +#define LOG_BARRIER do { \ + mb(); \ + isb();\ + } while (0) +#else + +static inline int uncached_logk_pc(enum logk_event_type log_type, + void *caller, + void *data) { return 0; } + +static inline int uncached_logk(enum logk_event_type log_type, + void *data) { return 0; } + +#define ETB_WAYPOINT +#define BRANCH_TO_NEXT_ISTR +/* + * Due to a GCC bug, we need to have a nop here in order to prevent an extra + * read from being generated after the write. + */ +#define LOG_BARRIER nop() +#endif +#endif diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index 420032d41d27..f3a800001028 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -53,6 +53,19 @@ __attribute__((section(".discard"), unused)) /* + * Macro which verifies @ptr is a percpu pointer without evaluating + * @ptr. This is to be used in percpu accessors to verify that the + * input parameter is a percpu pointer. + * + * + 0 is required in order to convert the pointer type from a + * potential array type to a pointer to a single item of the array. + */ +#define __verify_pcpu_ptr(ptr) do { \ + const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \ + (void)__vpp_verify; \ +} while (0) + +/* * s390 and alpha modules require percpu variables to be defined as * weak to force the compiler to generate GOT based external * references for them. This is necessary because percpu sections diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 67fc8fcdc4b0..c9c38aa25ac5 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -34,7 +34,6 @@ extern int reboot_default; extern int reboot_cpu; extern int reboot_force; - extern int register_reboot_notifier(struct notifier_block *); extern int unregister_reboot_notifier(struct notifier_block *); diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h new file mode 100644 index 000000000000..10d7e2675f8f --- /dev/null +++ b/include/linux/regulator/krait-regulator.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2012-2013, 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. + */ + +#ifndef __KRAIT_REGULATOR_H__ +#define __KRAIT_REGULATOR_H__ + +#define KRAIT_REGULATOR_DRIVER_NAME "krait-power-regulator" +#define KRAIT_PDN_DRIVER_NAME "krait-pdn" + +/** + * krait_power_init - driver initialization function + * + * This function registers the krait-power-regulator platform driver. This + * should be called from appropriate initialization code. Returns 0 on + * success and error on failure. + */ + +#ifdef CONFIG_KRAIT_REGULATOR +int __init krait_power_init(void); +void secondary_cpu_hs_init(void *base_ptr, int cpu); +#else +static inline int __init krait_power_init(void) +{ + return -ENOSYS; +} + +static inline void secondary_cpu_hs_init(void *base_ptr, int cpu) {} +#endif + +#endif diff --git a/include/linux/sched_clock.h b/include/linux/sched_clock.h index efa931c5cef1..e10601e855c8 100644 --- a/include/linux/sched_clock.h +++ b/include/linux/sched_clock.h @@ -16,5 +16,10 @@ static inline void sched_clock_postinit(void) { } extern void sched_clock_register(u64 (*read)(void), int bits, unsigned long rate); +extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate); +extern void sched_clock_register(u64 (*read)(void), int bits, + unsigned long rate); + +extern unsigned long long (*sched_clock_func)(void); #endif diff --git a/include/linux/smp.h b/include/linux/smp.h index 93dff5fff524..6aaaddafd7a8 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -111,6 +111,27 @@ void generic_smp_call_function_single_interrupt(void); generic_smp_call_function_single_interrupt /* + * Call a function on all processors + */ +int on_each_cpu(smp_call_func_t func, void *info, int wait); + +/* + * Call a function on processors specified by mask, which might include + * the local one. + */ +void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func, + void *info, bool wait); + +/* + * Call a function on each processor for which the supplied function + * cond_func returns a positive value. This may include the local + * processor. + */ +void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), + smp_call_func_t func, void *info, bool wait, + gfp_t gfp_flags); + +/* * Mark the boot cpu "online" so that it can call console drivers in * printk() and can access its per-cpu storage. */ diff --git a/include/soc/qcom/boot_stats.h b/include/soc/qcom/boot_stats.h new file mode 100644 index 000000000000..b607dc3fa5b8 --- /dev/null +++ b/include/soc/qcom/boot_stats.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, 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. + */ + +#ifdef CONFIG_MSM_BOOT_STATS +int boot_stats_init(void); +#else +static inline int boot_stats_init(void) { return 0; } +#endif diff --git a/include/soc/qcom/pm.h b/include/soc/qcom/pm.h new file mode 100644 index 000000000000..47de77c385fd --- /dev/null +++ b/include/soc/qcom/pm.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. + * Author: San Mehat <san@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_PM_H +#define __ARCH_ARM_MACH_MSM_PM_H + +#include <linux/types.h> +#include <linux/cpuidle.h> +#include <asm/smp_plat.h> + +#if !defined(CONFIG_SMP) +#define msm_secondary_startup NULL +#elif defined(CONFIG_CPU_V7) +extern void msm_secondary_startup(void); +#else +#define msm_secondary_startup secondary_holding_pen +#endif + +enum msm_pm_sleep_mode { + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, + MSM_PM_SLEEP_MODE_RETENTION, + MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE, + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND, + MSM_PM_SLEEP_MODE_NR, + MSM_PM_SLEEP_MODE_NOT_SELECTED, +}; + +enum msm_pm_l2_scm_flag { + MSM_SCM_L2_ON = 0, + MSM_SCM_L2_OFF = 1, + MSM_SCM_L2_RET = 2, + MSM_SCM_L2_GDHS = 3, +}; + +#define MSM_PM_MODE(cpu, mode_nr) ((cpu) * MSM_PM_SLEEP_MODE_NR + (mode_nr)) + +struct msm_pm_time_params { + uint32_t latency_us; + uint32_t sleep_us; + uint32_t next_event_us; + uint32_t modified_time_us; +}; + +struct msm_pm_sleep_status_data { + void *base_addr; + uint32_t cpu_offset; + uint32_t mask; +}; + +int msm_pm_mode_sysfs_add(const char *); + +/** + * msm_pm_sleep_mode_allow() - API to determine if sleep mode is allowed. + * @cpu: CPU on which to check for the sleep mode. + * @mode: Sleep Mode to check for. + * @idle: Idle or Suspend Sleep Mode. + * + * Helper function to determine if a Idle or Suspend + * Sleep mode is allowed for a specific CPU. + * + * Return: 1 for allowed; 0 if not allowed. + */ +int msm_pm_sleep_mode_allow(unsigned int, unsigned int, bool); + +/** + * msm_pm_sleep_mode_supported() - API to determine if sleep mode is + * supported. + * @cpu: CPU on which to check for the sleep mode. + * @mode: Sleep Mode to check for. + * @idle: Idle or Suspend Sleep Mode. + * + * Helper function to determine if a Idle or Suspend + * Sleep mode is allowed and enabled for a specific CPU. + * + * Return: 1 for supported; 0 if not supported. + */ +int msm_pm_sleep_mode_supported(unsigned int, unsigned int, bool); + +struct msm_pm_cpr_ops { + void (*cpr_suspend)(void); + void (*cpr_resume)(void); +}; + +void __init msm_pm_set_tz_retention_flag(unsigned int flag); +void msm_pm_enable_retention(bool enable); +bool msm_pm_retention_enabled(void); +void msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle); + +#ifdef CONFIG_MSM_PM +void msm_pm_set_rpm_wakeup_irq(unsigned int irq); +int msm_pm_wait_cpu_shutdown(unsigned int cpu); +int __init msm_pm_sleep_status_init(void); +void msm_pm_set_l2_flush_flag(enum msm_pm_l2_scm_flag flag); +void lpm_cpu_hotplug_enter(unsigned int cpu); +s32 msm_cpuidle_get_deep_idle_latency(void); +int msm_pm_collapse(unsigned long unused); +#else +static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {} +static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; } +static inline int msm_pm_sleep_status_init(void) { return 0; }; +static inline void msm_pm_set_l2_flush_flag(unsigned int flag) { } +static inline void lpm_cpu_hotplug_enter(unsigned int cpu) {}; +static inline s32 msm_cpuidle_get_deep_idle_latency(void) { return 0; } +#define msm_pm_collapse NULL +#endif + +#ifdef CONFIG_HOTPLUG_CPU +int msm_platform_secondary_init(unsigned int cpu); +#else +static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; } +#endif + +enum msm_pm_time_stats_id { + MSM_PM_STAT_REQUESTED_IDLE = 0, + MSM_PM_STAT_IDLE_SPIN, + MSM_PM_STAT_IDLE_WFI, + MSM_PM_STAT_RETENTION, + MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE, + MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE, + MSM_PM_STAT_IDLE_POWER_COLLAPSE, + MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE, + MSM_PM_STAT_SUSPEND, + MSM_PM_STAT_FAILED_SUSPEND, + MSM_PM_STAT_NOT_IDLE, + MSM_PM_STAT_COUNT +}; + +#ifdef CONFIG_MSM_IDLE_STATS +void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size); +void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t); +void msm_pm_l2_add_stat(uint32_t id, int64_t t); +#else +static inline void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, + int size) {} +static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {} +static inline void msm_pm_l2_add_stat(uint32_t id, int64_t t) {} +#endif + +void msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops); +extern unsigned long msm_pc_debug_counters_phys; +#endif /* __ARCH_ARM_MACH_MSM_PM_H */ diff --git a/include/soc/qcom/scm-boot.h b/include/soc/qcom/scm-boot.h new file mode 100644 index 000000000000..ef108ee7cc8f --- /dev/null +++ b/include/soc/qcom/scm-boot.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2010, 2012, 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. + */ +#ifndef __MACH_SCM_BOOT_H +#define __MACH_SCM_BOOT_H + +#define SCM_BOOT_ADDR 0x1 +#define SCM_FLAG_COLDBOOT_CPU1 0x01 +#define SCM_FLAG_COLDBOOT_CPU2 0x08 +#define SCM_FLAG_COLDBOOT_CPU3 0x20 +#define SCM_FLAG_WARMBOOT_CPU1 0x02 +#define SCM_FLAG_WARMBOOT_CPU0 0x04 +#define SCM_FLAG_WARMBOOT_CPU2 0x10 +#define SCM_FLAG_WARMBOOT_CPU3 0x40 + +/* Multicluster Variants */ +#define SCM_BOOT_ADDR_MC 0x11 +#define SCM_FLAG_COLDBOOT_MC 0x02 +#define SCM_FLAG_WARMBOOT_MC 0x04 + +#ifdef CONFIG_ARM64 +#define SCM_FLAG_HLOS 0x01 +#else +#define SCM_FLAG_HLOS 0x0 +#endif + +#ifdef CONFIG_MSM_SCM +int scm_set_boot_addr(phys_addr_t addr, unsigned int flags); +int scm_set_boot_addr_mc(phys_addr_t addr, u32 aff0, + u32 aff1, u32 aff2, u32 flags); +int scm_set_warm_boot_addr_mc_for_all(phys_addr_t addr); +int scm_is_mc_boot_available(void); +#else +static inline int scm_set_boot_addr(phys_addr_t addr, unsigned int flags) +{ + WARN_ONCE(1, "CONFIG_MSM_SCM disabled, SCM call will fail silently\n"); + return 0; +} +int scm_set_boot_addr_mc(phys_addr_t addr, u32 aff0, + u32 aff1, u32 aff2, u32 flags) +{ + WARN_ONCE(1, "CONFIG_MSM_SCM disabled, SCM call will fail silently\n"); + return 0; +} +int scm_set_warm_boot_addr_mc_for_all(phys_addr_t addr) +{ + WARN_ONCE(1, "CONFIG_MSM_SCM disabled, SCM call will fail silently\n"); + return 0; +} +static inline int scm_is_mc_boot_available(void) +{ + WARN_ONCE(1, "CONFIG_MSM_SCM disabled, SCM call will fail silently\n"); + return 0; +} +#endif + +#endif diff --git a/include/soc/qcom/scm.h b/include/soc/qcom/scm.h new file mode 100644 index 000000000000..b05a7cb61d05 --- /dev/null +++ b/include/soc/qcom/scm.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2010-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. + */ +#ifndef __MACH_SCM_H +#define __MACH_SCM_H + +#define SCM_SVC_BOOT 0x1 +#define SCM_SVC_PIL 0x2 +#define SCM_SVC_UTIL 0x3 +#define SCM_SVC_TZ 0x4 +#define SCM_SVC_IO 0x5 +#define SCM_SVC_INFO 0x6 +#define SCM_SVC_SSD 0x7 +#define SCM_SVC_FUSE 0x8 +#define SCM_SVC_PWR 0x9 +#define SCM_SVC_MP 0xC +#define SCM_SVC_DCVS 0xD +#define SCM_SVC_ES 0x10 +#define SCM_SVC_HDCP 0x11 +#define SCM_SVC_TZSCHEDULER 0xFC + +#define SCM_FUSE_READ 0x7 +#define SCM_CMD_HDCP 0x01 + +/* SCM Features */ +#define SCM_SVC_SEC_CAMERA 0xD + +#define DEFINE_SCM_BUFFER(__n) \ +static char __n[PAGE_SIZE] __aligned(PAGE_SIZE); + +#define SCM_BUFFER_SIZE(__buf) sizeof(__buf) + +#define SCM_BUFFER_PHYS(__buf) virt_to_phys(__buf) + +#ifdef CONFIG_MSM_SCM +extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, + void *resp_buf, size_t resp_len); + +extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf, + size_t cmd_len, void *resp_buf, size_t resp_len, + void *scm_buf, size_t scm_buf_size); + + +extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1); +extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2); +extern s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3); +extern s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3, + u32 arg4, u32 *ret1, u32 *ret2); + +#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) + +extern u32 scm_get_version(void); +extern int scm_is_call_available(u32 svc_id, u32 cmd_id); +extern int scm_get_feat_version(u32 feat); + +#define SCM_HDCP_MAX_REG 5 + +struct scm_hdcp_req { + u32 addr; + u32 val; +}; + +#else + +static inline int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, + size_t cmd_len, void *resp_buf, size_t resp_len) +{ + return 0; +} + +static inline int scm_call_noalloc(u32 svc_id, u32 cmd_id, + const void *cmd_buf, size_t cmd_len, void *resp_buf, + size_t resp_len, void *scm_buf, size_t scm_buf_size) +{ + return 0; +} + +static inline s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) +{ + return 0; +} + +static inline s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2) +{ + return 0; +} + +static inline s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2, + u32 arg3) +{ + return 0; +} + +static inline s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, + u32 arg3, u32 arg4, u32 *ret1, u32 *ret2) +{ + return 0; +} + +static inline u32 scm_get_version(void) +{ + return 0; +} + +static inline int scm_is_call_available(u32 svc_id, u32 cmd_id) +{ + return 0; +} + +static inline int scm_get_feat_version(u32 feat) +{ + return 0; +} + +#endif +#endif diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h new file mode 100644 index 000000000000..c734dee2d9d0 --- /dev/null +++ b/include/soc/qcom/smem.h @@ -0,0 +1,241 @@ +/* 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. + */ + +#ifndef _ARCH_ARM_MACH_MSM_SMEM_H_ +#define _ARCH_ARM_MACH_MSM_SMEM_H_ + +#include <linux/types.h> + +enum { + SMEM_APPS, + SMEM_MODEM, + SMEM_Q6, + SMEM_DSPS, + SMEM_WCNSS, + SMEM_MODEM_Q6_FW, + SMEM_RPM, + NUM_SMEM_SUBSYSTEMS, +}; + +/* + * Flag options for the XXX_to_proc() API + * + * SMEM_ITEM_CACHED_FLAG - Indicates this operation should use cachable smem + * + * SMEM_ANY_HOST_FLAG - Indicates this operation should not apply to smem items + * which are limited to a specific host pairing. Will + * cause this operation to ignore the to_proc parameter. + */ +#define SMEM_ITEM_CACHED_FLAG 1 +#define SMEM_ANY_HOST_FLAG 2 + +#define SMEM_NUM_SMD_STREAM_CHANNELS 64 + +/** + * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow + * + * @type: type to check for overflow + * @a: left value to use + * @b: right value to use + * @returns: true if a + b will result in overflow; false otherwise + */ +#define OVERFLOW_ADD_UNSIGNED(type, a, b) \ + (((type)~0 - (a)) < (b) ? true : false) + +enum { + /* fixed items */ + SMEM_PROC_COMM = 0, + SMEM_HEAP_INFO, + SMEM_ALLOCATION_TABLE, + SMEM_VERSION_INFO, + SMEM_HW_RESET_DETECT, + SMEM_AARM_WARM_BOOT, + SMEM_DIAG_ERR_MESSAGE, + SMEM_SPINLOCK_ARRAY, + SMEM_MEMORY_BARRIER_LOCATION, + SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION, + + /* dynamic items */ + SMEM_AARM_PARTITION_TABLE, + SMEM_AARM_BAD_BLOCK_TABLE, + SMEM_RESERVE_BAD_BLOCKS, + SMEM_WM_UUID, + SMEM_CHANNEL_ALLOC_TBL, + SMEM_SMD_BASE_ID, + SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS, + SMEM_SMEM_LOG_EVENTS, + SMEM_SMEM_STATIC_LOG_IDX, + SMEM_SMEM_STATIC_LOG_EVENTS, + SMEM_SMEM_SLOW_CLOCK_SYNC, + SMEM_SMEM_SLOW_CLOCK_VALUE, + SMEM_BIO_LED_BUF, + SMEM_SMSM_SHARED_STATE, + SMEM_SMSM_INT_INFO, + SMEM_SMSM_SLEEP_DELAY, + SMEM_SMSM_LIMIT_SLEEP, + SMEM_SLEEP_POWER_COLLAPSE_DISABLED, + SMEM_KEYPAD_KEYS_PRESSED, + SMEM_KEYPAD_STATE_UPDATED, + SMEM_KEYPAD_STATE_IDX, + SMEM_GPIO_INT, + SMEM_MDDI_LCD_IDX, + SMEM_MDDI_HOST_DRIVER_STATE, + SMEM_MDDI_LCD_DISP_STATE, + SMEM_LCD_CUR_PANEL, + SMEM_MARM_BOOT_SEGMENT_INFO, + SMEM_AARM_BOOT_SEGMENT_INFO, + SMEM_SLEEP_STATIC, + SMEM_SCORPION_FREQUENCY, + SMEM_SMD_PROFILES, + SMEM_TSSC_BUSY, + SMEM_HS_SUSPEND_FILTER_INFO, + SMEM_BATT_INFO, + SMEM_APPS_BOOT_MODE, + SMEM_VERSION_FIRST, + SMEM_VERSION_SMD = SMEM_VERSION_FIRST, + SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24, + SMEM_OSS_RRCASN1_BUF1, + SMEM_OSS_RRCASN1_BUF2, + SMEM_ID_VENDOR0, + SMEM_ID_VENDOR1, + SMEM_ID_VENDOR2, + SMEM_HW_SW_BUILD_ID, + SMEM_SMD_BASE_ID_2, + SMEM_SMD_FIFO_BASE_ID_2 = SMEM_SMD_BASE_ID_2 + + SMEM_NUM_SMD_STREAM_CHANNELS, + SMEM_CHANNEL_ALLOC_TBL_2 = SMEM_SMD_FIFO_BASE_ID_2 + + SMEM_NUM_SMD_STREAM_CHANNELS, + SMEM_I2C_MUTEX = SMEM_CHANNEL_ALLOC_TBL_2 + + SMEM_NUM_SMD_STREAM_CHANNELS, + SMEM_SCLK_CONVERSION, + SMEM_SMD_SMSM_INTR_MUX, + SMEM_SMSM_CPU_INTR_MASK, + SMEM_APPS_DEM_SLAVE_DATA, + SMEM_QDSP6_DEM_SLAVE_DATA, + SMEM_CLKREGIM_BSP, + SMEM_CLKREGIM_SOURCES, + SMEM_SMD_FIFO_BASE_ID, + SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID + + SMEM_NUM_SMD_STREAM_CHANNELS, + SMEM_POWER_ON_STATUS_INFO, + SMEM_DAL_AREA, + SMEM_SMEM_LOG_POWER_IDX, + SMEM_SMEM_LOG_POWER_WRAP, + SMEM_SMEM_LOG_POWER_EVENTS, + SMEM_ERR_CRASH_LOG, + SMEM_ERR_F3_TRACE_LOG, + SMEM_SMD_BRIDGE_ALLOC_TABLE, + SMEM_SMDLITE_TABLE, + SMEM_SD_IMG_UPGRADE_STATUS, + SMEM_SEFS_INFO, + SMEM_RESET_LOG, + SMEM_RESET_LOG_SYMBOLS, + SMEM_MODEM_SW_BUILD_ID, + SMEM_SMEM_LOG_MPROC_WRAP, + SMEM_BOOT_INFO_FOR_APPS, + SMEM_SMSM_SIZE_INFO, + SMEM_SMD_LOOPBACK_REGISTER, + SMEM_SSR_REASON_MSS0, + SMEM_SSR_REASON_WCNSS0, + SMEM_SSR_REASON_LPASS0, + SMEM_SSR_REASON_DSPS0, + SMEM_SSR_REASON_VCODEC0, + SMEM_SMP2P_APPS_BASE = 427, + SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8, /* 435 */ + SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8, /* 443 */ + SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */ + SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */ + SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8, /* 467 */ + SMEM_BAM_PIPE_MEMORY, /* 468 */ + SMEM_IMAGE_VERSION_TABLE, /* 469 */ + SMEM_LC_DEBUGGER, /* 470 */ + SMEM_FLASH_NAND_DEV_INFO, /* 471 */ + SMEM_A2_BAM_DESCRIPTOR_FIFO, /* 472 */ + SMEM_CPR_CONFIG, /* 473 */ + SMEM_CLOCK_INFO, /* 474 */ + SMEM_IPC_FIFO, /* 475 */ + SMEM_NUM_ITEMS, +}; + +#ifdef CONFIG_MSM_SMEM +void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, + unsigned flags); +void *smem_find(unsigned id, unsigned size_in, unsigned to_proc, + unsigned flags); +void *smem_get_entry(unsigned id, unsigned *size, unsigned to_proc, + unsigned flags); + +/** + * smem_get_entry_no_rlock - Get existing item without using remote spinlock + * + * @id: ID of SMEM item + * @size_out: Pointer to size variable for storing the result + * @to_proc: SMEM host that shares the item with apps + * @flags: Item attribute flags + * @returns: Pointer to SMEM item or NULL if it doesn't exist + * + * This function does not lock the remote spinlock and should only be used in + * failure-recover cases such as retrieving the subsystem failure reason during + * subsystem restart. + */ +void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out, unsigned to_proc, + unsigned flags); + +/** + * smem_virt_to_phys() - Convert SMEM address to physical address. + * + * @smem_address: Virtual address returned by smem_alloc() + * @returns: Physical address (or NULL if there is a failure) + * + * This function should only be used if an SMEM item needs to be handed + * off to a DMA engine. + */ +phys_addr_t smem_virt_to_phys(void *smem_address); + +/** + * SMEM initialization function that registers for a SMEM platform driver. + * + * @returns: success on successful driver registration. + */ +int __init msm_smem_init(void); + +#else +static inline void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, + unsigned flags) +{ + return NULL; +} +static inline void *smem_find(unsigned id, unsigned size_in, + unsigned to_proc, unsigned flags) +{ + return NULL; +} +static inline void *smem_get_entry(unsigned id, unsigned *size, + unsigned to_proc, unsigned flags) +{ + return NULL; +} +static inline void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out, + unsigned to_proc, unsigned flags) +{ + return NULL; +} +static inline phys_addr_t smem_virt_to_phys(void *smem_address) +{ + return (phys_addr_t) NULL; +} +static inline int __init msm_smem_init(void) +{ + return 0; +} +#endif /* CONFIG_MSM_SMEM */ +#endif /* _ARCH_ARM_MACH_MSM_SMEM_H_ */ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h new file mode 100644 index 000000000000..9f18fd90a94b --- /dev/null +++ b/include/soc/qcom/socinfo.h @@ -0,0 +1,604 @@ +/* Copyright (c) 2009-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. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_ +#define _ARCH_ARM_MACH_MSM_SOCINFO_H_ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/of_fdt.h> +#include <linux/of.h> + +#include <asm/cputype.h> +/* + * SOC version type with major number in the upper 16 bits and minor + * number in the lower 16 bits. For example: + * 1.0 -> 0x00010000 + * 2.3 -> 0x00020003 + */ +#define SOCINFO_VERSION_MAJOR(ver) ((ver & 0xffff0000) >> 16) +#define SOCINFO_VERSION_MINOR(ver) (ver & 0x0000ffff) + +#ifdef CONFIG_OF +#define of_board_is_cdp() of_machine_is_compatible("qcom,cdp") +#define of_board_is_sim() of_machine_is_compatible("qcom,sim") +#define of_board_is_rumi() of_machine_is_compatible("qcom,rumi") +#define of_board_is_fluid() of_machine_is_compatible("qcom,fluid") +#define of_board_is_liquid() of_machine_is_compatible("qcom,liquid") +#define of_board_is_dragonboard() \ + of_machine_is_compatible("qcom,dragonboard") +#define of_board_is_cdp() of_machine_is_compatible("qcom,cdp") +#define of_board_is_mtp() of_machine_is_compatible("qcom,mtp") +#define of_board_is_qrd() of_machine_is_compatible("qcom,qrd") +#define of_board_is_xpm() of_machine_is_compatible("qcom,xpm") +#define of_board_is_skuf() of_machine_is_compatible("qcom,skuf") +#define of_board_is_sbc() of_machine_is_compatible("qcom,sbc") + +#define machine_is_msm8974() of_machine_is_compatible("qcom,msm8974") +#define machine_is_msm9625() of_machine_is_compatible("qcom,msm9625") +#define machine_is_msm8610() of_machine_is_compatible("qcom,msm8610") +#define machine_is_msm8226() of_machine_is_compatible("qcom,msm8226") +#define machine_is_apq8074() of_machine_is_compatible("qcom,apq8074") +#define machine_is_msm8926() of_machine_is_compatible("qcom,msm8926") + +#define early_machine_is_msm8610() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610") +#define early_machine_is_mpq8092() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mpq8092") +#define early_machine_is_msm8916() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8916") +#define early_machine_is_msm8936() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8936") +#define early_machine_is_msm8939() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8939") +#define early_machine_is_apq8084() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8084") +#define early_machine_is_mdm9630() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mdm9630") +#define early_machine_is_msmzirc() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmzirc") +#define early_machine_is_fsm9900() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,fsm9900") +#define early_machine_is_msmsamarium() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmsamarium") +#else +#define of_board_is_sim() 0 +#define of_board_is_rumi() 0 +#define of_board_is_fluid() 0 +#define of_board_is_liquid() 0 +#define of_board_is_dragonboard() 0 +#define of_board_is_cdp() 0 +#define of_board_is_mtp() 0 +#define of_board_is_qrd() 0 +#define of_board_is_xpm() 0 +#define of_board_is_skuf() 0 +#define of_board_is_sbc() 0 + +#define machine_is_msm8974() 0 +#define machine_is_msm9625() 0 +#define machine_is_msm8610() 0 +#define machine_is_msm8226() 0 +#define machine_is_apq8074() 0 +#define machine_is_msm8926() 0 + +#define early_machine_is_msm8610() 0 +#define early_machine_is_mpq8092() 0 +#define early_machine_is_msm8916() 0 +#define early_machine_is_msm8936() 0 +#define early_machine_is_msm8939() 0 +#define early_machine_is_apq8084() 0 +#define early_machine_is_mdm9630() 0 +#define early_machine_is_fsm9900() 0 +#define early_machine_is_msmsamarium() 0 +#endif + +#define PLATFORM_SUBTYPE_MDM 1 +#define PLATFORM_SUBTYPE_INTERPOSERV3 2 +#define PLATFORM_SUBTYPE_SGLTE 6 + +enum msm_cpu { + MSM_CPU_UNKNOWN = 0, + MSM_CPU_7X01, + MSM_CPU_7X25, + MSM_CPU_7X27, + MSM_CPU_8X50, + MSM_CPU_8X50A, + MSM_CPU_7X30, + MSM_CPU_8X55, + MSM_CPU_8X60, + MSM_CPU_8960, + MSM_CPU_8960AB, + MSM_CPU_7X27A, + FSM_CPU_9XXX, + MSM_CPU_7X25A, + MSM_CPU_7X25AA, + MSM_CPU_7X25AB, + MSM_CPU_8064, + MSM_CPU_8064AB, + MSM_CPU_8064AA, + MSM_CPU_8930, + MSM_CPU_8930AA, + MSM_CPU_8930AB, + MSM_CPU_7X27AA, + MSM_CPU_9615, + MSM_CPU_8974, + MSM_CPU_8974PRO_AA, + MSM_CPU_8974PRO_AB, + MSM_CPU_8974PRO_AC, + MSM_CPU_8627, + MSM_CPU_8625, + MSM_CPU_9625, + MSM_CPU_8092, + MSM_CPU_8916, + MSM_CPU_8936, + MSM_CPU_8939, + MSM_CPU_8226, + MSM_CPU_8610, + MSM_CPU_8625Q, + MSM_CPU_8084, + MSM_CPU_9630, + FSM_CPU_9900, + MSM_CPU_ZIRC, +}; + +struct msm_soc_info { + enum msm_cpu generic_soc_type; + char *soc_id_string; +}; + +enum pmic_model { + PMIC_MODEL_PM8058 = 13, + PMIC_MODEL_PM8028 = 14, + PMIC_MODEL_PM8901 = 15, + PMIC_MODEL_PM8027 = 16, + PMIC_MODEL_ISL_9519 = 17, + PMIC_MODEL_PM8921 = 18, + PMIC_MODEL_PM8018 = 19, + PMIC_MODEL_PM8015 = 20, + PMIC_MODEL_PM8014 = 21, + PMIC_MODEL_PM8821 = 22, + PMIC_MODEL_PM8038 = 23, + PMIC_MODEL_PM8922 = 24, + PMIC_MODEL_PM8917 = 25, + PMIC_MODEL_UNKNOWN = 0xFFFFFFFF +}; + +enum msm_cpu socinfo_get_msm_cpu(void); +uint32_t socinfo_get_id(void); +uint32_t socinfo_get_version(void); +uint32_t socinfo_get_raw_id(void); +char *socinfo_get_build_id(void); +uint32_t socinfo_get_platform_type(void); +uint32_t socinfo_get_platform_subtype(void); +uint32_t socinfo_get_platform_version(void); +enum pmic_model socinfo_get_pmic_model(void); +uint32_t socinfo_get_pmic_die_revision(void); +int __init socinfo_init(void) __must_check; +const int read_msm_cpu_type(void); +const int get_core_count(void); +const int cpu_is_krait(void); +const int cpu_is_krait_v1(void); +const int cpu_is_krait_v2(void); +const int cpu_is_krait_v3(void); + +static inline int cpu_is_msm7x01(void) +{ +#ifdef CONFIG_ARCH_MSM7X01A + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X01; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x25(void) +{ +#ifdef CONFIG_ARCH_MSM7X25 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X25; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x27(void) +{ +#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A) + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X27; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x27a(void) +{ +#ifdef CONFIG_ARCH_MSM7X27A + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X27A; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x27aa(void) +{ +#ifdef CONFIG_ARCH_MSM7X27A + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X27AA; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x25a(void) +{ +#ifdef CONFIG_ARCH_MSM7X27A + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X25A; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x25aa(void) +{ +#ifdef CONFIG_ARCH_MSM7X27A + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X25AA; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x25ab(void) +{ +#ifdef CONFIG_ARCH_MSM7X27A + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X25AB; +#else + return 0; +#endif +} + +static inline int cpu_is_msm7x30(void) +{ +#ifdef CONFIG_ARCH_MSM7X30 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X30; +#else + return 0; +#endif +} + +static inline int cpu_is_qsd8x50(void) +{ +#ifdef CONFIG_ARCH_QSD8X50 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8X50; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8x55(void) +{ +#ifdef CONFIG_ARCH_MSM7X30 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8X55; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8x60(void) +{ +#ifdef CONFIG_ARCH_MSM8X60 + return read_msm_cpu_type() == MSM_CPU_8X60; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8960(void) +{ + return 0; +} + +static inline int cpu_is_msm8960ab(void) +{ + return 0; +} + +static inline int cpu_is_apq8064(void) +{ +#ifdef CONFIG_ARCH_APQ8064 + return read_msm_cpu_type() == MSM_CPU_8064; +#else + return 0; +#endif +} + +static inline int cpu_is_apq8064ab(void) +{ +#ifdef CONFIG_ARCH_APQ8064 + return read_msm_cpu_type() == MSM_CPU_8064AB; +#else + return 0; +#endif +} + +static inline int cpu_is_apq8064aa(void) +{ +#ifdef CONFIG_ARCH_APQ8064 + return read_msm_cpu_type() == MSM_CPU_8064AA; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8930(void) +{ +#ifdef CONFIG_ARCH_MSM8930 + return read_msm_cpu_type() == MSM_CPU_8930; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8930aa(void) +{ +#ifdef CONFIG_ARCH_MSM8930 + return read_msm_cpu_type() == MSM_CPU_8930AA; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8930ab(void) +{ +#ifdef CONFIG_ARCH_MSM8930 + return read_msm_cpu_type() == MSM_CPU_8930AB; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8627(void) +{ +/* 8930 and 8627 will share the same CONFIG_ARCH type unless otherwise needed */ +#ifdef CONFIG_ARCH_MSM8930 + return read_msm_cpu_type() == MSM_CPU_8627; +#else + return 0; +#endif +} + +static inline int cpu_is_fsm9xxx(void) +{ +#ifdef CONFIG_ARCH_FSM9XXX + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == FSM_CPU_9XXX; +#else + return 0; +#endif +} + +static inline int cpu_is_msm9615(void) +{ +#ifdef CONFIG_ARCH_MSM9615 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_9615; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8625(void) +{ +#ifdef CONFIG_ARCH_MSM8625 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8625; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8974(void) +{ +#ifdef CONFIG_ARCH_MSM8974 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8974; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8974pro_aa(void) +{ +#ifdef CONFIG_ARCH_MSM8974 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8974PRO_AA; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8974pro_ab(void) +{ +#ifdef CONFIG_ARCH_MSM8974 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8974PRO_AB; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8974pro_ac(void) +{ +#ifdef CONFIG_ARCH_MSM8974 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8974PRO_AC; +#else + return 0; +#endif +} + +static inline int cpu_is_mpq8092(void) +{ +#ifdef CONFIG_ARCH_MPQ8092 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8092; +#else + return 0; +#endif + +} + +static inline int cpu_is_msm8916(void) +{ +#ifdef CONFIG_ARCH_MSM8916 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8916; +#else + return 0; +#endif + +} + +static inline int cpu_is_msm8936(void) +{ +#ifdef CONFIG_ARCH_MSM8916 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8936; +#else + return 0; +#endif + +} + +static inline int cpu_is_msm8939(void) +{ +#ifdef CONFIG_ARCH_MSM8916 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8939; +#else + return 0; +#endif + +} + +static inline int cpu_is_msm8226(void) +{ +#ifdef CONFIG_ARCH_MSM8226 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8226; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8610(void) +{ +#ifdef CONFIG_ARCH_MSM8610 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8610; +#else + return 0; +#endif +} + +static inline int cpu_is_msm8625q(void) +{ +#ifdef CONFIG_ARCH_MSM8625 + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8625Q; +#else + return 0; +#endif +} + +static inline int soc_class_is_msm8960(void) +{ + return cpu_is_msm8960() || cpu_is_msm8960ab(); +} + +static inline int soc_class_is_apq8064(void) +{ + return cpu_is_apq8064() || cpu_is_apq8064ab() || cpu_is_apq8064aa(); +} + +static inline int soc_class_is_msm8930(void) +{ + return cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8930ab() || + cpu_is_msm8627(); +} + +static inline int soc_class_is_msm8974(void) +{ + return cpu_is_msm8974() || cpu_is_msm8974pro_aa() || + cpu_is_msm8974pro_ab() || cpu_is_msm8974pro_ac(); +} + +#endif diff --git a/init/Kconfig b/init/Kconfig index 2081a4d3d917..7bc67dab58f1 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1345,6 +1345,12 @@ config HAVE_PCSPKR_PLATFORM config BPF bool +config PANIC_TIMEOUT + int "Default panic timeout" + default 0 + help + Set default panic timeout. + menuconfig EXPERT bool "Configure standard kernel features (expert users)" # Unhide debug options, to make the on-by-default options visible diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 54be19a0fa51..5f7772fcc953 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -295,6 +295,12 @@ _dtbinst_pre_: %.dtb_dtbinst_: $(obj)/%.dtb _dtbinst_pre_ $(call cmd,dtb_install,$(INSTALL_DTBS_PATH)) +# cat +# --------------------------------------------------------------------------- +# Concatentate multiple files together +quiet_cmd_cat = CAT $@ +cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false) + # Bzip2 # --------------------------------------------------------------------------- |